PluginProbe
WDesignKit – AI Templates, Widget Builder & MCP Workflow / 2.7.0
WDesignKit – AI Templates, Widget Builder & MCP Workflow v2.7.0
2.7.0 2.6.6 2.6.5 2.6.4 2.6.3 2.6.2 2.6.1 2.6.0 2.5.5 2.5.4 2.5.3 2.5.2 2.5.1 2.5.0 2.4.0 2.3.3 2.3.2 2.3.1 1.0.10 1.0.11 1.0.12 1.0.13 1.0.14 1.0.15 1.0.16 All 129 releases
← All changes | includes/admin/class-wdkit-enqueue.php +214 -37 2.3.2 → 2.7.0 View file →
@@ -83,9 +83,21 @@
83 83 *
84 84 * @since 1.0.0
85 85 * @return void
86 86 */
87 - public function wdkit_enqueue_styles_library() {
87 + public function wdkit_enqueue_styles_library( $hook = '' ) {
88 + // Hooked on admin_enqueue_scripts with no screen check at all, so this loaded the icon
89 + // font on every wp-admin screen (ClickUp 86d41cnze). admin_enqueue_scripts passes the
90 + // screen hook as its first argument, so the same guard wdkit_admin_scripts() uses can
91 + // apply here. Kept as a separate handle from 'wdkit-library-preview' — both point at the
92 + // same stylesheet, and deduplicating the handles is a separate change.
93 + $is_nexter_page = isset( $_GET['page'] ) && sanitize_key( wp_unslash( $_GET['page'] ) ) === 'nxt_code_snippets';
94 + $is_theme_builder_page = ( isset( $_GET['post_type'] ) && sanitize_key( wp_unslash( $_GET['post_type'] ) ) === 'nxt_builder' ) || ( isset( $_GET['page'] ) && sanitize_key( wp_unslash( $_GET['page'] ) ) === 'nxt_builder' );
95 +
96 + if ( ! in_array( $hook, array( 'toplevel_page_wdesign-kit', 'elementor', 'post-new.php', 'post.php' ), true ) && ! $is_nexter_page && ! $is_theme_builder_page ) {
97 + return;
98 + }
99 +
88 100 wp_enqueue_style( 'wdkit-library', WDKIT_URL . 'assets/fonts/style.css', array(), WDKIT_VERSION, false );
89 101 }
90 102
91 103 /**
@@ -124,11 +136,11 @@
124 136 global $current_screen;
125 137
126 138 $editor = 'wdkit';
127 139
128 - $action = ! empty( $_GET['action'] ) ? $_GET['action'] : '';
140 + $action = ! empty( $_GET['action'] ) ? sanitize_key( wp_unslash( $_GET['action'] ) ) : '';
129 141
130 - if ( $current_screen->is_block_editor() ) {
142 + if ( $current_screen && $current_screen->is_block_editor() ) {
131 143
132 144 if ( array_key_exists( 'action', $_GET ) && isset( $action ) ) {
133 145 if ( 'elementor' === $action ) {
134 146 $editor = 'elementor';
@@ -173,8 +185,9 @@
173 185 public function wdkit_bricks_editor_style() {
174 186 // Only load in Bricks editor
175 187 if ( function_exists( 'bricks_is_builder' ) && bricks_is_builder() ) {
176 188 wp_enqueue_style( 'wdkit-bricks-editor-css', WDKIT_URL . 'assets/css/bricks/wdkit_enqueue_editor_styles.css', array(), WDKIT_VERSION );
189 + // Cross-domain copy/paste for Bricks is marked "Coming Soon" — do not enqueue yet.
177 190
178 191 // Hide WDesignKit logo icon when white label is enabled
179 192 $white_label = get_option( 'wkit_white_label', false );
180 193 if ( ! empty( $white_label['help_link'] ) ) {
@@ -187,8 +200,9 @@
187 200 * Gutenberg Editor Panel Style Loaded
188 201 */
189 202 public function wdkit_gutenberg_editor_style() {
190 203 wp_enqueue_style( 'wdkit-gutenberg-editor-css', WDKIT_URL . 'assets/css/gutenberg/wdkit_enqueue_editor_styles.css', array(), WDKIT_VERSION );
204 + $this->wdkit_cross_copy_paste_script( 'gutenberg' );
191 205
192 206 // Hide WDesignKit logo icon + Need Help panel when white label is enabled
193 207 $white_label = get_option( 'wkit_white_label', false );
194 208 if ( ! empty( $white_label['help_link'] ) ) {
@@ -213,23 +227,36 @@
213 227 * @param string $hook use for check page type.
214 228 */
215 229 public function wdkit_admin_scripts( $hook ) {
216 230
217 - wp_enqueue_style( 'wdkit-library-preview', WDKIT_URL . 'assets/fonts/style.css', array(), WDKIT_VERSION, false );
231 + // Deliberately BEFORE the screen guard below: this 1.4 KB stylesheet contains nothing but
232 + // #adminmenu rules for the WDesignKit menu item, and the admin menu is rendered on every
233 + // admin screen. Gating it to WDesignKit's own screens leaves the menu icon unstyled
234 + // everywhere else — the masked-SVG ::before never applies, so the raw <img> shows through.
235 + // Do not "optimise" this into the guard (ClickUp 86d41cnze).
218 236 wp_enqueue_style( 'wdkit-out-dashborad', WDKIT_URL . 'assets/css/dashborad/wdkit-dashborad.css', array(), WDKIT_VERSION, false );
219 237
238 + $page = isset( $_GET['page'] ) ? sanitize_key( wp_unslash( $_GET['page'] ) ) : '';
239 + $ptype = isset( $_GET['post_type'] ) ? sanitize_key( wp_unslash( $_GET['post_type'] ) ) : '';
240 +
220 241 // Check if we're on a Nexter Extension page
221 - $is_nexter_page = isset( $_GET['page'] ) && $_GET['page'] === 'nxt_code_snippets';
242 + $is_nexter_page = isset( $_GET['page'] ) && sanitize_key( wp_unslash( $_GET['page'] ) ) === 'nxt_code_snippets';
222 243
223 244 // Check if we're on a Theme Builder page (via post_type or page parameter)
224 - $is_theme_builder_page = ( isset( $_GET['post_type'] ) && $_GET['post_type'] === 'nxt_builder' ) || ( isset( $_GET['page'] ) && $_GET['page'] === 'nxt_builder' );
225 -
245 + $is_theme_builder_page = ( isset( $_GET['post_type'] ) && sanitize_key( wp_unslash( $_GET['post_type'] ) ) === 'nxt_builder' ) || ( isset( $_GET['page'] ) && sanitize_key( wp_unslash( $_GET['page'] ) ) === 'nxt_builder' );
246 +
226 247 if ( ! in_array( $hook, array( 'toplevel_page_wdesign-kit', 'elementor', 'post-new.php', 'post.php' ), true ) && !$is_nexter_page && !$is_theme_builder_page ) {
227 248 return;
228 249 }
229 250
230 - wp_enqueue_media();
251 + // Moved BELOW the screen guard: this is the 9 KB WDesignKit icon font, used only by
252 + // WDesignKit's own UI (no #adminmenu rules in it), yet it was enqueued on every wp-admin
253 + // screen — dashboard, posts list, media library, plugins page (ClickUp 86d41cnze).
254 + // The admin-menu stylesheet is NOT gated here; see the note at the top of this method.
255 + wp_enqueue_style( 'wdkit-library-preview', WDKIT_URL . 'assets/fonts/style.css', array(), WDKIT_VERSION, false );
231 256
257 + wp_enqueue_media();
258 +
232 259 $this->wdkit_enqueue_scripts( $hook );
233 260 $this->wdkit_enqueue_styles();
234 261 }
235 262
@@ -239,8 +266,16 @@
239 266 * @since 1.0.0
240 267 */
241 268 public function wdkit_enqueue_styles() {
242 269 wp_enqueue_style( 'wdkit-editor-css', WDKIT_URL . 'build/index.css', array(), WDKIT_VERSION );
270 +
271 + /**
272 + * The build emits a right-to-left stylesheet (build/index-rtl.css) because the
273 + * source CSS uses physical left/right properties. WordPress does not auto-load
274 + * the -rtl variant; registering it here makes core swap in index-rtl.css on RTL
275 + * locales (Arabic, Hebrew, Farsi, Urdu) so the admin layout mirrors correctly.
276 + */
277 + wp_style_add_data( 'wdkit-editor-css', 'rtl', 'replace' );
243 278 }
244 279
245 280 /**
246 281 * Register the JavaScript for the admin area.
@@ -248,9 +283,32 @@
248 283 * @param string $hook give builder name.
249 284 * @since 1.0.0
250 285 */
251 286 public function wdkit_enqueue_scripts( $hook ) {
252 - wp_enqueue_script( 'wdkit-editor-js', WDKIT_URL . 'build/index.js', array( 'wp-i18n', 'wp-element', 'wp-components' ), WDKIT_VERSION, true );
287 + $asset_file = WDKIT_PATH . 'build/index.min.asset.php';
288 + $asset = file_exists( $asset_file ) ? require $asset_file : array( 'dependencies' => array( 'wp-i18n', 'wp-element', 'wp-components' ), 'version' => WDKIT_VERSION );
289 +
290 + /**
291 + * JS translations catalog.
292 + *
293 + * The app ships as a large minified bundle (build/index.min.js) which
294 + * `wp i18n make-pot` skips (all *.min.js are skipped) and could not parse
295 + * within WordPress.org's budget anyway. build/wdk-i18n-strings.js is a
296 + * small, readable catalog of every translatable JS string (generated from
297 + * src/ by bin/generate-i18n-strings.js). WordPress.org extracts strings
298 + * from it and builds the per-locale JSON keyed to this handle; loading it
299 + * here populates the shared wp.i18n store so the whole React app is
300 + * translated. It is a dependency of the app bundle so it (and its inline
301 + * translation data) load first.
302 + */
303 + $script_deps = $asset['dependencies'];
304 + if ( file_exists( WDKIT_PATH . 'build/wdk-i18n-strings.js' ) ) {
305 + wp_enqueue_script( 'wdkit-editor-i18n', WDKIT_URL . 'build/wdk-i18n-strings.js', array( 'wp-i18n' ), $asset['version'], array( 'in_footer' => true, 'strategy' => 'defer' ) );
306 + wp_set_script_translations( 'wdkit-editor-i18n', 'wdesignkit' );
307 + $script_deps = array_merge( $script_deps, array( 'wdkit-editor-i18n' ) );
308 + }
309 +
310 + wp_enqueue_script( 'wdkit-editor-js', WDKIT_URL . 'build/index.min.js', $script_deps, $asset['version'], array( 'in_footer' => true, 'strategy' => 'defer' ) );
253 311 wp_set_script_translations( 'wdkit-editor-js', 'wdesignkit' );
254 312
255 313 $onbording_end = get_option( $this->wdkit_onbording_end );
256 314 $white_label = get_option( 'wkit_white_label', false );
@@ -259,46 +317,165 @@
259 317 wp_localize_script(
260 318 'wdkit-editor-js',
261 319 'wdkitData',
262 320 array(
263 - 'ajax_url' => admin_url( 'admin-ajax.php' ),
264 - 'WDKIT_PATH' => WDKIT_PATH,
265 - 'WDKIT_URL' => WDKIT_URL,
266 - 'WDKIT_ASSETS' => WDKIT_ASSETS,
267 - 'wdkit_server_url' => WDKIT_SERVER_SITE_URL,
268 - 'wdkit_site_api_url' => WDKIT_SERVER_API_URL,
269 - 'wdkit_wp_version' => get_bloginfo( 'version' ),
270 - 'home_url' => esc_url( home_url( '/' ) ),
271 - 'kit_nonce' => wp_create_nonce( 'wdkit_nonce' ),
272 - 'post_id' => get_the_ID(),
273 - 'post_type' => get_post_type(),
274 - 'text_domain' => WDKIT_TEXT_DOMAIN,
275 - 'use_editor' => $this->wdkit_use_editor(),
276 - 'post_type_list' => $this->wdkit_get_post_type_list(),
277 - 'WDKIT_onbording_end' => $onbording_end,
278 - 'wdkit_white_label' => $white_label,
279 - 'WDKIT_dark_mode' => $dark_mode,
280 - /** Widget Builder Path */
281 - 'WDKIT_SITE_URL' => WDKIT_GET_SITE_URL,
282 - 'WDKIT_DOC_URL' => WDKIT_DOCUMENT,
283 - 'WDKIT_SERVER_PATH' => WDKIT_SERVER_PATH,
284 - 'WDKIT_BUILDER_PATH' => WDKIT_BUILDER_PATH,
285 - 'WDKIT_VERSION' => WDKIT_VERSION,
321 + 'ajax_url' => admin_url( 'admin-ajax.php' ),
322 + // Mirrors the PHP side's WP_DEBUG gate on its own import timing/diagnostic
323 + // error_log() calls, so the JS import flow's console diagnostics follow the
324 + // same convention instead of always printing in every visitor's console.
325 + 'debug' => (bool) ( defined( 'WP_DEBUG' ) && WP_DEBUG ),
326 + 'WDKIT_URL' => WDKIT_URL,
327 + 'WDKIT_ASSETS' => WDKIT_ASSETS,
328 + 'wdkit_server_url' => WDKIT_SERVER_SITE_URL,
329 + 'wdkit_site_api_url' => WDKIT_SERVER_API_URL,
330 + 'wdkit_wp_version' => get_bloginfo( 'version' ),
331 + 'home_url' => esc_url( home_url( '/' ) ),
332 + 'kit_nonce' => wp_create_nonce( 'wdkit_nonce' ),
286 333
287 - 'gutenberg_template' => Wdkit_Wdesignkit::wdkit_is_compatible( 'gutenberg_template', 'template' )
334 + /* Kit Import engine switch. 'yes' => the wizard drives the PHP runner in four
335 + * stage calls; anything else => it falls back to its original ~25-call
336 + * orchestration, which is still fully present. Flip with the
337 + * `wdkit_use_php_runner` filter.
338 + *
339 + * Deliberately 'yes'/'no' rather than a boolean. wp_localize_script() casts
340 + * booleans to "1" and "", and while "" is falsy in JS, relying on that is the
341 + * same PHP/JS truthiness trap that bites elsewhere in the importer — a switch
342 + * that silently failed to switch OFF would be the worst outcome for a
343 + * rollback path. An explicit string compares the same in both languages.
344 + *
345 + * Fully qualified: this file is namespaced, and an unqualified reference here
346 + * resolved to wdkit\WdKit_enqueue\Wdkit_Import_Wizard and fatalled. */
347 + 'use_php_runner' => ( class_exists( '\\Wdkit_Import_Wizard' ) && \Wdkit_Import_Wizard::is_enabled() ) ? 'yes' : 'no',
348 + 'post_id' => get_the_ID(),
349 + 'post_type' => get_post_type(),
350 + 'text_domain' => WDKIT_TEXT_DOMAIN,
351 + 'use_editor' => $this->wdkit_use_editor(),
352 + 'post_type_list' => $this->wdkit_get_post_type_list(),
353 + 'WDKIT_onbording_end' => $onbording_end,
354 + 'wdkit_white_label' => $white_label,
355 + 'WDKIT_dark_mode' => $dark_mode,
356 + /** Widget Builder — public URL only, no server filesystem paths */
357 + 'WDKIT_SITE_URL' => WDKIT_GET_SITE_URL,
358 + 'WDKIT_DOC_URL' => WDKIT_DOCUMENT,
359 + 'WDKIT_SERVER_PATH' => WDKIT_SERVER_PATH,
360 + 'WDKIT_VERSION' => WDKIT_VERSION,
361 +
362 + 'gutenberg_template' => Wdkit_Wdesignkit::wdkit_is_compatible( 'gutenberg_template', 'template' ),
363 +
364 + /**
365 + * Data Sharing switcher, Settings panel.
366 + *
367 + * Read as a SITE option — the consent is one answer per install, not per blog. The
368 + * class guard matches the one in wdesignkit.php: on a white-labelled install, or when
369 + * a sibling POSIMYTH plugin's SDK copy won the loader, the tracker class is never
370 + * declared and the constant reference would fatal.
371 + *
372 + * Both references are root-namespaced. This file lives in wdkit\WdKit_enqueue while
373 + * the SDK class is declared in the global namespace: a string class name is always
374 + * global so the guard passed either way, but an unprefixed `Posimyth_Tracker_WDK::`
375 + * resolves against THIS namespace and fatals on every admin page load.
376 + */
377 + 'wdkit_data_sharing' => class_exists( '\Posimyth_Tracker_WDK' ) ? (bool) get_site_option( \Posimyth_Tracker_WDK::OPT_IN_OPTION, false ) : false,
378 + 'wdkit_consent_nonce' => wp_create_nonce( 'posimyth_consent_wdk' ),
379 +
380 + /**
381 + * Whether the Data Sharing card may be shown at all.
382 + *
383 + * Tracks the tracker class rather than the white-label flag: a rebranded install now
384 + * keeps the feature (see wdesignkit.php), so this is false only when the SDK genuinely
385 + * failed to load — a sibling POSIMYTH plugin winning the loader with a diverged copy.
386 + * Rendering a switch in that case would offer a save with no handler behind it.
387 + *
388 + * Separate from wdkit_data_sharing on purpose: that one is false both when sharing is
389 + * off and when the feature is absent, which cannot tell the two apart.
390 + */
391 + 'wdkit_data_sharing_available' => class_exists( '\Posimyth_Tracker_WDK' ),
392 +
393 + /**
394 + * Reseller's product name, for the Data Sharing copy that would otherwise say
395 + * "WDesignKit" on a plugin they have rebranded as their own.
396 + */
397 + 'wdkit_data_sharing_name' => ! empty( $white_label['plugin_name'] ) ? $white_label['plugin_name'] : 'WDesignKit',
398 +
399 + /** help_link is the reseller's "hide POSIMYTH documentation links" switch. */
400 + 'wdkit_data_sharing_docs' => empty( $white_label['help_link'] ) ? WDKIT_DOCUMENT . 'data-sharing/' : ''
288 401 )
289 402 );
290 403
291 404 /**Ace Editor files for Widget-builder */
292 405 if ( 'toplevel_page_wdesign-kit' === $hook && Wdkit_Wdesignkit::wdkit_is_compatible( 'builder', 'widget' ) ) {
293 - wp_enqueue_script( 'widgetBuilder-script-editor-js', WDKIT_URL . 'assets/js/extra/ace.min.js', array( 'wp-element' ), WDKIT_VERSION, true );
294 - wp_enqueue_script( 'widgetBuilder-script-editor-cobalt', WDKIT_URL . 'assets/js/extra/theme-cobalt.js', array( 'wp-element' ), WDKIT_VERSION, true );
295 - wp_enqueue_script( 'widgetBuilder-script-editor-html', WDKIT_URL . 'assets/js/extra//mode-html.js', array( 'wp-element' ), WDKIT_VERSION, true );
406 + wp_enqueue_script( 'widgetBuilder-script-editor-js', WDKIT_URL . 'assets/js/extra/ace.min.js', array( 'wp-element' ), WDKIT_VERSION, array( 'in_footer' => true, 'strategy' => 'defer' ) );
407 + wp_enqueue_script( 'widgetBuilder-script-editor-cobalt', WDKIT_URL . 'assets/js/extra/theme-cobalt.js', array( 'wp-element' ), WDKIT_VERSION, array( 'in_footer' => true, 'strategy' => 'defer' ) );
408 + wp_enqueue_script( 'widgetBuilder-script-editor-html', WDKIT_URL . 'assets/js/extra/mode-html.js', array( 'wp-element' ), WDKIT_VERSION, array( 'in_footer' => true, 'strategy' => 'defer' ) );
296 409 }
297 410
298 411 if ( 'elementor' === $hook && Wdkit_Wdesignkit::wdkit_is_compatible( 'elementor_template', 'template' ) ) {
299 - wp_enqueue_script( 'wdkit-frontend-editor', WDKIT_ASSETS . '/js/main/elementor/elementor-editor.js', array( 'jquery', 'wp-i18n' ), WDKIT_VERSION, true );
412 + wp_enqueue_script( 'wdkit-frontend-editor', WDKIT_ASSETS . 'js/main/elementor/elementor-editor.js', array( 'jquery', 'wp-i18n' ), WDKIT_VERSION, array( 'in_footer' => true, 'strategy' => 'defer' ) );
413 + wp_set_script_translations( 'wdkit-frontend-editor', 'wdesignkit' );
414 + $this->wdkit_cross_copy_paste_script( 'elementor' );
300 415 }
416 + }
417 +
418 + /**
419 + * Enqueue cross-domain copy/paste support for active builders.
420 + *
421 + * @since 1.0.0
422 + */
423 + public function wdkit_cross_copy_paste_script( $builder = '' ) {
424 + $settings = get_option( 'wkit_settings_panel', array() );
425 + $enabled = array(
426 + 'elementor' => ! empty( $settings['cross_copy_paste_elementor'] ) || ! empty( $settings['cross_copy_paste'] ),
427 + 'gutenberg' => ! empty( $settings['cross_copy_paste_gutenberg'] ) || ! empty( $settings['cross_copy_paste'] ),
428 + // Bricks support is "Coming Soon" — force-disabled regardless of saved setting.
429 + 'bricks' => false,
430 + );
431 +
432 + if ( empty( array_filter( $enabled ) ) ) {
433 + return;
434 + }
435 +
436 + if ( ! empty( $builder ) && empty( $enabled[ $builder ] ) ) {
437 + return;
438 + }
439 +
440 + if ( wp_script_is( 'wdkit-cross-copy-paste', 'enqueued' ) ) {
441 + return;
442 + }
443 +
444 + $deps = array( 'wp-i18n' );
445 + // Gutenberg SlotFill needs these so the block toolbar's
446 + // "Options" menu can host our "WDesignKit Copy / Paste" items.
447 + if ( ! empty( $enabled['gutenberg'] ) ) {
448 + $deps[] = 'wp-plugins';
449 + $deps[] = 'wp-element';
450 + $deps[] = 'wp-components';
451 + $deps[] = 'wp-block-editor';
452 + $deps[] = 'wp-data';
453 + $deps[] = 'wp-blocks';
454 + $deps[] = 'wp-dom-ready';
455 + }
456 +
457 + wp_enqueue_script( 'wdkit-cross-copy-paste', WDKIT_ASSETS . 'js/main/wdkit-cross-copy-paste.js', $deps, WDKIT_VERSION, array( 'in_footer' => true, 'strategy' => 'defer' ) );
458 + wp_set_script_translations( 'wdkit-cross-copy-paste', 'wdesignkit' );
459 + wp_localize_script(
460 + 'wdkit-cross-copy-paste',
461 + 'wdkitCrossCopyPaste',
462 + array(
463 + 'enabled' => true,
464 + 'version' => WDKIT_VERSION,
465 + 'site' => esc_url( home_url( '/' ) ),
466 + 'builders' => $enabled,
467 + // Direct AJAX access — the editor pages don't always
468 + // load the dashboard wdkitData global. Needed for the
469 + // wdkit_cp_check_widgets endpoint.
470 + 'ajax_url' => admin_url( 'admin-ajax.php' ),
471 + // WDesignKit dashboard (hash-router) page. Missing widgets
472 + // are installed by loading its /create/widget/:w_unique
473 + // route inside a hidden iframe.
474 + 'dashboard_url' => admin_url( 'admin.php?page=wdesign-kit' ),
475 + 'kit_nonce' => wp_create_nonce( 'wdkit_nonce' ),
476 + )
477 + );
301 478 }
302 479
303 480 /**
304 481 * Add Menu Page WdKit.