Home Blog Using an ACF repeater to set a custom order for global content in WordPress
Web Development

Using an ACF repeater to set a custom order for global content in WordPress

TLDR: Code tutorial on how to control the order of carousel slides on a per-page basis while content is updated globally through an options page ACF repeater.


What does this code achieve?

Allows a WordPress admin user to display repeater-based content from an ACF options page and select a custom order on each page by using a pre-filled ACF repeater as the ordering control.

Screenshot of the prefilled ACF block used for controlling the order of slides. A bit of dashboard-only CSS was applied to disable editing of field values.

Step 1: Prefill the repeater with global content

To prefill our block we’ll hook into ACF’s load_value filter here passing in the repeater’s ID which in my case is “field_65fc7016b9bc1“. See my comments in the code snippet below for more details on the functionality.

PHP

add_filter('acf/load_value/key=field_65fc7016b9bc1', function($value, $postId, $field){
    
    //Get the slider content from the options page
    $slider = get_field('hero_slider', 'options');

    /* refer to the field we want to pre-fill as $repeater 
    and make sure it exists */
    $repeater = $value ? $value : [];

    /* First compare $repeater's content with $slider's content
    and update/create the rows that exist in $slider  */
    $slidesToUpdate = airtightGetSlidesToUpdate($slider, $repeater);

    if (!empty($slidesToUpdate)):
        array_map(function($id) use (&$repeater){

            /* foreach slide in $slider, 
            push a new row into to $repeater 
            
            $repeater subfields:
                - field_65fc7020b9bc2 refers to an image 
                - field_65fc7cc8ff08e refers to a text field
            */

            return array_push($repeater, [
                'field_65fc7020b9bc2' => $id,
                'field_65fc7cc8ff08e' => $id,
            ]);
        }, $slidesToUpdate);
    endif; 

    //Then check if $repeater has slides that no longer exist in $slider
    $slidesToDelete = airtightGetSlidesToDelete($slider, $repeater);

    if (!empty($slidesToDelete)):

        //to delete, just filter out the slides that shouldn't be there
        $repeater = array_filter($repeater, function($row) use ($slidesToDelete){    
            return !in_array($row['field_65fc7020b9bc2'], $slidesToDelete);
        });
    endif; 

    return $repeater;
}, 10, 3);


//returns slides that should be updated
function airtightGetSlidesToUpdate($slider, $repeater = []){

    if(!is_array($repeater)) return [];

    $slideIds = array_map(function($slide){
        return $slide['banner_image']['ID'];
    }, $slider);

    $savedIds = array_map(function($row){
        return intval($row['field_65fc7cc8ff08e']);
    }, $repeater);

    $notPresent = array_filter($slideIds, function($id) use ($savedIds){
        return !in_array($id, $savedIds);
    });

    return $notPresent;
}


//returns slides that should be deleted
function airtightGetSlidesToDelete($slider, $repeater = []){

    if(!is_array($repeater)) return [];

    $slideIds = array_map(function($slide){
        return $slide['banner_image']['ID'];
    }, $slider);

    $savedIds = array_map(function($row){
        return intval($row['field_65fc7cc8ff08e']);
    }, $repeater);

    $unwanted = array_filter($savedIds, function($id) use ($slideIds){
        return !in_array($id, $slideIds);
    });

    return $unwanted;
}

Step 2: Apply custom sorting logic

Apply the selected custom order to your content using a custom PHP usort function.

PHP
/* using parameters
    -$slide: a repeater row from global content as 
    -$sorter: the order control (repeater field)

    - return an integer to indicate posision */
function airtightGetSlidePosition($slide, $sorter){
    $postion = array_filter($sorter, function($value, $key) use ($slide){
        $imgId = $slide['banner_image']['id'] ?? null;
        
        return $imgId == $value['slide_img']['id'];
    }, ARRAY_FILTER_USE_BOTH);

    if(!is_array($postion)) return;
    
    $position = array_keys($postion)[0];

    return $position;
}

/* just compare order of slides and apply a custom sort
using PHP spaceship <=> operator */
function airtightCustomSortSlider($slider, $sorter){
    
    usort($slider, function($a, $b) use ($sorter){
        
        $aPosition = airtightGetSlidePosition($a, $sorter);
        $bPosition = airtightGetSlidePosition($b, $sorter);

        return $aPosition <=> $bPosition;
    });

    return $slider;
}
PHP
//template usage example

<div class="airtight-slider">
    <?php
        $slider = get_field('hero_slider', 'options');
        $sorter = get_field('airtight_custom_slide_order');


        if(!empty($sorter)):
            $slider = airtightCustomSortSlider($slider, $sorter);
        endif;
    ?>
</div>

Step 3: Apply admin CSS

We don’t want the WordPress user to be able to edit the prefilled slides shown within the block aside from drag and drop re-ordering.

Let’s enqueue an admin stylesheet, and knock out the default ACF controls for add, delete, edit remove etc. using pointer-events and display: none.

PHP
//enqueue a stylesheet for the dashboard only
add_action( 'admin_enqueue_scripts', function(){
    wp_enqueue_style( 'airtight-admin-styles', get_template_directory_uri()  . "/assets/admin.css", array(), '0.0.2' );
});
CSS
.acf-field[data-key="field_65fc7020b9bc2"]{
    pointer-events: none;
}

//makes input appear disabled
.acf-field[data-key="field_65fc7cc8ff08e"] input{
    
    pointer-events: none;
    opacity: 0.7;
    background-color: #dcdcdc;
}

[data-key="field_65fc7016b9bc1"] .acf-actions{
    display: none;
}

[data-key="field_65fc7016b9bc1"] .acf-row-handle.remove{
    pointer-events: none;
}
You may also be interested in reading
Ranked – The best and worst character portrayals in Netflix’s Avatar: The Last Airbender live-action remake
Avatar! Such nostalgia. This show captivated me as a kid and I’m still waiting for them to make a fourth season. Water, Earth, Fire…. Air right? It all ended too soon for how good it was....
Continue reading
You deserve better web hosting
I’ve seen it over and over. My clients who use a massive public hosting company like GoDaddy or NetworkSolutions often end up frustrated with unexplainable issues and unhelpful tech support. Tied to notching in their next...
Continue reading