wordpress 根据ACF字段的更新时间管理scss文件的创建

8yoxcaq7  于 2023-06-21  发布在  WordPress
关注(0)|答案(3)|浏览(105)

在WordPress中,我使用ACF来创建一个使用灵活内容字段的页面构建器。对于每个组件,我手动创建_component-name.scss并将其附加到主SCSS文件中。这很好,但容易出错。
鉴于此,我正在查看ACF过滤器,并看到有acf/update_field,所以我的意图是说,当灵活的内容字段更新时,通过布局数组循环并使用布局名称创建scss文件,因为那时我不能忘记。
我有一个问题是,创建是所有的罚款,但当你重命名一个布局,我真的想更新相应的scss文件的名称,但是,我不知道以前的名称是什么。
这是我的尝试,它可以处理创建,但我被重命名难住了。

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;
}
csga3l58

csga3l581#

最简单的管理方法可能是分析目录中存在的文件以及不在布局名称列表中的文件,然后删除这些文件。

vaqhlq81

vaqhlq812#

我不知道我是否满意,但这就是我最终得到的。

<?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 = "/@import\s+'scss\/[^\s;]+?';/";

    // Remove lines that match the pattern
    $modified_contents = preg_replace($search_pattern, '', $contents);

    // Remove blank lines
    $modified_contents = preg_replace("/(^[\r\n]*|[\r\n]+)[\s\t]*[\r\n]+/", "\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;
}
q8l4jmvw

q8l4jmvw3#

我想保留我现有的答案作为起点,但这里有一个处理编辑和删除的改进。
我希望这在未来能帮助到其他人。

<?php

/**
 * When ACF Fields are loaded, if they are flexible content store the name of each layout as a value in the post meta.
 * This will allow us to retrieve the original name later so we can do things when fields are renamed.
 *
 * @param [type] $field
 *
 * @return void
 */
function store_field_meta_data($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;
}

/**
 * When an ACF Field is updated perform the actions defined in this method.
 * Currently this is responsible for creating scss and blade files.
 *
 * @param [type] $field
 *
 * @return void
 */
function handle_field_update($field)
{
    // If we're not in the page builder, return early
    if ($field['name'] !== 'page_builder_elements' && !is_array($field['layouts'])) {
        return $field;
    }

    create_css_files($field);
    create_blade_component_files($field);

    return $field;
}

/**
 * Create Blade files based on the names of the layouts in our flexible content field.
 *
 * @param [type] $field
 *
 * @return void
 */

function create_blade_component_files($field)
{
    // If we're not in the page builder, return early
    if ($field['name'] !== 'page_builder_elements') {
        return $field;
    }

    $page_builder_directory = '/resources/views/layouts/page-builder/';

    $base_blade_component_path = get_stylesheet_directory() . $page_builder_directory;

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

    create_blade_files_from_layouts($field, $base_blade_component_path);
    delete_unused_blade_files($field, $base_blade_component_path);
}

/**
 * Loop through the layouts array of a given flexible content field and create template files.
 * These files will relate to the component name so that when building each component can be worked on in isolation.
 *
 * @param [type] $field
 * @param [type] $scss_component_path
 *
 * @return void
 */
function create_blade_files_from_layouts($field, $blade_component_path)
{
    $layout_names = [];

    foreach ($field['layouts'] as $key => $layout) {
        $previous_name = get_post_meta(get_the_ID(), 'acf_layout_original_name_' . $layout['key'], true);
        $current_name = $layout['name'];

        // If the file was renamed
        if ($current_name !== $previous_name && !empty($previous_name)) {
            $previous_clean_name = sanitize_name($previous_name);
            $previous_file_path = $blade_component_path . $previous_clean_name . '.blade.php';
            $new_clean_name = sanitize_name($current_name);
            $new_file_path = $blade_component_path . $new_clean_name . '.blade.php';

            if (file_exists($previous_file_path)) {
                rename($previous_file_path, $new_file_path);
            } else {
                create_file($new_file_path);
            }

            continue;
        }

        // If the file was not renamed
        $new_clean_name = sanitize_name($current_name);
        $new_file_path = $blade_component_path . $new_clean_name . '.blade.php';

        create_file($new_file_path);

        $layout_names[] = $new_clean_name;
    }
}

/**
 * Scan our blade directory and see if any files should be deleted as they no longer exist as a layout.
 * Note that the layout names use underscores so we've used str_replace.
 *
 * @param [type] $field
 * @param [type] $blade_component_path
 *
 * @return void
 */
function delete_unused_blade_files($field, $blade_component_path)
{
    $existing_files = get_existing_files_from_directory($blade_component_path);

    $existing_files = array_map(function ($file) {
        return basename($file);
    }, $existing_files);

    $layout_names = [];

    foreach ($field['layouts'] as $layout) {
        $layout_names[] = str_replace('_', '-', $layout['name']);
    }

    foreach ($existing_files as $file) {
        $filename = pathinfo($file, PATHINFO_FILENAME);
        $filename = str_replace('.blade', '', $filename);

        if (!in_array($filename, $layout_names)) {
            $file_path = $blade_component_path . $filename . '.blade.php';

            if (file_exists($file_path)) {
                unlink($file_path);
            }
        }
    }
}

/**
 * Create SCSS files based on the names of the layouts in our flexible content field.
 * It also appends the necessary import statements to the main scss file.
 *
 * @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/components/page-builder/';

    // Create the base scss component directory if it doesn't exist
    if (!file_exists($base_scss_component_path)) {
        mkdir($base_scss_component_path, 0755, true);
    }

    $layout_names = create_scss_files_from_layouts($field, $base_scss_component_path);

    delete_unused_css_files($field, $base_scss_component_path);

    update_main_stylesheet($base_stylesheet_path, $layout_names);
}

/**
 * Loop through the layouts array of a given flexible content field and create scss files.
 * These files will relate to the component name so that when building each component can be worked on in isolation.
 *
 * @param [type] $field
 * @param [type] $scss_component_path
 *
 * @return void
 */
function create_scss_files_from_layouts($field, $scss_component_path)
{
    $layout_names = [];

    foreach ($field['layouts'] as $key => $layout) {
        $previous_name = get_post_meta(get_the_ID(), 'acf_layout_original_name_' . $layout['key'], true);
        $current_name = $layout['name'];

        if ($current_name !== $previous_name && !empty($previous_name)) {
            $previous_clean_name = sanitize_name($previous_name);
            $previous_file_path = $scss_component_path . '_' . $previous_clean_name . '.scss';
            $new_clean_name = sanitize_name($current_name);
            $new_file_path = $scss_component_path . '_' . $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;

            continue;
        }

        // If the file was not renamed
        $new_clean_name = sanitize_name($current_name);
        $new_file_path = $scss_component_path . '_' . $new_clean_name . '.scss';

        create_file($new_file_path);

        $layout_names[] = $new_clean_name;
    }

    return $layout_names;
}

/**
 * Remove unused SCSS files.
 *
 * @param [type] $field
 * @param [type] $base_scss_component_path
 *
 * @return void
 */
function delete_unused_css_files($field, $base_scss_component_path)
{
    $existing_files = get_existing_files_from_directory($base_scss_component_path);

    $existing_files = array_map(function ($file) {
        return basename($file);
    }, $existing_files);

    $layout_names_with_underscore = [];

    foreach ($field['layouts'] as $layout) {
        $layout_names_with_underscore[] = '_' . str_replace('_', '-', $layout['name']);
    }

    foreach ($existing_files as $file) {
        $filename = pathinfo($file, PATHINFO_FILENAME);

        if (!in_array($filename, $layout_names_with_underscore)) {
            $file_path = $base_scss_component_path . $filename . '.scss';

            if (file_exists($file_path)) {
                unlink($file_path);
            }
        }
    }
}

/**
 * Add the import statements to our main scss file, in this case app.scss
 * This function removes all page builder imports and then re-adds them,
 * this allows us to keep our imports up to date.
 *
 *
 * @param [type] $base_stylesheet_path
 * @param [type] $layout_names
 *
 * @return void
 */
function update_main_stylesheet($base_stylesheet_path, $layout_names)
{
    $contents = file_get_contents($base_stylesheet_path);

    $contents = preg_replace("/@import\s+'(components\/page-builder[^']+?)';\n?/", '', $contents);

    $importStatements = '';

    foreach ($layout_names as $import_name) {
        $importStatements .= "@import 'components/page-builder/" . $import_name . "';\n";
    }

    $contents .= $importStatements;

    file_put_contents($base_stylesheet_path, $contents);
}

/**
 * Simple helper to clean name given.
 *
 * @param [type] $name
 *
 * @return string $clean_name
 */
function sanitize_name($name)
{
    $clean_name = preg_replace('/[^A-Za-z0-9_\-]/', '', $name);
    $clean_name = str_replace('_', '-', $clean_name);

    return $clean_name;
}

/**
 * Creates an empty file if it does not exist.
 *
 * @param [type] $file_path
 *
 * @return void
 */
function create_file($file_path)
{
    if (!file_exists($file_path)) {
        file_put_contents($file_path, '');
    }
}

/**
 * Retrieves all the files from a given directory and stores the full path in an array.
 * We store the full path in case we need to do anything at a system level, rather than relative paths.
 *
 * @param string $path
 *
 * @return array $files
 */
function get_existing_files_from_directory($path, $fullPath = true)
{
    if (!is_dir($path)) {
        throw new InvalidArgumentException("Invalid directory path: $path");
    }

    $files = [];

    $directory = scandir($path);
    $directory = array_diff($directory, ['.', '..']);

    foreach ($directory as $file) {
        if (is_file($path . $file)) {
            $files[] = $fullPath ? $path . $file : $file;
        }
    }

    return $files;
}

add_filter('acf/load_field', 'store_field_meta_data');
add_filter('acf/update_field', 'handle_field_update', 10, 1);

需要注意的是,为了清晰起见,路径可能会存储为更高的变量。

相关问题