PluginProbe
WDesignKit – AI Templates, Widget Builder & MCP Workflow / 2.7.0
WDesignKit – AI Templates, Widget Builder & MCP Workflow v2.7.0
2.7.1 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 All 130 releases
← All changes | includes/abilities/class-wdk-ability-main.php +87 -0 2.6.4 → 2.7.0 View file →
@@ -530,8 +530,95 @@
530 530 delete_transient( 'wdkit_registered_widgets_' . $widget_type );
531 531 }
532 532 }
533 533
534 +if ( ! function_exists( 'wdesignkit_widget_registry_option_prefix' ) ) {
535 + /**
536 + * Shared prefix of every versioned widget-registry cache option.
537 + *
538 + * One constant-ish source of truth for the three places that need to match these rows by
539 + * pattern rather than by exact name: the orphan sweep below, and uninstall.php. Keep it in
540 + * step with wdesignkit_widget_registry_cache_key(), which builds the full name.
541 + *
542 + * @since 2.6.5
543 + *
544 + * @return string
545 + */
546 + function wdesignkit_widget_registry_option_prefix() {
547 + return 'wdkit_widget_registry_';
548 + }
549 +}
550 +
551 +if ( ! function_exists( 'wdesignkit_purge_stale_widget_registries' ) ) {
552 + /**
553 + * Deletes widget-registry cache options left behind by OTHER plugin versions.
554 + *
555 + * wdesignkit_widget_registry_cache_key() embeds WDKIT_VERSION in the option name, which is
556 + * deliberate — it is what makes an update or a rollback orphan the old entry so the registry
557 + * rebuilds itself instead of trusting a stale cache (ClickUp 86d41cd1z). What was missing is
558 + * the other half: nothing ever deleted the orphan. There was no cleanup path anywhere in the
559 + * codebase, so every release left one row per builder in wp_options permanently. Observed on
560 + * a site upgraded twice — twelve rows across three versions, the largest 12 KB:
561 + *
562 + * wdkit_widget_registry_elementor_2_6_3 wdkit_widget_registry_gutenberg_2_6_3
563 + * wdkit_widget_registry_elementor_2_6_4 wdkit_widget_registry_gutenberg_2_6_4 …
564 + *
565 + * These are written with autoload = false, so there is no per-request cost and this is
566 + * housekeeping rather than a performance fix — but it grows without bound, and a row nothing
567 + * will ever read again is exactly what an uninstall is expected to leave clean.
568 + *
569 + * Matches by prefix and keeps only the CURRENT version's keys, so it also collects rows from
570 + * a build whose version this code cannot know about (a rollback, or a downgrade). The LIKE
571 + * pattern is escaped with $wpdb->esc_like(); the option names are plugin-generated and
572 + * contain no wildcards today, but the escape is what keeps that true if the prefix changes.
573 + *
574 + * @since 2.6.5
575 + *
576 + * @return int Number of orphaned options deleted.
577 + */
578 + function wdesignkit_purge_stale_widget_registries() {
579 + global $wpdb;
580 +
581 + $prefix = wdesignkit_widget_registry_option_prefix();
582 + $pattern = $wpdb->esc_like( $prefix ) . '%';
583 +
584 + $names = $wpdb->get_col( // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- option names are only discoverable by pattern; no caching API covers a LIKE sweep.
585 + $wpdb->prepare( "SELECT option_name FROM {$wpdb->options} WHERE option_name LIKE %s", $pattern )
586 + );
587 +
588 + if ( empty( $names ) ) {
589 + return 0;
590 + }
591 +
592 + // Build the set of names that are still live, rather than parsing the version out of each
593 + // row: the builder slug can itself contain underscores (gutenberg_core), so splitting on
594 + // '_' to find the version suffix is ambiguous. Comparing against what the current version
595 + // WOULD be named has no such ambiguity.
596 + $keep = array();
597 + foreach ( array( 'elementor', 'gutenberg', 'gutenberg_core', 'bricks' ) as $builder ) {
598 + $key = wdesignkit_widget_registry_cache_key( $builder );
599 + if ( '' !== $key ) {
600 + $keep[ $key ] = true;
601 + }
602 + }
603 +
604 + $deleted = 0;
605 + foreach ( $names as $name ) {
606 + if ( isset( $keep[ $name ] ) ) {
607 + continue;
608 + }
609 +
610 + // delete_option() rather than a bulk DELETE: it clears the option cache and fires the
611 + // documented hooks, which a raw query would silently skip.
612 + if ( delete_option( $name ) ) {
613 + ++$deleted;
614 + }
615 + }
616 +
617 + return $deleted;
618 + }
619 +}
620 +
534 621 if ( ! function_exists( 'wdesignkit_widget_folder_name' ) ) {
535 622 /**
536 623 * Canonical widget folder name: "<Title-With-Hyphens>_<widget_id>".
537 624 *