Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

List available ACF Flexible Layout options

Tags:

I'm working on creating a settings system for a Wordpress installation, where super admins can disable some ACF Flexible Content layouts if they are not needed for the current website, without modifying the structure of the plugin.

I'm looking for a way to list all of the available ACF Flexible Content Layouts inside a new admin page.

After looking through the plugin's folders I have found the following code inside class-acf-field-flexible-content.php:

<script type="text-html" class="tmpl-popup"><?php 
    ?><div class="acf-fc-popup"><ul><?php foreach( $layouts as $layout ): 

        $atts = array(
            'href'            => '#',
            'data-layout'    => $layout['name'],
            'data-min'         => $layout['min'],
            'data-max'         => $layout['max'],
        );

        ?><li><a <?php acf_esc_attr_e( $atts ); ?>><?php echo $layout['label']; ?></a></li><?php 

    endforeach; ?></ul></div>
</script>

Which builds a list of available layouts for the client to use when creating new posts/pages.

Does anyone know of a simple way that I can build an array of ACF layouts in PHP that I can just display on a different page inside the WP Admin?

Sorry I don't really have any code to show, it's a bit of a unique request

like image 470
Andy Holmes Avatar asked Jan 10 '18 10:01

Andy Holmes


1 Answers

I have come up with a solution that on a settings page, will display all of the flexible content layouts names alongside a checkbox where you can un-select which layouts are removed from the list when you press the 'Add' button when you try to add a new layout.

As a brief introduction, I used acf-json to get all of the flexible layout names and then created another json file which holds the names of the layouts I wish to disable. I then run a function that looks at each layout name, checks if it isn't in the disabled list, and if it is, it will be removed.

To start with, I initialised the local JSON within ACF. To do this, follow the steps on https://www.advancedcustomfields.com/resources/local-json/.

I then created a new settings page within functions.php:

<?php
function add_theme_menu_item()
{
    add_options_page("Flexible Layouts", "Flexible Layouts", "manage_options", "flexible-layouts", "theme_settings_page", null, 99);
}

add_action("admin_menu", "add_theme_menu_item");
?>

Within the theme_settings_page function, you would need to decode the JSON for the flexible content group:

<?php
$jsonURL = get_template_directory_uri(). "/acf-json/flexible_content_group.json";
$contents = file_get_contents("{$jsonURL}");
$data =  json_decode($contents);
?>

I then did the same with for a JSON file that would hold all of the disabled fields (I'll explain how this file is created shortly):

<?php
$jsonDisabledFieldsURL = get_template_directory_uri(). "/acf-json/disabledFields.json";
$disabledFieldsContents = file_get_contents("{$jsonDisabledFieldsURL}");
$disabledFieldsData =  json_decode($disabledFieldsContents);
?>

I then pushed all of the layout names to an array $availableOptions:

<?php
$availableOptions = [];
foreach($data->fields as $field) {
    foreach($field->layouts as $layout) {
        array_push($availableOptions, $layout->name);
    }
}
?>

So we need a list of all fields with checkboxes and a submit button. With the submit button, I used ajax to post the disabled fields that I placed within an array:

<script type="text/javascript" src="<?php echo get_template_directory_uri(); ?>/js/lib/sweetalert2.js"></script>
<script>
    jQuery('.submit_json_handler').click(function(e){
        e.preventDefault();
        var self = jQuery(this);
        var array = [];

        jQuery('input:checkbox:not(:checked)').each(function() {
            array.push(jQuery(this).val());
        });

        jQuery.ajax({
            type:'POST',
            url:'<?php echo get_template_directory_uri(); ?>/acf-json/custom_json_handler.php',
            data: {
                'disabled_fields' : array
            },
            success:function(data){
                console.log(data);
                swal(
                  'Success!',
                  'The active layouts have now been updated.',
                  'success'
                )
            }
        });
    });
</script>

I used the SweetAlert2 plugin (https://sweetalert2.github.io/) in order to process a success message when the fields have modified.

My code for the custom_json_handler.php gets the posted disabled fields and pushes them into an array. The array is then encoded into the JSON file spoken about earlier (disabledFields.json):

<?php
    $disabledFields = $_POST['disabled_fields'];
    $disabledFieldsArray = [];

    try {   

        foreach($disabledFields as $field) {
            array_push($disabledFieldsArray, $field); 
        }

        $fp = fopen($_SERVER['DOCUMENT_ROOT']."/wp-content/themes/pblite-theme/acf-json/disabledFields.json","wb");
        fwrite($fp,json_encode($disabledFieldsArray));
        fclose($fp);

    }
    catch(Exception $e) {
        return $e;
    }

    echo "Success!";
?>

The final piece of the puzzle within the theme_settings_page function, is to create the form which will show all layouts, with checkboxes next to them which are able to be checked/unchecked based on the selected disabled fields:

<?php
$activeLayouts = array_diff($availableOptions, $disabledFieldsData);

echo "<form action=\"post\">";
echo "<table>";
foreach($data->fields as $field) {

    foreach($field->layouts as $layout) {

        if(in_array($layout->name, $activeLayouts)) {
            $checked = "checked";
        } else {
            $checked = "";
        }

        echo "<tr><td><input type=\"checkbox\" {$checked} name=\"disabled_flexible_layouts[]\" value=\"{$layout->name}\" /></td><td>{$layout->label}</td></tr>";

    }

}

echo "</table>";
echo "<p class=\"submit\"><input type=\"button\" value=\"Submit\" name=\"submit\" class=\"button button-primary submit_json_handler\" /></p>";
echo "</form>";
?>

This will then give you your list of layouts where disabled fields will be unchecked.

Lastly, I needed to use the disabled fields JSON in order to remove the list items within the 'Add' button in a page where you select a layout. To do this, I created another function within functions.php that hooks into the acf/input/admin_head (so the function will fun when ACF is present):

<?php

function acf_admin_head_layout( $field ) {

?>

<script type="text/javascript">

    (function($) {

        $(document).ready(function(){

            $.get('<?php echo get_template_directory_uri(); ?>/acf-json/disabledFields.json', function(data) {

            // alert(data);
                $.each(data, function(i, item) {

                    tmpl = $('.tmpl-popup').html();

                    //Create jQuery object
                    tmplDiv = $('<div>', {html : tmpl});

                    //Target element and remove it
                    tmplDiv.find('a[data-layout="'+item+'"]').closest('li').remove();

                    tmpl = tmplDiv.html();

                    $('.tmpl-popup').replaceWith('<script type="text-html" class="tmpl-popup">'+tmpl+'</sc'+'ript>');

                });

            });                   

        });

    })(jQuery);  

</script>  

<?php

}

add_action('acf/input/admin_head', 'acf_admin_head_layout', 10, 1);

?>

This will find the class within the page where the string is that holds the layout options, converts this to HTML so we are able to manipulate the content and store this within a temporary variable. We then loop through each of the disabled fields that were present in the JSON file and try to find a match within the data-layout attribute and if there is a match, then the closet list item (it's parent), will be removed.

We then have to add back in the <script> tags and put back into the page so that the newly cleaned list is used rather than the old one.

Once this has all be done, you should have an area within your settings menu where you have all of your layouts that you can enable/disable. You should then be able to add/edit a page and select the Add button and you should only see the layouts that you have selected in the settings page.

like image 94
M. Ferguson Avatar answered Sep 23 '22 12:09

M. Ferguson