By default, the media array attached to any content object is set to be sorted by a custom sort order. The original sort order you create, however, is difficult to control if you are using batch uploads: there is no way to ensure the media will be saved to the database in a particular order.


Once attached to a content object, the sort order of your media can be rearranged through simple drag 'n' drop. However, if you carefully name your files, for example, as

attachment_1.jpg
attachment_2.jpg
attachment_3.jpg
...
attachment_15.jpg

you may want an easy way to guarantee that your images are sorted alphabetically by filename, preserving your sequence. While you could simply reorder them manually, this could quickly become tedious.


If you want to automate this process in the Manifesto manner, you could write a quick script to automate the alphabetical re-ordering of your images.


The ManifestoListener class is basically a utility class for creating scripts to be executed in response to a particular event. The method ShoppingCartListener::cartable_edit is called whenever a Product is being edited (where the "object_editform" event is triggered), and the method adds ecommerce-related form fields to the Product editing page.


So for our DatedPost content, we want to ensure sequential ordering of our attached media.


We're going to edit our DatedPostListener class (make a theme-specific clone first, if you haven't already), and add a new event like so:


public static function sequential_sort(&$obj)
{
    $obj->get_media_array();
    // Re-order based on file name
    usort($obj->media_array, function($a, $b) {
        // This convoluted comparison handles proper numeric sorting, 
        // e.g. file_2 before file_10
        if (strlen($a->filename) < strlen($b->filename)) {
            return -1;
        }
        if (strlen($a->filename) > strlen($b->filename)) {
            return 1;
        }
        return $a->filename <=> $b->filename;
    });


    // Update sort_order property
    $oracle = new \Manifesto\Media\MediaInstanceOracle();
    foreach($obj->media_array as $i=>$mobj) {
        $oracle->reset();
        $oracle->set_set_clause('sort_order = '.($i + 1));
        $oracle->set_where_clause("objectid = $mobj->objectid");
        $oracle->update();
    }
}


Then you simply register a new event listener for the object_postsave event, specifying that it should execute your DatedPostListener::sequential_sort method whenever a DatedPost content object is saved.


After initial upload of media to a brand-new post, the sort order may appear random, but once you've saved the post, the custom function is triggered, and the media array receives a new sort order based on filename sequence!