基于ACF字段更新自动管理SCSS文件及重命名问题
问题描述
我在WordPress中用ACF(高级自定义字段)的灵活内容字段搭建页面构建器,之前手动为每个组件创建_component-name.scss文件并导入主SCSS文件,这种方式容易出错。于是尝试利用acf/update_field过滤器,在灵活内容字段更新时遍历layouts数组自动生成对应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; }
解决方案
要解决重命名布局时同步SCSS文件的问题,核心是获取布局更新前的原始名称。由于acf/update_field仅提供更新后的字段数据,需要借助acf/prepare_field过滤器先缓存原始布局信息,再在更新时对比新旧名称。
步骤1:缓存原始布局数据
添加acf/prepare_field过滤器,在字段加载时缓存原始布局的key与name映射关系:
add_filter('acf/prepare_field', 'cache_original_layouts', 10, 1); function cache_original_layouts($field) { if ($field['name'] == 'page_builder_elements') { $original_layouts = []; foreach ($field['layouts'] as $layout) { $original_layouts[$layout['key']] = $layout['name']; } wp_cache_set('acf_page_builder_original_layouts', $original_layouts, 'acf'); } return $field; }
步骤2:更新时对比新旧名称并同步文件
修改原有create_css_files函数,取出缓存数据对比布局新旧名称,实现文件重命名与导入语句更新:
add_filter('acf/update_field', 'create_css_files', 10, 1); function create_css_files($field) { if ($field['name'] != 'page_builder_elements') { return $field; } $original_layouts = wp_cache_get('acf_page_builder_original_layouts', 'acf'); $scss_dir = get_stylesheet_directory() . '/resources/styles/scss/'; $app_scss_path = get_stylesheet_directory() . '/resources/styles/app.scss'; $existing_imports = file_get_contents($app_scss_path); foreach ($field['layouts'] as $layout) { // 处理新名称的清理逻辑 $new_name = $layout['name']; $clean_new_name = preg_replace('/[^A-Za-z0-9_\-]/', '', $new_name); $clean_new_name = str_replace('_', '-', $clean_new_name); $new_file_path = $scss_dir . '_' . $clean_new_name . '.scss'; // 处理重命名逻辑 if ($original_layouts && isset($original_layouts[$layout['key']])) { $old_name = $original_layouts[$layout['key']]; $clean_old_name = preg_replace('/[^A-Za-z0-9_\-]/', '', $old_name); $clean_old_name = str_replace('_', '-', $clean_old_name); $old_file_path = $scss_dir . '_' . $clean_old_name . '.scss'; if ($clean_old_name != $clean_new_name && file_exists($old_file_path)) { // 重命名SCSS文件 rename($old_file_path, $new_file_path); // 更新app.scss中的导入语句 $old_import = "@import 'scss/$clean_old_name';"; $new_import = "@import 'scss/$clean_new_name';"; $existing_imports = str_replace($old_import, $new_import, $existing_imports); } } // 保留原有新布局文件创建逻辑 $directory = dirname($new_file_path); if (!file_exists($directory)) { mkdir($directory, 0755, true); } if (!file_exists($new_file_path)) { fclose(fopen($new_file_path, 'w')); } // 避免重复追加导入语句 $new_import = "@import 'scss/$clean_new_name';"; if (strpos($existing_imports, $new_import) === false) { $existing_imports .= $new_import . "\n"; } } // 写入更新后的app.scss file_put_contents($app_scss_path, $existing_imports); // 清理缓存避免残留旧数据 wp_cache_delete('acf_page_builder_original_layouts', 'acf'); return $field; }
额外优化说明
- 修复了原有代码中每次更新重复追加导入语句的问题,现在会先检查语句是否已存在。
- 用布局的
key作为唯一标识(创建后不会改变),比name更可靠。 - 操作完成后清理缓存,避免影响后续字段更新操作。
内容的提问来源于stack exchange,提问作者Jesse Luke Orange
相关产品推荐
相关产品推荐

