目录
Toggle
悦然wordpress建站之前分享了一些Elementor V4的内容,最近几天试用下来发现V4的BUG还有不少,比如它的变量和类别集居然不支持导入导出。以前的全局样式都是可以的,这可能是官方还未完善,这么重要的一个功能居然都没有,这就太不应该了。
虽然官方暂时未提供导入导出的功能,但是没关系,有大佬出手了,接下来分享一个工具和使用方法
以下是一个国外大佬分享的代码,大家可以直接添加到wordpress网站的主题functions.php文件中,或者是添加到wp code之类的代码管理插件中并启用。
/**
* Elementor V4 Class Manager
*/
/*Elementor V4 Design System Export/Import (Variables + Classes)*/
if (!defined('ABSPATH')) exit;
if (is_admin()) {
class WSQ_Elementor_V4_Design_System_Portable {
const CAP = 'manage_options';
const NONCE_ACTION = 'wsq_el_v4_ds_nonce';
const ACTION_EXPORT = 'wsq_el_v4_ds_export';
const ACTION_BACKUP = 'wsq_el_v4_ds_backup';
const ACTION_IMPORT = 'wsq_el_v4_ds_import';
const FORMAT_ID = 'wsq_el_v4_design_system_v2';
// Keep uploads sane (JSON can be big-ish, but shouldn’t be huge)
const MAX_UPLOAD_BYTES = 5_000_000; // 5MB
public function __construct() {
add_action('admin_menu', [$this, 'menu']);
add_action('admin_post_' . self::ACTION_EXPORT, [$this, 'handle_export']);
add_action('admin_post_' . self::ACTION_BACKUP, [$this, 'handle_backup']);
add_action('admin_post_' . self::ACTION_IMPORT, [$this, 'handle_import']);
}
public function menu() {
add_management_page(
'Elementor V4 Export',
'Elementor V4 Export',
self::CAP,
'wsq-el-v4-design-system',
[$this, 'page']
);
}
private function get_active_kit_id(): int {
$kit_id = (int) get_option('elementor_active_kit');
// Fallback: attempt to locate a published Kit (rarely needed)
if ($kit_id <= 0) {
$q = new WP_Query([
'post_type' => 'elementor_library',
'post_status' => 'publish',
'posts_per_page' => 1,
'tax_query' => [
[
'taxonomy' => 'elementor_library_type',
'field' => 'slug',
'terms' => ['kit'],
]
],
'fields' => 'ids',
]);
if (!empty($q->posts[0])) {
$kit_id = (int) $q->posts[0];
}
}
return $kit_id;
}
private function sanitize_export_name($name): string {
$name = (string) $name;
$name = trim($name);
if ($name === '') $name = 'Blueprint Variables and Classes';
// Keep it safe for filenames + readable
$name = wp_strip_all_tags($name);
$name = preg_replace('/\s+/', ' ', $name);
$name = preg_replace('/[^a-zA-Z0-9 _-]/', '', $name);
return substr($name, 0, 80);
}
private function filename_slug($name): string {
$name = strtolower($name);
$name = preg_replace('/[^a-z0-9]+/', '-', $name);
$name = trim($name, '-');
return $name ?: 'design-system';
}
public function page() {
if (!current_user_can(self::CAP)) wp_die('Insufficient permissions.');
$kit_id = $this->get_active_kit_id();
$nonce = wp_create_nonce(self::NONCE_ACTION);
$default_name = 'Blueprint Variables and Classes';
echo '<div class="wrap">';
echo '<h1>Elementor Design System (V4)</h1>';
echo '<p><strong>After importing:</strong> go to <code>Elementor → Editor → Tools</code> and click <strong>Regenerate CSS & Data</strong>.</p>';
if ($kit_id > 0) {
echo '<p><strong>Active Kit ID:</strong> ' . esc_html($kit_id) . '</p>';
} else {
echo '<p><strong style="color:#b32d2e;">Active Kit not found.</strong> Elementor must have a Kit to store design system data.</p>';
}
if (!empty($_GET['wsq_import']) && $_GET['wsq_import'] === 'ok') {
echo '<div class="notice notice-success"><p>Imported successfully. Now regenerate: <code>Elementor → Editor → Tools → Regenerate CSS & Data</code>.</p></div>';
} elseif (!empty($_GET['wsq_import']) && $_GET['wsq_import'] === 'fail') {
$msg = isset($_GET['wsq_msg']) ? sanitize_text_field(wp_unslash($_GET['wsq_msg'])) : 'Import failed. Check the JSON file and try again.';
echo '<div class="notice notice-error"><p>' . esc_html($msg) . '</p></div>';
}
echo '<hr/>';
// EXPORT
echo '<h2>Export (Variables + Classes)</h2>';
echo '<form method="post" action="' . esc_url(admin_url('admin-post.php')) . '">';
echo '<input type="hidden" name="action" value="' . esc_attr(self::ACTION_EXPORT) . '">';
echo '<input type="hidden" name="_wpnonce" value="' . esc_attr($nonce) . '">';
echo '<p><label><strong>Export name</strong><br>';
echo '<input type="text" name="export_name" value="' . esc_attr($default_name) . '" style="width: 420px; max-width: 100%;">';
echo '</label></p>';
echo '<p><label><input type="checkbox" name="exclude_deleted" value="1" checked> Exclude variables marked as deleted</label></p>';
submit_button('Download Design System JSON', 'primary');
echo '</form>';
echo '<hr/>';
// BACKUP NOW (download current state)
echo '<h2>Download Backup (recommended before import)</h2>';
echo '<p>This downloads your current Variables + Classes as a file named <code>Backup_{ExportName}_YYYYMMDD-HHMMSS.json</code>. No backups are stored in the database.</p>';
echo '<form method="post" action="' . esc_url(admin_url('admin-post.php')) . '">';
echo '<input type="hidden" name="action" value="' . esc_attr(self::ACTION_BACKUP) . '">';
echo '<input type="hidden" name="_wpnonce" value="' . esc_attr($nonce) . '">';
echo '<p><label><strong>Export name</strong><br>';
echo '<input type="text" name="export_name" value="' . esc_attr($default_name) . '" style="width: 420px; max-width: 100%;">';
echo '</label></p>';
echo '<p><label><input type="checkbox" name="exclude_deleted" value="1" checked> Exclude variables marked as deleted</label></p>';
submit_button('Download Backup Now', 'secondary');
echo '</form>';
echo '<hr/>';
// IMPORT
echo '<h2>Import (Variables + Classes)</h2>';
echo '<p>Upload a JSON export from another site. This writes into the <strong>active Elementor Kit</strong> on this site.</p>';
echo '<form method="post" action="' . esc_url(admin_url('admin-post.php')) . '" enctype="multipart/form-data">';
echo '<input type="hidden" name="action" value="' . esc_attr(self::ACTION_IMPORT) . '">';
echo '<input type="hidden" name="_wpnonce" value="' . esc_attr($nonce) . '">';
echo '<p><input type="file" name="wsq_ds_file" accept="application/json" required></p>';
echo '<p><label><input type="checkbox" name="merge_mode" value="1"> Merge with existing (otherwise overwrite)</label></p>';
echo '<p style="margin-top:12px;"><strong>After import:</strong> go to <code>Elementor → Editor → Tools</code> and click <strong>Regenerate CSS & Data</strong>.</p>';
submit_button('Import Design System JSON', 'primary');
echo '</form>';
echo '</div>';
}
public function handle_export() {
$this->require_admin_and_nonce();
$kit_id = $this->get_active_kit_id();
if ($kit_id <= 0) wp_die('Active Elementor Kit not found.');
$export_name = $this->sanitize_export_name($_POST['export_name'] ?? '');
$exclude_deleted = !empty($_POST['exclude_deleted']);
$payload = $this->build_payload($kit_id, $export_name, $exclude_deleted);
$filename = $this->filename_slug($export_name) . '-' . gmdate('Ymd-His') . '.json';
$this->download_json($payload, $filename);
}
public function handle_backup() {
$this->require_admin_and_nonce();
$kit_id = $this->get_active_kit_id();
if ($kit_id <= 0) wp_die('Active Elementor Kit not found.');
$export_name = $this->sanitize_export_name($_POST['export_name'] ?? '');
$exclude_deleted = !empty($_POST['exclude_deleted']);
$payload = $this->build_payload($kit_id, $export_name, $exclude_deleted);
$filename = 'Backup_' . $this->filename_slug($export_name) . '_' . gmdate('Ymd-His') . '.json';
$this->download_json($payload, $filename);
}
public function handle_import() {
$this->require_admin_and_nonce();
$kit_id = $this->get_active_kit_id();
if ($kit_id <= 0) $this->redirect_fail('Active Elementor Kit not found.');
if (empty($_FILES['wsq_ds_file']['tmp_name'])) $this->redirect_fail('No JSON file was uploaded.');
// Basic file validations
$size = (int) ($_FILES['wsq_ds_file']['size'] ?? 0);
if ($size <= 0 || $size > self::MAX_UPLOAD_BYTES) {
$this->redirect_fail('The uploaded file is empty or too large.');
}
$raw = file_get_contents($_FILES['wsq_ds_file']['tmp_name']);
if (!$raw) $this->redirect_fail('The uploaded JSON file could not be read.');
$payload = json_decode($raw, true);
if (!is_array($payload)) $this->redirect_fail('The uploaded file is not valid JSON.');
// Validate format
$format = $payload['meta']['format'] ?? '';
if ($format !== self::FORMAT_ID) {
// Still allow older v1 payloads if you used the earlier snippet
$old = $payload['meta']['format'] ?? '';
if ($old !== 'wsq_el_v4_design_system_v1') {
$this->redirect_fail('This JSON file is not a supported export format.');
}
}
if (empty($payload['data']) || !is_array($payload['data'])) {
$this->redirect_fail('The JSON file does not contain importable design system data.');
}
$incoming_vars_raw = $payload['data']['_elementor_global_variables'] ?? null;
$incoming_classes_raw = $payload['data']['_elementor_global_classes'] ?? null;
// Both should be arrays (Elementor stores as array or JSON string; we standardize to arrays)
$incoming_vars = $this->sanitize_variables_payload($this->maybe_decode_json($incoming_vars_raw));
$incoming_classes = $this->sanitize_classes_payload($this->maybe_decode_json($incoming_classes_raw));
if (!is_array($incoming_vars) || !is_array($incoming_classes)) {
$this->redirect_fail('The JSON file contains invalid Variables or Classes data.');
}
$merge_mode = !empty($_POST['merge_mode']);
if ($merge_mode) {
$current_vars = $this->sanitize_variables_payload($this->maybe_decode_json(get_post_meta($kit_id, '_elementor_global_variables', true)));
$current_classes = $this->sanitize_classes_payload($this->maybe_decode_json(get_post_meta($kit_id, '_elementor_global_classes', true)));
$merged_vars = $this->merge_variables(is_array($current_vars) ? $current_vars : [], $incoming_vars);
$merged_classes = $this->merge_classes(is_array($current_classes) ? $current_classes : [], $incoming_classes);
update_post_meta($kit_id, '_elementor_global_variables', $merged_vars);
update_post_meta($kit_id, '_elementor_global_classes', $merged_classes);
} else {
update_post_meta($kit_id, '_elementor_global_variables', $incoming_vars);
update_post_meta($kit_id, '_elementor_global_classes', $incoming_classes);
}
$this->clear_elementor_cache_best_effort();
wp_safe_redirect(add_query_arg([
'page' => 'wsq-el-v4-design-system',
'wsq_import' => 'ok',
], admin_url('tools.php')));
exit;
}
private function require_admin_and_nonce() {
if (!current_user_can(self::CAP)) wp_die('Insufficient permissions.');
check_admin_referer(self::NONCE_ACTION);
}
private function redirect_fail(string $message = '') {
$args = [
'page' => 'wsq-el-v4-design-system',
'wsq_import' => 'fail',
];
if ($message !== '') {
$args['wsq_msg'] = rawurlencode($message);
}
wp_safe_redirect(add_query_arg($args, admin_url('tools.php')));
exit;
}
private function build_payload(int $kit_id, string $export_name, bool $exclude_deleted): array {
$vars_raw = get_post_meta($kit_id, '_elementor_global_variables', true);
$class_raw = get_post_meta($kit_id, '_elementor_global_classes', true);
$vars = $this->sanitize_variables_payload($this->maybe_decode_json($vars_raw));
$classes = $this->sanitize_classes_payload($this->maybe_decode_json($class_raw));
if ($exclude_deleted && is_array($vars)) {
$vars = $this->strip_deleted_variables($vars);
}
return [
'meta' => [
'exported_at_utc' => gmdate('c'),
'site_url' => home_url(),
'kit_id' => $kit_id,
'export_name' => $export_name,
'format' => self::FORMAT_ID,
],
'data' => [
'_elementor_global_variables' => $vars,
'_elementor_global_classes' => $classes,
],
];
}
private function download_json(array $payload, string $filename) {
$json = wp_json_encode($payload, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
if (!$json) wp_die('Failed to encode JSON.');
nocache_headers();
header('Content-Type: application/json; charset=utf-8');
header('Content-Disposition: attachment; filename="' . $filename . '"');
echo $json;
exit;
}
private function maybe_decode_json($value) {
if (is_array($value)) return $value;
if (!is_string($value) || $value === '') return $value;
$trim = ltrim($value);
if ($trim === '' || ($trim[0] !== '{' && $trim[0] !== '[')) return $value;
$decoded = json_decode($value, true);
return (json_last_error() === JSON_ERROR_NONE) ? $decoded : $value;
}
private function strip_deleted_variables(array $vars): array {
if (!isset($vars['data']) || !is_array($vars['data'])) return $vars;
foreach ($vars['data'] as $id => $obj) {
if (is_array($obj) && !empty($obj['deleted_at'])) {
unset($vars['data'][$id]);
}
}
return $vars;
}
private function sanitize_variables_payload($vars) {
if (!is_array($vars)) {
return [
'data' => [],
'watermark' => 0,
'version' => 0,
];
}
$sanitized = $vars;
$data = $vars['data'] ?? [];
if (!is_array($data)) {
$data = [];
}
$clean_data = [];
foreach ($data as $id => $item) {
$clean_id = is_string($id) || is_int($id) ? (string) $id : '';
if ($clean_id === '' || !is_array($item)) {
continue;
}
$clean_data[$clean_id] = $this->sanitize_deep_array($item, ['watermark', 'version']);
}
$sanitized['data'] = $clean_data;
$sanitized['watermark'] = $this->sanitize_int_like($vars['watermark'] ?? 0, 0);
$sanitized['version'] = $this->sanitize_int_like($vars['version'] ?? 0, 0);
return $sanitized;
}
private function sanitize_classes_payload($classes) {
if (!is_array($classes)) {
return [
'items' => [],
'order' => [],
'version' => 0,
];
}
$sanitized = $classes;
$items = $classes['items'] ?? [];
if (!is_array($items)) {
$items = [];
}
$clean_items = [];
foreach ($items as $id => $item) {
$clean_id = is_string($id) || is_int($id) ? (string) $id : '';
if ($clean_id === '' || !is_array($item)) {
continue;
}
$clean_items[$clean_id] = $this->sanitize_deep_array($item, ['watermark', 'version']);
}
$order = $classes['order'] ?? [];
if (!is_array($order)) {
$order = [];
}
$clean_order = [];
foreach ($order as $id) {
$id = is_string($id) || is_int($id) ? (string) $id : '';
if ($id !== '' && isset($clean_items[$id]) && !in_array($id, $clean_order, true)) {
$clean_order[] = $id;
}
}
foreach (array_keys($clean_items) as $id) {
if (!in_array($id, $clean_order, true)) {
$clean_order[] = $id;
}
}
$sanitized['items'] = $clean_items;
$sanitized['order'] = $clean_order;
$sanitized['version'] = $this->sanitize_int_like($classes['version'] ?? 0, 0);
return $sanitized;
}
private function sanitize_deep_array($value, array $int_keys = []) {
if (!is_array($value)) {
return $value;
}
$clean = [];
foreach ($value as $key => $item) {
$clean_key = is_string($key) || is_int($key) ? $key : '';
if ($clean_key === '') {
continue;
}
if (in_array((string) $clean_key, $int_keys, true)) {
$clean[$clean_key] = $this->sanitize_int_like($item, 0);
continue;
}
$clean[$clean_key] = is_array($item)
? $this->sanitize_deep_array($item, $int_keys)
: $item;
}
return $clean;
}
private function sanitize_int_like($value, int $fallback = 0): int {
if ($value === null || $value === '') {
return $fallback;
}
if (is_int($value)) {
return $value;
}
if (is_float($value)) {
return (int) $value;
}
if (is_string($value)) {
$value = trim($value);
if ($value === '') {
return $fallback;
}
if (preg_match('/^-?\d+$/', $value)) {
return (int) $value;
}
}
if (is_numeric($value)) {
return (int) $value;
}
return $fallback;
}
private function merge_variables(array $current, array $incoming): array {
$current = $this->sanitize_variables_payload($current);
$incoming = $this->sanitize_variables_payload($incoming);
$current_data = (isset($current['data']) && is_array($current['data'])) ? $current['data'] : [];
$incoming_data = (isset($incoming['data']) && is_array($incoming['data'])) ? $incoming['data'] : [];
// Incoming wins by ID, but preserve the full root structure Elementor expects.
$merged = $current;
foreach ($incoming as $key => $value) {
if ($key === 'data') {
continue;
}
$merged[$key] = $value;
}
$merged['data'] = array_merge($current_data, $incoming_data);
$merged['watermark'] = $this->sanitize_int_like($merged['watermark'] ?? ($current['watermark'] ?? 0), 0);
$merged['version'] = $this->sanitize_int_like($merged['version'] ?? ($current['version'] ?? 0), 0);
return $merged;
}
private function merge_classes(array $current, array $incoming): array {
$current = $this->sanitize_classes_payload($current);
$incoming = $this->sanitize_classes_payload($incoming);
$current_items = (isset($current['items']) && is_array($current['items'])) ? $current['items'] : [];
$incoming_items = (isset($incoming['items']) && is_array($incoming['items'])) ? $incoming['items'] : [];
$merged_items = array_merge($current_items, $incoming_items);
$current_order = (isset($current['order']) && is_array($current['order'])) ? $current['order'] : [];
$incoming_order = (isset($incoming['order']) && is_array($incoming['order'])) ? $incoming['order'] : [];
$merged = $current;
foreach ($incoming as $key => $value) {
if ($key === 'items' || $key === 'order') {
continue;
}
$merged[$key] = $value;
}
$merged_order = array_values(array_unique(array_merge($current_order, $incoming_order)));
// Ensure every item key is present in order
foreach (array_keys($merged_items) as $id) {
if (!in_array($id, $merged_order, true)) {
$merged_order[] = $id;
}
}
$merged['items'] = $merged_items;
$merged['order'] = $merged_order;
$merged['version'] = $this->sanitize_int_like($merged['version'] ?? ($current['version'] ?? 0), 0);
return $merged;
}
private function clear_elementor_cache_best_effort() {
// Best-effort: clears Elementor caches; UI may still require “Regenerate CSS & Data”
if (class_exists('\Elementor\Plugin')) {
try {
$plugin = \Elementor\Plugin::$instance;
if (isset($plugin->files_manager) && method_exists($plugin->files_manager, 'clear_cache')) {
$plugin->files_manager->clear_cache();
}
if (isset($plugin->cache_manager) && method_exists($plugin->cache_manager, 'clear_cache')) {
$plugin->cache_manager->clear_cache();
}
} catch (\Throwable $e) {
// Silent: best effort only
}
}
if (function_exists('wp_cache_flush')) {
wp_cache_flush();
}
}
}
new WSQ_Elementor_V4_Design_System_Portable();
}
接下来简要介绍一下工具的使用方法。
首先你需要先在Elementor编辑器中创建好V4的变量和类别集。

然后在wordpress网站后台打开【工具-Elementor V4 Export】。导入操作就点【Download Design System JSON】上面的文件名可以随便写。点下载会得到一个json文件。
在你的新项目网站中,也安装上面的代码并启用。然后在wordpress网站后台打开【工具-Elementor V4 Export】,使用最下面的Import (Variables + Classes),点【选择文件】,选择之前下载好的json文件,然后点【Import Design System JSON】按钮。

接下来在后台打开【Elementor-工具】,如上图所示,清除一下缓存,同步一下模板库,然后保存。

最后你可以重新打开或刷新Elementor编辑界面,添加一个V4的原子化元素,在样式设置中,任意选中字体大小或尺寸等就可以看到导出之后的变量了。
本文分享的工具建议先在测试环境下使用哦,如果没有使用Elementor V4模块,也别用。后续Elementor官方应该是会补上这个功能的,这个工具也只是作为一个过渡而已。
© Copyright 2024. 悦然网络工作室/悦然wordpress建站 专注中小企业wordpress建站 All Rights Reserved.网站地图
本站图片来源为Pexels、Pixabay、Freepik、Unsplash等图片库的免费许可,CC0协议;还有部分为自己手绘,版权碰瓷请自重!法律服务:law@yueranseo.com 蜀ICP备20016391号-1 川公网安备 51011502000367号