Andy Holmes
Andy Holmes

Reputation: 8077

List available ACF Flexible Layout options

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

Upvotes: 5

Views: 3847

Answers (3)

Matt Keys
Matt Keys

Reputation: 439

Assuming that your flexible content layouts all exist within a single field. The easiest way to do what you are asking for is just to use the ACF internal "get_field_object" function, and pass it the field ID of your flexible content field.

$field_data = get_field_object( 'field_5e98b383fa39f' );

This will return an array of field data containing your layouts.

$field_data['layouts']

From there you can loop through the layouts to get their name, label, sub fields, etc.

No need to go through all the hoops above. This will also read from acf-json files if you use that functionality.

Upvotes: 0

Daniel Vickers
Daniel Vickers

Reputation: 1074

So what it seems like you are looking for is the below:

  • Customers website has a custom field that lists multiple options for them to select in order to alter the page layout (sort of like a template).
  • You want to be able to disable certain layouts for certain customers website without editing the custom field and/or the plugin code.

My answer for this would be to use the ACF User Role Plugin and limit the accounts that can see certain fields i.e. limit the fields to just your user role so only you have access to this (may have to create a new user role if they have the same role as you).

You would then want to add to your current custom fields another section for each layout that is a radio button that displays something like "Enable" and "Disable". And then you want to edit your layout fields to have conditional formatting where it checks the value of this field and if it is not equal to enable then it doesn't display.

  1. Install The Plugin
  2. Create a Radio Button field with the options enable/disable
  3. Limit the user role that can see the radio button field
  4. Add conditioning to the layouts to only display when the matching radio button is equal to enable
  5. Enable / Disable the layouts you don't want to appear

Additional Steps - You may need to create another user role for this method if they share the same role.

There is multiple plugins out there that you can use, just search create a new user role in wordpress. All you have to do is give it the exact same permissions as your role but it allows you to select a role that only applies to you so they cant see the field.

I hope this helps, if not I can clarify further.

OPTION 2:

  1. Create options page, limit its view to super admin
  2. Add checkboxes to options page for disable/enable
  3. Connect to the flexible fields dropdown list
  4. Run if statement to run the remove from array php on checkbox value = disable
  5. Update the flexible fields dropdown
  6. Finished

Since you are happy with the other answered I won't go through the code for this, it'd be similar just minus the json part and the success message.

Upvotes: 2

M. Ferguson
M. Ferguson

Reputation: 1421

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.

Upvotes: 2

Related Questions