modules = require LWEK_PATH . 'includes/modules.php'; // Register integration hooks immediately; Elementor may initialize lazily. add_action('plugins_loaded', [$this, 'boot'], 30); add_action('init', [$this, 'boot'], 1); add_action('elementor/elements/categories_registered', [$this, 'category']); add_action('elementor/widgets/register', [$this, 'widgets']); add_action('wp_enqueue_scripts', [$this, 'assets']); add_action('elementor/editor/before_enqueue_scripts', [$this, 'editor_assets'], 30); add_action('elementor/frontend/after_register_styles', [$this, 'assets']); add_action('elementor/frontend/after_register_scripts', [$this, 'assets']); add_action('admin_menu', [$this, 'admin_menu']); add_action('admin_enqueue_scripts', [$this, 'admin_assets']); add_action('admin_post_lwek_save_modules', [$this, 'save']); add_action('admin_post_lwek_deactivate_legacy', [$this, 'deactivate_legacy']); add_action('admin_notices', [$this, 'notices']); add_filter('plugin_action_links_' . plugin_basename(LWEK_FILE), [$this, 'action_links']); } public static function activate() { $modules = require LWEK_PATH . 'includes/modules.php'; add_option(self::OPTION, array_fill_keys(array_keys($modules), 1), '', false); self::instance()->clear_elementor_cache(); } public function enabled() { $saved = get_option(self::OPTION, null); $result = []; foreach ($this->modules as $key => $module) { // 已有模块沿用保存值;新增模块未写入 option 时默认关闭,避免升级后自动出现在编辑器。 $result[$key] = is_array($saved) && array_key_exists($key, $saved) ? !empty($saved[$key]) : false; } return $result; } /** Check active plugins, including renamed directories and network activation. */ public function legacy_plugins() { $network = is_multisite() ? (array) get_site_option('active_sitewide_plugins', []) : []; $active = array_unique(array_merge((array) get_option('active_plugins', []), array_keys($network))); $found = []; foreach ($active as $plugin) { if ($plugin === plugin_basename(LWEK_FILE) || validate_file($plugin) !== 0) { continue; } $file = WP_PLUGIN_DIR . '/' . $plugin; if (!is_readable($file)) { continue; } $header = get_file_data($file, ['domain' => 'Text Domain']); foreach ($this->modules as $key => $module) { if ($plugin === $module['legacy'] || basename($plugin) === basename($module['legacy']) || $header['domain'] === $module['folder']) { $found[$key][$plugin] = isset($network[$plugin]); } } } return $found; } public function boot() { if ($this->booted) { return; } $this->conflicts = $this->legacy_plugins(); if (!did_action('elementor/loaded') && !defined('ELEMENTOR_VERSION')) { return; } if (defined('ELEMENTOR_VERSION') && version_compare(ELEMENTOR_VERSION, '3.5.0', '<')) { return; } $this->booted = true; foreach ($this->enabled() as $key => $on) { if (!$on || isset($this->conflicts[$key])) { continue; } $module = $this->modules[$key]; if (!empty($module['min_elementor']) && (!defined('ELEMENTOR_VERSION') || version_compare(ELEMENTOR_VERSION, $module['min_elementor'], '<'))) { continue; } // Also guard against modules manually loaded as MU plugins. if (class_exists($module['class'], false) || class_exists($module['legacy_class'], false) || (!empty($module['legacy_function']) && function_exists($module['legacy_function'])) || ($key === 'pdf-library' && function_exists('alai_pdf_render_library'))) { $this->conflicts[$key] = ['手动加载的独立组件 / MU 插件' => true]; continue; } $this->loaded[$key] = $module; } if (isset($this->loaded['pdf-library'])) { require_once LWEK_PATH . 'modules/alai-pdf-library/backend.php'; } if (isset($this->loaded['whatsapp-inquiry'])) { require_once LWEK_PATH . 'modules/fucuo-whatsapp-inquiry/social-preview.php'; } } public function category($manager) { $this->boot(); if ($this->loaded) { $manager->add_category('laowang-elementor-kit', ['title' => 'FUCUO Elements', 'icon' => 'fa fa-cubes']); } } private function supports_widget_runtime($module) { return empty($module['nested']) || ( class_exists('Elementor\\Widget_Base') && class_exists(\Elementor\Modules\NestedElements\Base\Widget_Nested_Base::class) && class_exists(\Elementor\Modules\NestedElements\Controls\Control_Nested_Repeater::class) && \Elementor\Plugin::instance()->experiments->is_feature_active('container') ); } public function widgets($manager) { $this->boot(); if (!class_exists('Elementor\\Widget_Base')) { return; } $this->assets(); foreach ($this->loaded as $module) { if (!$this->supports_widget_runtime($module)) { continue; } require_once LWEK_PATH . 'modules/' . $module['folder'] . '/widget.php'; $class = $module['class']; $manager->register(new $class()); } } public function assets() { $this->boot(); foreach ($this->loaded as $module) { if (!$this->supports_widget_runtime($module)) { continue; } $assets = isset($module['assets']) && is_array($module['assets']) ? $module['assets'] : []; $version = !empty($module['version']) ? $module['version'] : LWEK_VERSION; $base = LWEK_URL . 'modules/' . $module['folder'] . '/assets/'; // 通用扩展点:复杂模块自行注册资源;这里不出现任何模块名判断。 if (!empty($assets['callback']) && is_callable($assets['callback'])) { call_user_func($assets['callback'], $version); continue; } $extra_scripts = isset($assets['extra_scripts']) && is_array($assets['extra_scripts']) ? $assets['extra_scripts'] : []; $extra_handles = []; foreach ($extra_scripts as $extra) { wp_register_script( $extra['handle'], $base . $extra['file'], isset($extra['deps']) ? $extra['deps'] : [], $version, true ); $extra_handles[] = $extra['handle']; } if (!empty($assets['style']['handle'])) { wp_register_style( $assets['style']['handle'], $base . $assets['style']['file'], isset($assets['style']['deps']) ? $assets['style']['deps'] : [], $version ); } if (!empty($assets['script']['handle'])) { $deps = array_merge( ['elementor-frontend'], $extra_handles, isset($assets['script']['deps']) ? $assets['script']['deps'] : [] ); wp_register_script( $assets['script']['handle'], $base . $assets['script']['file'], array_values(array_unique($deps)), $version, true ); } } } public function editor_assets() { $this->boot(); foreach ($this->loaded as $module) { if (!$this->supports_widget_runtime($module)) { continue; } $asset = $module['assets']['editor'] ?? null; if (!$asset) { continue; } wp_enqueue_script( $asset['handle'], LWEK_URL . 'modules/' . $module['folder'] . '/assets/' . $asset['file'], $asset['deps'] ?? [], $module['version'] ?? LWEK_VERSION, true ); } } public function admin_menu() { add_menu_page('FUCUO Elements · Elementor 组件库', 'FUCUO 组件库', 'manage_options', 'laowang-elementor-kit', [$this, 'page'], 'dashicons-screenoptions', 58); add_submenu_page('laowang-elementor-kit', '组件管理', '组件管理', 'manage_options', 'laowang-elementor-kit', [$this, 'page']); if (isset($this->loaded['pdf-library'])) { add_submenu_page('laowang-elementor-kit', 'PDF 画册', 'PDF 画册', 'manage_options', 'edit.php?post_type=alai_pdf_book'); add_submenu_page('laowang-elementor-kit', '资料分类', '资料分类', 'manage_options', 'edit-tags.php?taxonomy=alai_pdf_category&post_type=alai_pdf_book'); add_submenu_page('laowang-elementor-kit', '下载客户资料', '下载客户资料', 'manage_options', 'edit.php?post_type=alai_pdf_lead'); } } public function admin_assets($hook) { if ($hook !== 'toplevel_page_laowang-elementor-kit') { return; } wp_enqueue_style('lwek-admin', LWEK_URL . 'assets/admin.css', [], LWEK_VERSION); wp_enqueue_script('lwek-admin', LWEK_URL . 'assets/admin.js', [], LWEK_VERSION, true); } public function action_links($links) { array_unshift($links, '组件管理'); return $links; } public function notices() { $screen = get_current_screen(); if (!$screen || !in_array($screen->id, ['plugins', 'plugins-network', 'toplevel_page_laowang-elementor-kit'], true)) { return; } if (!current_user_can('manage_options')) { return; } if (!did_action('elementor/loaded')) { echo '

FUCUO 组件库:请先安装并启用 Elementor(免费版即可),启用后组件自动生效。

'; } elseif (defined('ELEMENTOR_VERSION') && version_compare(ELEMENTOR_VERSION, '3.5.0', '<')) { echo '

FUCUO 组件库需要 Elementor 3.5 或更高版本。

'; } if ($this->conflicts) { $names = []; foreach ($this->conflicts as $key => $plugins) { $names[] = $this->modules[$key]['title']; } echo '

FUCUO 组件库检测到独立插件仍在加载:' . esc_html(implode('、', $names)) . '。这些组件暂由原插件提供,合集开关不能控制原插件。请先停用对应独立插件,再使用合集。前往组件管理

'; } } public function save() { if (!current_user_can('manage_options')) { wp_die('无权修改组件设置。', '', ['response' => 403]); } check_admin_referer('lwek_save_modules'); $values = []; foreach ($this->modules as $key => $module) { $value = isset($_POST['modules'][$key]) && is_string($_POST['modules'][$key]) ? sanitize_text_field(wp_unslash($_POST['modules'][$key])) : ''; $values[$key] = $value === '1' ? 1 : 0; } $changed = $this->enabled() !== array_map('boolval', $values); update_option(self::OPTION, $values, false); if ($changed) { $this->clear_elementor_cache(); } wp_safe_redirect(admin_url('admin.php?page=laowang-elementor-kit&saved=1')); exit; } private function clear_elementor_cache() { if (class_exists('\\Elementor\\Plugin') && isset(\Elementor\Plugin::$instance->files_manager)) { $manager = \Elementor\Plugin::$instance->files_manager; if (is_callable([$manager, 'clear_cache'])) { $manager->clear_cache(); } } do_action('lwek/modules_updated'); } public function deactivate_legacy() { if (!current_user_can('manage_options') || !current_user_can('activate_plugins')) { wp_die('无权停用插件。', '', ['response' => 403]); } check_admin_referer('lwek_deactivate_legacy'); require_once ABSPATH . 'wp-admin/includes/plugin.php'; foreach ($this->legacy_plugins() as $plugins) { foreach ($plugins as $plugin => $network) { if (!$network) { deactivate_plugins($plugin, false, false); } } } $this->clear_elementor_cache(); wp_safe_redirect(admin_url('admin.php?page=laowang-elementor-kit&migrated=1')); exit; } private static function notice_requested($key) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only banner flag; does not execute an action. return isset($_GET[$key]) && is_string($_GET[$key]) && sanitize_text_field(wp_unslash($_GET[$key])) === '1'; } public function page() { if (!current_user_can('manage_options')) { return; } $enabled = $this->enabled(); $legacy = $this->legacy_plugins(); $total = count($this->modules); ?>
FUCUO / ELEMENTS

FUCUO Elements · Elementor 组件库 v

一个插件,统一管理 个 Elementor 组件。

建站老王

组件开关已保存。请重新打开或刷新 Elementor 编辑器;如前台仍显示旧内容,请清除网站页面缓存和 CDN 缓存。

已停用本站检测到的原独立插件,数据保留。网络启用的插件请到网络管理中单独停用。

检测到原独立插件仍处于启用状态

先勾选要使用的合集组件并保存,再停用对应独立插件。此操作不会删除页面配置、画册或客户资料。

若为网络启用,请到「网络管理 → 插件」停用对应插件。

开关说明

开启:可在 Elementor「FUCUO 组件库」分组中使用。关闭:不注册、不加载该模块,编辑器中不显示,已有页面中的该组件也会暂时停止渲染。原配置与数据库资料保留,重新开启后恢复。

原组件标识保持不变,方便已有页面切换到合集。关闭已在使用的组件前,建议先替换页面内容;组件关闭期间请勿删除编辑器中的缺失组件占位。

组件管理 / 已选择开启
modules as $key => $module) { ?>

建站老王conflicts[$key]) ? '原插件冲突,尚未接管' : ($enabled[$key] ? (isset($this->loaded[$key]) ? '模块已加载' : '开关已开启,等待 Elementor 加载') : '已关闭'); ?>
修改开关后点击保存,再刷新 Elementor 编辑器。
安装、迁移与使用说明
  1. 需要 WordPress 6.0+、PHP 7.4+、Elementor 3.5+;免费版 Elementor 即可,无需 Pro。
  2. 已有独立插件:先在合集勾选对应组件并保存,再停用独立插件,由合集接管。
  3. 打开 Elementor 页面,在「FUCUO 组件库」中拖入组件,也可直接搜索组件名称。
  4. PDF 资料在本菜单下的「PDF 画册」添加;客户填写的下载资料在「下载客户资料」查看。
  5. 画册使用媒体库公开文件地址供在线阅读;资料表单是下载引导,不提供 PDF 文件保密或访问权限保护。
  6. 保存开关会清理 Elementor 生成文件;页面缓存、服务器缓存及 CDN 缓存需按网站环境自行清理。
  7. 停用或删除合集不会自动删除页面配置、PDF、客户资料及开关设置。