Answers.Body: <p>I don't know if I ever got this working exactly as I initially intended, but this is the final transformer code I ended up going with. Basically the same but with some usort calls on sessions and dates. I then had to manually do the pagination in the Twig template where courses were listed. Hope it helps!</p>
  <pre><code>    &lt;?php
  namespace Craft;
  
  require craft()-&gt;path-&gt;getPluginsPath().'elementapi/vendor/autoload.php';
  
  use League\Fractal\TransformerAbstract;
  
  class CoursesTransformer extends TransformerAbstract {
  
      public function transform (EntryModel $entry) {
  
          $next_session_start = null;
          $sessions = array();
          $now = date('Y-m-d');
  
          foreach ($entry-&gt;sessions as $session) {
              if ($session-&gt;level == 1) {
                  $this_session = array(
                      'location' =&gt; $session-&gt;location,
                      'registrationLink' =&gt; $session-&gt;registrationLink,
                      'dates' =&gt; array()
                  );
                  foreach ($session-&gt;children as $date) {
                      array_push($this_session['dates'], array(
                          'date' =&gt; date_format($date-&gt;date, 'Y-m-d'),
                          'startTime' =&gt; date_format($date-&gt;startTime, 'g:iA'),
                          'endTime' =&gt; date_format($date-&gt;endTime, 'g:iA')
                      ));
                  }
  
                  //ensure dates are in correct order
                  usort($this_session['dates'], function($a,$b) {
                      return $a['date'] &gt; $b['date'];
                  });
  
                  array_push($sessions, $this_session);
              }
          }
  
          //ensure sessions are in correct order
          usort($sessions, function($a,$b) {
              return $a['dates'][0]['date'] &gt; $b['dates'][0]['date'];
          });
  
          return [
              'title' =&gt; $entry-&gt;title,
              'url' =&gt; $entry-&gt;url,
              'nextSessionStart' =&gt; date_format(new DateTime($entry-&gt;nextSessionStartDate), 'Y-m-d'),
              'sessions' =&gt; $sessions
          ];
  
      }
  }
  </code></pre>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2020-08-02T17:31:52.030Z
Answers.LastActivityDate: 2020-08-02T17:31:52.030Z
Answers.UserDisplayName: GTerrill
Answers.Body: <p>I know this is answered but I just wanted to suggest a potentially better way.</p>
  <p>I would suggest trying the <a href="https://plugins.craftcms.com/preparse-field" rel="nofollow noreferrer">Preparse field plugin</a>. This way you can create a new field that automatically generates the data you want to sort/query (in your case, the first session date). This will only happen when you save the entry so it will likely speed up your API considerably.</p>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2020-08-04T13:05:55.270Z
Answers.LastActivityDate: 2020-08-04T13:05:55.270Z
Answers.UserDisplayName: dmatthams
Body: <p>I need to sort the entries for an Element API endpoint by a value calculated in a custom transformer. Is this possible?</p>
  
  <p>The use case is this: We're dealing with Events/Courses that have multiple instances (sessions) that each may contain multiple dates. I have a Neo field called <code>sessions</code> with <code>session</code> blocks that contain <code>date</code> sub-blocks. The <code>session</code> block contains <code>registrationLink</code> and <code>location</code>, and each <code>date</code> block contains the fields <code>date</code>, <code>startTime</code>, and <code>endTime</code>.</p>
  
  <p>However, these need to be sorted by nearest session date (the user could input the sessions/dates in any order), so I need to determine the nearest upcoming session by looking through all the sessions and finding the first date for that session. We also don't want to show sessions that have already passed. I wasn't able to figure out how to do this in Twig, so I thought it might be easier in Element API. I've got the transformer working, so I can get output like this:</p>
  
  <pre><code>{
    "entries": [
      {
        "title": "TITLE REMOVED",
        "url": "URL REMOVED",
        "nextSessionStart": "2017-08-09",
        "sessions": [
          {
            "location": "LOCATION REMOVED",
            "registrationLink": "URL REMOVED",
            "dates": [
              {
                "date": "2017-08-09",
                "startTime": "8:30AM",
                "endTime": "4:30PM"
              },
              {
                "date": "2017-08-10",
                "startTime": "8:30AM",
                "endTime": "4:30PM"
              }
            ]
          },
          {
            "location": "LOCATION REMOVED",
            "registrationLink": "URL REMOVED",
            "dates": [
              {
                "date": "2017-11-02",
                "startTime": "8:30AM",
                "endTime": "4:30PM"
              },
              {
                "date": "2017-11-03",
                "startTime": "8:30AM",
                "endTime": "4:30PM"
              }
            ]
          },
          {
            "location": "LOCATION REMOVED",
            "registrationLink": "URL REMOVED",
            "dates": [
              {
                "date": "2018-02-06",
                "startTime": "8:30AM",
                "endTime": "4:30PM"
              },
              {
                "date": "2018-02-07",
                "startTime": "8:30AM",
                "endTime": "4:30PM"
              }
            ]
          }
        ]
      },
      {
        "title": "TITLE REMOVED",
        "url": "URL REMOVED",
        "nextSessionStart": "2018-07-07",
        "sessions": [
          {
            "location": "LOCATION REMOVED",
            "registrationLink": "URL REMOVED",
            "dates": [
              {
                "date": "2018-07-07",
                "startTime": "5:30PM",
                "endTime": "8:30PM"
              },
              {
                "date": "2018-08-07",
                "startTime": "8:30AM",
                "endTime": "4:30PM"
              }
            ]
          }
        ]
      },
      {
        "title": "TITLE REMOVED",
        "url": "URL REMOVED",
        "nextSessionStart": "2017-07-11",
        "sessions": [
          {
            "location": "LOCATION REMOVED",
            "registrationLink": "URL REMOVED",
            "dates": [
              {
                "date": "2017-12-05",
                "startTime": "8:30AM",
                "endTime": "4:30PM"
              }
            ]
          },
          {
            "location": "LOCATION REMOVED",
            "registrationLink": "URL REMOVED",
            "dates": [
              {
                "date": "2017-07-11",
                "startTime": "8:30AM",
                "endTime": "4:30PM"
              }
            ]
          },
          {
            "location": "LOCATION REMOVED",
            "registrationLink": "URL REMOVED",
            "dates": [
              {
                "date": "2017-10-25",
                "startTime": "8:30AM",
                "endTime": "4:30PM"
              }
            ]
          }
        ]
      }
    ],
    "meta": {
      "pagination": {
        "total": 3,
        "count": 3,
        "per_page": 10,
        "current_page": 1,
        "total_pages": 1,
        "links": [
  
        ]
      }
    }
  }
  </code></pre>
  
  <p>The problem is that I need to sort and paginate the results based on that nextSessionStart key.</p>
  
  <p>Here's the elementapi.php config file:</p>
  
  <pre><code>    return [
          'defaults' =&gt; [
              'elementType' =&gt; ElementType::Entry,
              'elementsPerPage' =&gt; 10,
              'pageParam' =&gt; 'pg',
              'resourceKey' =&gt; 'entries'
          ],
  
          'endpoints' =&gt; [
              'courses.json' =&gt; function() {
  
                  require craft()-&gt;path-&gt;getConfigPath().'elementapi/CoursesTransformer.php';
  
                  return [
                      'criteria' =&gt; [
                          'section' =&gt; ['courses'],
                          'order' =&gt; 'nextSessionStart asc' //NOTE: this doesn't work and needs to be removed to get the above output
                      ],
                      'transformer' =&gt; new CoursesTransformer()
                  ];
              }
          ]
      ];
  </code></pre>
  
  <p>The transformer looks like this:</p>
  
  <pre><code>    class CoursesTransformer extends TransformerAbstract {
  
          public function transform (EntryModel $entry) {
  
              $next_session_start = null;
              $sessions = array();
              $now = date('Y-m-d');
  
              foreach ($entry-&gt;sessions as $session) {
                  if ($session-&gt;level == 1) {
                      $this_session = array(
                          'location' =&gt; $session-&gt;location,
                          'registrationLink' =&gt; $session-&gt;registrationLink,
                          'dates' =&gt; array()
                      );
                      foreach ($session-&gt;children as $date) {
                          $this_date = $date-&gt;date;
  
                          array_push($this_session['dates'], array(
                              'date' =&gt; date_format($this_date, 'Y-m-d'),
                              'startTime' =&gt; date_format($date-&gt;startTime, 'g:iA'),
                              'endTime' =&gt; date_format($date-&gt;endTime, 'g:iA')
                          ));
  
                          if ($this_date &gt; $now &amp;&amp; (is_null($next_session_start) || $this_date &lt; $next_session_start)) {
                              $next_session_start = $this_date;
                          }
                      }
                      array_push($sessions, $this_session);
                  }
              }
  
              return [
                  'title' =&gt; $entry-&gt;title,
                  'url' =&gt; $entry-&gt;url,
                  'nextSessionStart' =&gt; date_format(new DateTime($next_session_start), 'Y-m-d'),
                  'sessions' =&gt; $sessions
              ];
  
          }
  
      }
  </code></pre>
  
  <p>Any information about how I can resort based on the transformer output would be really appreciated. This project is sort of at a standstill until I can figure out how to sort these courses and events based on their next upcoming date.</p>
  
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2020-07-31T10:45:49.423Z
Comments.Text: Did you ever find a solution? I'm having the same issue.
Comments.UserDisplayName: Tom De Smet
Tags: <plugin-elementapi><sorting>
Title: How do I sort and paginate a JSON feed by a key from a transformer?
ThreadText: # How do I sort and paginate a JSON feed by a key from a transformer?
  
  (Asked by: username_0 on 2017-06-27)
  
  I need to sort the entries for an Element API endpoint by a value calculated in a custom transformer. Is this possible?
  
  The use case is this: We're dealing with Events/Courses that have multiple instances (sessions) that each may contain multiple dates. I have a Neo field called `sessions` with `session` blocks that contain `date` sub-blocks. The `session` block contains `registrationLink` and `location`, and each `date` block contains the fields `date`, `startTime`, and `endTime`.
  
  However, these need to be sorted by nearest session date (the user could input the sessions/dates in any order), so I need to determine the nearest upcoming session by looking through all the sessions and finding the first date for that session. We also don't want to show sessions that have already passed. I wasn't able to figure out how to do this in Twig, so I thought it might be easier in Element API. I've got the transformer working, so I can get output like this:
  
  ```
  {
    "entries": [
      {
        "title": "TITLE REMOVED",
        "url": "URL REMOVED",
        "nextSessionStart": "2017-08-09",
        "sessions": [
          {
            "location": "LOCATION REMOVED",
            "registrationLink": "URL REMOVED",
            "dates": [
              {
                "date": "2017-08-09",
                "startTime": "8:30AM",
                "endTime": "4:30PM"
              },
              {
                "date": "2017-08-10",
                "startTime": "8:30AM",
                "endTime": "4:30PM"
              }
            ]
          },
          {
            "location": "LOCATION REMOVED",
            "registrationLink": "URL REMOVED",
            "dates": [
              {
                "date": "2017-11-02",
                "startTime": "8:30AM",
                "endTime": "4:30PM"
              },
              {
                "date": "2017-11-03",
                "startTime": "8:30AM",
                "endTime": "4:30PM"
              }
            ]
          },
          {
            "location": "LOCATION REMOVED",
            "registrationLink": "URL REMOVED",
            "dates": [
              {
                "date": "2018-02-06",
                "startTime": "8:30AM",
                "endTime": "4:30PM"
              },
              {
                "date": "2018-02-07",
                "startTime": "8:30AM",
                "endTime": "4:30PM"
              }
            ]
          }
        ]
      },
      {
        "title": "TITLE REMOVED",
        "url": "URL REMOVED",
        "nextSessionStart": "2018-07-07",
        "sessions": [
          {
            "location": "LOCATION REMOVED",
            "registrationLink": "URL REMOVED",
            "dates": [
              {
                "date": "2018-07-07",
                "startTime": "5:30PM",
                "endTime": "8:30PM"
              },
              {
                "date": "2018-08-07",
                "startTime": "8:30AM",
                "endTime": "4:30PM"
              }
            ]
          }
        ]
      },
      {
        "title": "TITLE REMOVED",
        "url": "URL REMOVED",
        "nextSessionStart": "2017-07-11",
        "sessions": [
          {
            "location": "LOCATION REMOVED",
            "registrationLink": "URL REMOVED",
            "dates": [
              {
                "date": "2017-12-05",
                "startTime": "8:30AM",
                "endTime": "4:30PM"
              }
            ]
          },
          {
            "location": "LOCATION REMOVED",
            "registrationLink": "URL REMOVED",
            "dates": [
              {
                "date": "2017-07-11",
                "startTime": "8:30AM",
                "endTime": "4:30PM"
              }
            ]
          },
          {
            "location": "LOCATION REMOVED",
            "registrationLink": "URL REMOVED",
            "dates": [
              {
                "date": "2017-10-25",
                "startTime": "8:30AM",
                "endTime": "4:30PM"
              }
            ]
          }
        ]
      }
    ],
    "meta": {
      "pagination": {
        "total": 3,
        "count": 3,
        "per_page": 10,
        "current_page": 1,
        "total_pages": 1,
        "links": [
  
        ]
      }
    }
  }
  
  ```
  
  The problem is that I need to sort and paginate the results based on that nextSessionStart key.
  
  Here's the elementapi.php config file:
  
  ```
      return [
          'defaults' => [
              'elementType' => ElementType::Entry,
              'elementsPerPage' => 10,
              'pageParam' => 'pg',
              'resourceKey' => 'entries'
          ],
  
          'endpoints' => [
              'courses.json' => function() {
  
                  require craft()->path->getConfigPath().'elementapi/CoursesTransformer.php';
  
                  return [
                      'criteria' => [
                          'section' => ['courses'],
                          'order' => 'nextSessionStart asc' //NOTE: this doesn't work and needs to be removed to get the above output
                      ],
                      'transformer' => new CoursesTransformer()
                  ];
              }
          ]
      ];
  
  ```
  
  The transformer looks like this:
  
  ```
      class CoursesTransformer extends TransformerAbstract {
  
          public function transform (EntryModel $entry) {
  
              $next_session_start = null;
              $sessions = array();
              $now = date('Y-m-d');
  
              foreach ($entry->sessions as $session) {
                  if ($session->level == 1) {
                      $this_session = array(
                          'location' => $session->location,
                          'registrationLink' => $session->registrationLink,
                          'dates' => array()
                      );
                      foreach ($session->children as $date) {
                          $this_date = $date->date;
  
                          array_push($this_session['dates'], array(
                              'date' => date_format($this_date, 'Y-m-d'),
                              'startTime' => date_format($date->startTime, 'g:iA'),
                              'endTime' => date_format($date->endTime, 'g:iA')
                          ));
  
                          if ($this_date > $now && (is_null($next_session_start) || $this_date < $next_session_start)) {
                              $next_session_start = $this_date;
                          }
                      }
                      array_push($sessions, $this_session);
                  }
              }
  
              return [
                  'title' => $entry->title,
                  'url' => $entry->url,
                  'nextSessionStart' => date_format(new DateTime($next_session_start), 'Y-m-d'),
                  'sessions' => $sessions
              ];
  
          }
  
      }
  
  ```
  
  Any information about how I can resort based on the transformer output would be really appreciated. This project is sort of at a standstill until I can figure out how to sort these courses and events based on their next upcoming date.
  
  **Tags:** plugin-elementapi, sorting
  
  > **Comments:**
  > **username_1**: Did you ever find a solution? I'm having the same issue.  
  
  ---
  
  ## 2 answers
  
  ### Answer by username_0 on 2020-08-02. Score: 1
  
  I don't know if I ever got this working exactly as I initially intended, but this is the final transformer code I ended up going with. Basically the same but with some usort calls on sessions and dates. I then had to manually do the pagination in the Twig template where courses were listed. Hope it helps!
  
  ```
      <?php
  namespace Craft;
  
  require craft()->path->getPluginsPath().'elementapi/vendor/autoload.php';
  
  use League\Fractal\TransformerAbstract;
  
  class CoursesTransformer extends TransformerAbstract {
  
      public function transform (EntryModel $entry) {
  
          $next_session_start = null;
          $sessions = array();
          $now = date('Y-m-d');
  
          foreach ($entry->sessions as $session) {
              if ($session->level == 1) {
                  $this_session = array(
                      'location' => $session->location,
                      'registrationLink' => $session->registrationLink,
                      'dates' => array()
                  );
                  foreach ($session->children as $date) {
                      array_push($this_session['dates'], array(
                          'date' => date_format($date->date, 'Y-m-d'),
                          'startTime' => date_format($date->startTime, 'g:iA'),
                          'endTime' => date_format($date->endTime, 'g:iA')
                      ));
                  }
  
                  //ensure dates are in correct order
                  usort($this_session['dates'], function($a,$b) {
                      return $a['date'] > $b['date'];
                  });
  
                  array_push($sessions, $this_session);
              }
          }
  
          //ensure sessions are in correct order
          usort($sessions, function($a,$b) {
              return $a['dates'][0]['date'] > $b['dates'][0]['date'];
          });
  
          return [
              'title' => $entry->title,
              'url' => $entry->url,
              'nextSessionStart' => date_format(new DateTime($entry->nextSessionStartDate), 'Y-m-d'),
              'sessions' => $sessions
          ];
  
      }
  }
  
  ```
  
  
  ---
  
  ### Answer by username_2 on 2020-08-04. Score: 1
  
  I know this is answered but I just wanted to suggest a potentially better way.
  
  I would suggest trying the [Preparse field plugin](https://plugins.craftcms.com/preparse-field). This way you can create a new field that automatically generates the data you want to sort/query (in your case, the first session date). This will only happen when you save the entry so it will likely speed up your API considerably.
  
  
  ---
  
  