skip to Main Content

In WordPress I am using ACF to create a page builder using flexible content fields. For each component I’m manually creating _component-name.scss and appending it to my main SCSS file. This is fine but prone to error.

Given this I was looking at the ACF filters and saw that there is acf/update_field so my intention was to say when the flexible content field is updated loop through the layouts array and create scss files using the layout name, as then I couldn’t forget.

An issue I’m having is that the creation is all fine, but when you rename a layout I really want to update the name of the corresponding scss file, however, I don’t know what the name previously was.

Here is my attempt, which handles creation okay, but I’m stumped on renaming.

add_filter('acf/update_field', 'create_css_files', 10, 1);

/**
 * When ACF Fields are saved, check to see if it was the page builder,
 * if it was, attempt to create a new scss file for any new elements within our page builder.
 * Note that get_stylesheet_directory gets the root of the current theme.
 *
 * @param [type] $field
 *
 * @return void
 */
function create_css_files($field)
{
    if ($field['name'] == 'page_builder_elements') {
        foreach ($field['layouts'] as $layout) {
            $name = $layout['name'];

            // Only allow letters, numbers, hyphens and underscores
            $clean_name = preg_replace('/[^A-Za-z0-9_-]/', '', $name);

            // Replace underscores with hyphens in the layout name
            $clean_name = str_replace('_', '-', $clean_name);

            $file_path = get_stylesheet_directory() . '/resources/styles/scss/_' . $clean_name . '.scss';

            $directory = dirname($file_path);

            if (!file_exists($directory)) {
                mkdir($directory, 0755, true);
            }

            if (!file_exists($file_path)) {
                $file_handle = fopen($file_path, 'w');
                fclose($file_handle);
            }

            $import_directive = "@import 'scss/$clean_name';" . "n";

            $base_stylesheet_path = get_stylesheet_directory() . '/resources/styles/app.scss';

            file_put_contents($base_stylesheet_path, $import_directive, FILE_APPEND);
        }
    }

    return $field;
}

2

Answers


  1. Chosen as BEST ANSWER

    I don't know if I'm happy with it, but this is what I ended up with.

    <?php
    
    add_filter('acf/load_field', 'my_acf_load_field');
    
    function my_acf_load_field($field)
    {
        if ($field['type'] === 'flexible_content') {
            foreach ($field['layouts'] as $key => $layout) {
                // Store the original layout name as post meta
                update_post_meta(
                    get_the_ID(),
                    'acf_layout_original_name_' . $key,
                    $layout['name']
                );
            }
        }
    
        return $field;
    }
    
    add_filter('acf/update_field', 'create_css_files', 10, 1);
    
    /**
     * When ACF Fields are saved, check to see if it was the page builder,
     * if it was, attempt to create a new scss file for any new elements within our page builder.
     * Note that get_stylesheet_directory gets the root of the current theme.
     *
     * @param [type] $field
     *
     * @return void
     */
    function create_css_files($field)
    {
        $base_stylesheet_path = get_stylesheet_directory() . '/resources/styles/app.scss';
        $base_scss_component_path = get_stylesheet_directory() . '/resources/styles/scss/';
    
        // If we're not in the page builder, I don't care
        if ($field['name'] !== 'page_builder_elements') {
            return $field;
        }
    
        // Store
        $layout_names = [];
    
        // Create the base scss component directory
        if (!file_exists($base_scss_component_path)) {
            mkdir($base_scss_component_path, 0755, true);
        }
    
        // Loop through the layouts array and create scss files according to the names
        foreach ($field['layouts'] as $key => $layout) {
            $previous_name = get_post_meta(get_the_ID(), 'acf_layout_original_name_' . $layout['key']);
            $current_name = $layout['name'];
    
            // If a component was renamed, rename the related scss file
            if ($current_name !== $previous_name) {
                if ($previous_name !== '') {
                    $previous_clean_name = sanitize_name($previous_name[0]);
                    $previous_file_path = get_stylesheet_directory() . '/resources/styles/scss/_' . $previous_clean_name . '.scss';
    
                    $new_clean_name = sanitize_name($current_name);
                    $new_file_path = get_stylesheet_directory() . '/resources/styles/scss/_' . $new_clean_name . '.scss';
    
                    if (file_exists($previous_file_path)) {
                        rename($previous_file_path, $new_file_path);
                    } else {
                        file_put_contents($new_file_path, '');
                    }
    
                    $layout_names[] = $new_clean_name;
                }
            } else {
                $layout_names[] = sanitize_name($current_name);
            }
        }
    
        // Get the contents of our main scss file
        $contents = file_get_contents($base_stylesheet_path);
    
        // Search for import statements
        $search_pattern = "/@imports+'scss/[^s;]+?';/";
    
        // Remove lines that match the pattern
        $modified_contents = preg_replace($search_pattern, '', $contents);
    
        // Remove blank lines
        $modified_contents = preg_replace("/(^[rn]*|[rn]+)[st]*[rn]+/", "n", $modified_contents);
    
        // Write the modified contents back to the file
        file_put_contents($base_stylesheet_path, $modified_contents);
    
        $importStatements = '';
    
        $importStatements .= "n";
    
        foreach ($layout_names as $import_name) {
            $importStatements .= "@import 'scss/" . $import_name . "';n";
        }
    
        file_put_contents($base_stylesheet_path, $importStatements, FILE_APPEND);
    
        return $field;
    }
    
    /**
     * Simple helper to clean name given.
     *
     * @param [type] $name
     *
     * @return void
     */
    function sanitize_name($name)
    {
        $clean_name = preg_replace('/[^A-Za-z0-9_-]/', '', $name);
        $clean_name = str_replace('_', '-', $clean_name);
    
        return $clean_name;
    }
    

  2. Probably the simplest way to manage this is to analyze the files that exist in the directory, and the files that are not in the list of layout names, then delete those files.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search