2

I am trying to create an endpoint that outputs the latest updated entry in each section (Themes, Videos and Screensavers) like this:

url/updated.json

{
 themes: '2016-08-22',
 videos: '2016-08-18',
 screensavers: '2016-07-20'
}

I can't think of how to do this but here is my code so far, no dice so far tho:

'updates.json' => [
        'elementType' => 'Entry',
        'paginate' => false,
        'criteria' => ['section' => '', 'limit' => null,],
        'transformer' => function(EntryModel $entry) {
            $screensaversLastUpdated = $entry->dateUpdated;
            $videosLastUpdated = $entry->dateUpdated;
            $themesLastUpdated = $entry->dateUpdated;
            return [
                'themes' => $screensaversLastUpdated ,
                'screensavers' => $screensaversLastUpdated ,
                'videos' => $videosLastUpdated
            ];
        }
    ]

Any help would be much appreciated!

Thanks!

1 Answer 1

2

This isn't really a job for the Element API plugin. You can accomplish what you want much easier by just creating a plain ol' Twig template (e.g. templates/updates.json) that pulls the three latest updated entries from each section, and returns the entries' dateUpdated values as JSON:

{% header "Content-Type: application/json" %}

{%- spaceless -%}

{% set sections = ['themes', 'videos', 'screensavers'] %}
{% set entries = [] %}
{% for section in sections %}
    {% set entry = craft.entries.section(section).order('dateUpdated desc').limit(1).first() %}
    {% set entries = entry ? entries|merge([entry]) : entries %}
{% endfor %}

{
  {%- for entry in entries -%}
    "{{ entry.section.handle }}":"{{ entry.dateUpdated }}"{% if not loop.last %},{% endif %}
  {%- endfor -%}
}

{%- endspaceless -%}

The above would render a JSON payload exactly like the one you have in your example.

If you really want to use Element API for some reason, you can get pretty close to what you want (but not quite). Here's why it's difficult to do, though:

For one, the transformer property function operates on a single entry at the time, which is a problem in terms of your desired payload.

Second, with Element API you don't have full control of the JSON format the plugin returns – so you'll never get the payload to look exactly like you want (the actual data will be wrapped in a data property).

Third and most importantly, an Element API endpoint requires a single query (or actually, a single ElementCriteriaModel) to pull your elements. Unfortunately, it isn't possible to tell an ElementCriteriaModel to return 1 entry from each section – notice that even in the template example above, there's actually three queries – one for each section (they're just wrapped in a for loop to keep the code small and DRY).

So basically, you'll need to "trick" Element API to return something similar to your example JSON.

First, since you can't use a single ElementCriteriaModel to query your 3 latest entries, you'll actually need three of those suckers. The Element API plugin gives you one, but you'll need to create the other two inside the transformer function – you just need to ensure that Element API actually runs that function, and only runs it once, by pulling a single entry (in other words; you'll need a limit => 1 for your endpoint's criteria). It makes sense to have the endpoint pull one of the three entries you need, so you'll avoid a redundant database query. Then, you'll have to pull the other two entries "manually". Finally, for the return value you can return an array similar to what you have in your example:

'updates.json' => [
    'elementType' => 'Entry',
    'paginate' => false,
    'criteria' => ['section' => 'themes', 'order' => 'dateUpdated desc', 'limit' => 1],
    'transformer' => function(EntryModel $entry) {

        $themesEntry = $entry;

        $videosEntry = craft()->elements->getCriteria(ElementType::Entry, [
            'section' => 'videos',
            'order' => 'dateUpdated desc',
            'limit' => 1
        ])->first();

        $screensaversEntry = craft()->elements->getCriteria(ElementType::Entry, [
            'section' => 'screensavers',
            'order' => 'dateUpdated desc',
            'limit' => 1
        ])->first();

        return [
            'themes' => date('Y-m-d', $themesEntry->dateUpdated->getTimestamp()),
            'videos' => date('Y-m-d', $videosEntry->dateUpdated->getTimestamp()),
            'screensavers' => date('Y-m-d', $screensaversEntry->dateUpdated->getTimestamp()),
        ];
    }
]

The above would return a JSON payload looking something like this:

{"data":[{"themes":"2016-02-23","videos":"2016-08-23","screensavers":"2016-07-16"}]}   
2
  • Thanks a bunch, this has really broadened my knowledge of the element API plugin! Worked perfectly, cheers! Commented Aug 23, 2016 at 10:18
  • @GrahamDragonbornWilsdon Awesome! Commented Aug 23, 2016 at 10:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.