| @@ -1,10 +1,10 @@ | ||
| 1 | 1 | <?php |
| 2 | 2 | /** |
| 3 | - * Plugin Name: WDesignKit - Elementor & Gutenberg Starter Templates, Patterns, Cloud Workspace & Widget Builder | |
| 3 | + * Plugin Name: WDesignKit - AI Templates, Widget Builder & MCP Workflow | |
| 4 | 4 | * Plugin URI: https://wdesignkit.com/ |
| 5 | - * Description: Your All-in-One solution for effortless WordPress website creation and collaboration. With over 1,000+ Elementor and WordPress website templates, a library of 100+ pre-made widgets for Elementor, Gutenberg Blocks, and Bricks, along with a cloud workspace for collaboration and more. | |
| 6 | - * Version: 2.6.2 | |
| 5 | + * Description: 3000+ Elementor & Gutenberg Templates, AI Templates, AI Widget Builder, AI Code Snippets, MCP Workflow, Cloud Workspace & 220+ Widgets Library. | |
| 6 | + * Version: 2.6.6 | |
| 7 | 7 | * Author: POSIMYTH |
| 8 | 8 | * Author URI: https://posimyth.com/ |
| 9 | 9 | * Text Domain: wdesignkit |
| 10 | 10 | * Domain Path: /languages |
| @@ -35,9 +35,9 @@ | ||
| 35 | 35 | ); |
| 36 | 36 | return; |
| 37 | 37 | } |
| 38 | 38 | |
| 39 | -define( 'WDKIT_VERSION', '2.6.2' ); | |
| 39 | +define( 'WDKIT_VERSION', '2.6.6' ); | |
| 40 | 40 | define( 'WDKIT_FILE', __FILE__ ); |
| 41 | 41 | define( 'WDKIT_PATH', plugin_dir_path( __FILE__ ) ); |
| 42 | 42 | define( 'WDKIT_PBNAME', plugin_basename( __FILE__ ) ); |
| 43 | 43 | define( 'WDKIT_BDNAME', basename( dirname( __FILE__ )) ); |
| @@ -53,6 +53,350 @@ | ||
| 53 | 53 | /** Widget Builder path*/ |
| 54 | 54 | define( 'WDKIT_SERVER_PATH', wp_upload_dir()['baseurl'] . '/wdesignkit' ); |
| 55 | 55 | define( 'WDKIT_BUILDER_PATH', wp_upload_dir()['basedir'] . '/wdesignkit' ); |
| 56 | 56 | define( 'WDKIT_GET_SITE_URL', get_site_url() ); |
| 57 | + | |
| 58 | +/* | |
| 59 | + * POSIMYTH Analytics SDK. | |
| 60 | + * | |
| 61 | + * Every POSIMYTH plugin bundles its own copy of the shared classes and registers it here rather than | |
| 62 | + * requiring them directly. The loader collects every registered copy and, at plugins_loaded priority | |
| 63 | + * 0 — before any consumer, which run at priority 10 — loads the files from the NEWEST one, as | |
| 64 | + * declared by that copy's version.php. Requiring them directly instead would let load order decide, | |
| 65 | + * and an older sibling would silently define the shared classes for the whole suite. | |
| 66 | + * | |
| 67 | + * Keep the copy in sync with .dev/sync-posimyth-sdk.py in Nexter Extension — never hand-edit | |
| 68 | + * anything under includes/posimyth-sdk/ except this product's own class-posimyth-tracker-wdk.php, | |
| 69 | + * which the sync script does not touch. | |
| 70 | + */ | |
| 71 | +require_once WDKIT_PATH . 'includes/posimyth-sdk/posimyth-sdk-loader.php'; | |
| 72 | +posimyth_sdk_register( WDKIT_PATH . 'includes/posimyth-sdk' ); | |
| 73 | + | |
| 74 | +/** | |
| 75 | + * Whether this install has been rebranded. | |
| 76 | + * | |
| 77 | + * Standalone rather than a method on the survey config class, because the tracker needs the same | |
| 78 | + * answer on front-end and cron requests, and that class carries eight inline reason icons that have | |
| 79 | + * no business being compiled outside the Plugins screen. | |
| 80 | + * | |
| 81 | + * Only the five rebranding keys count. Plain UI preferences stored in the same option must not | |
| 82 | + * suppress the tracker — that was the lesson from The Plus Addons, where they did. | |
| 83 | + * | |
| 84 | + * @since 2.6.4 | |
| 85 | + * | |
| 86 | + * @return bool | |
| 87 | + */ | |
| 88 | +function wdkit_posimyth_is_white_labelled() { | |
| 89 | + $label = get_option( 'wkit_white_label', array() ); | |
| 90 | + | |
| 91 | + if ( ! is_array( $label ) ) { | |
| 92 | + return false; | |
| 93 | + } | |
| 94 | + | |
| 95 | + foreach ( array( 'plugin_name', 'plugin_desc', 'plugin_logo', 'developer_name', 'website_url' ) as $key ) { | |
| 96 | + if ( ! empty( $label[ $key ] ) && is_scalar( $label[ $key ] ) && '' !== trim( (string) $label[ $key ] ) ) { | |
| 97 | + return true; | |
| 98 | + } | |
| 99 | + } | |
| 100 | + | |
| 101 | + return false; | |
| 102 | +} | |
| 103 | + | |
| 104 | +add_action( | |
| 105 | + 'plugins_loaded', | |
| 106 | + function () { | |
| 107 | + /* | |
| 108 | + * A rebranded install no longer bails here. | |
| 109 | + * | |
| 110 | + * It used to: the tracker, the consent notice and the posimyth_consent_wdk AJAX handler were | |
| 111 | + * all skipped, which meant the Settings panel's Data Sharing card had no handler to save to | |
| 112 | + * and had to be hidden entirely. Sharing now follows the white-label CRITERIA instead of the | |
| 113 | + * mere fact of rebranding — the feature stays available and consent-gated as everywhere else, | |
| 114 | + * while every user-visible string uses the reseller's own plugin name (see $wl_name below) and | |
| 115 | + * the POSIMYTH docs link is dropped wherever help_link is set. | |
| 116 | + * | |
| 117 | + * Consent still governs collection: on a rebranded site, as on any other, nothing is sent | |
| 118 | + * until someone turns the switch on. | |
| 119 | + */ | |
| 120 | + $wl_label = get_option( 'wkit_white_label', array() ); | |
| 121 | + $wl_label = is_array( $wl_label ) ? $wl_label : array(); | |
| 122 | + $wl_name = ! empty( $wl_label['plugin_name'] ) && is_scalar( $wl_label['plugin_name'] ) ? trim( (string) $wl_label['plugin_name'] ) : ''; | |
| 123 | + $wl_name = '' !== $wl_name ? $wl_name : 'WDesignKit'; | |
| 124 | + // help_link is the reseller's "hide POSIMYTH documentation links" switch — honoured here the | |
| 125 | + // same way the editor stylesheets honour it. | |
| 126 | + $wl_hide_docs = ! empty( $wl_label['help_link'] ); | |
| 127 | + // "Hide all Plugin Updates related News?" — the reseller's switch for plugin-authored admin | |
| 128 | + // notices. The consent bar is one, so it is not registered at all when this is on. The tracker | |
| 129 | + // and the Settings panel's Data Sharing card are unaffected: consent can still be given there, | |
| 130 | + // it is simply never asked for unprompted on a rebranded dashboard. | |
| 131 | + $wl_hide_notice = ! empty( $wl_label['plugin_news'] ); | |
| 132 | + | |
| 133 | + // Shared base already loaded by the SDK loader at priority 0; the subclass is ours alone. | |
| 134 | + require_once WDKIT_PATH . 'includes/posimyth-sdk/class-posimyth-tracker-wdk.php'; | |
| 135 | + | |
| 136 | + if ( class_exists( 'Posimyth_Tracker_WDK' ) ) { | |
| 137 | + /* | |
| 138 | + * Registers activate / deactivate / weekly-heartbeat hooks and the cron, all consent-gated, | |
| 139 | + * plus the template-import counter. NOT inside the is_admin() gate below: the weekly | |
| 140 | + * heartbeat fires from wp-cron.php, which is not an admin request. | |
| 141 | + */ | |
| 142 | + Posimyth_Tracker_WDK::init(); | |
| 143 | + } | |
| 144 | + | |
| 145 | + if ( ! is_admin() ) { | |
| 146 | + return; | |
| 147 | + } | |
| 148 | + | |
| 149 | + /* | |
| 150 | + * Guarded on class_exists rather than assumed: the loader requires the three shared files as a | |
| 151 | + * set, but a sibling plugin requiring one of them directly, or shipping an older SDK revision, | |
| 152 | + * can leave these classes undefined. An unguarded `new` would fatal on every admin page load. | |
| 153 | + */ | |
| 154 | + // Also guarded on Posimyth_Tracker_WDK: this block reads its OPT_IN_OPTION constant and | |
| 155 | + // passes send_first_ping as a callback below. class-posimyth-tracker-wdk.php is required | |
| 156 | + // unconditionally above, but declaring the class can itself fail if a sibling POSIMYTH | |
| 157 | + // plugin's newer SDK copy won the loader with a diverged Posimyth_Tracker_Base signature — | |
| 158 | + // the exact multi-plugin case posimyth_sdk_register() exists for. Without this guard, that | |
| 159 | + // leaves Posimyth_Tracker_WDK undefined and the ::OPT_IN_OPTION reference below fatals every | |
| 160 | + // wp-admin request (Consent_Notice is only constructed when is_admin()), locking the admin | |
| 161 | + // out of the dashboard with no way to deactivate via the UI. | |
| 162 | + if ( class_exists( 'Posimyth_Consent_Notice' ) && class_exists( 'Posimyth_Tracker_WDK' ) ) { | |
| 163 | + /* | |
| 164 | + * WDesignKit's OWN consent key and OWN suite — not Nexter's. | |
| 165 | + * | |
| 166 | + * Nexter Extension and Nexter Blocks share one answer because they are one brand with one | |
| 167 | + * dashboard. WDesignKit is a separate product on its own site with its own dashboard, so it | |
| 168 | + * asks separately and stores separately. A site running both sees two notices, one per | |
| 169 | + * product — that is the intent, not a bug: consenting to share Nexter data is not consenting | |
| 170 | + * to share WDesignKit data. | |
| 171 | + * | |
| 172 | + * The constructor registers its own hooks; nothing else needs the instance. | |
| 173 | + */ | |
| 174 | + $wdkit_consent_notice = new Posimyth_Consent_Notice( | |
| 175 | + array( | |
| 176 | + // The reseller's own product name on a rebranded install, 'WDesignKit' otherwise. | |
| 177 | + 'plugin_name' => $wl_name, | |
| 178 | + 'plugin_slug' => 'wdesignkit', | |
| 179 | + 'opt_in_option' => Posimyth_Tracker_WDK::OPT_IN_OPTION, | |
| 180 | + 'ajax_action' => 'posimyth_consent_wdk', | |
| 181 | + 'installed_option' => 'posimyth_wdk_first_use_at', | |
| 182 | + 'tracker_cb' => array( 'Posimyth_Tracker_WDK', 'send_first_ping' ), | |
| 183 | + // The SDK's suite_name default is 'Nexter', and it is what the notice prints instead | |
| 184 | + // of plugin_name once more than one product registers. WDesignKit is its own suite of | |
| 185 | + // one, so its suite name is simply its own name. | |
| 186 | + 'suite_name' => $wl_name, | |
| 187 | + 'suite_key' => 'wdk_suite', | |
| 188 | + // WDesignKit's own docs, not nexterwp.com. UTM matches the shape the SDK uses for its | |
| 189 | + // own default, so this notice is distinguishable from other places the docs are linked. | |
| 190 | + 'docs_url' => WDKIT_DOCUMENT . 'data-sharing/?utm_source=wpbackend&utm_medium=admin&utm_campaign=datasharingnotice', | |
| 191 | + // Legacy hook only, for host stylesheets. The SDK stylesheet keys off `posi-*`. | |
| 192 | + 'css_prefix' => 'wdkit', | |
| 193 | + // Passed explicitly. One copy of the notice class serves every active POSIMYTH plugin, | |
| 194 | + // so a product that passes nothing is painted by whatever that copy defaults to. | |
| 195 | + // --wdkit_blk_shade, matching the deactivation dialog. The SDK feeds this into | |
| 196 | + // --posi-accent, so the icon, left border and both buttons follow from this one value. | |
| 197 | + 'accent' => '#020202', | |
| 198 | + ) | |
| 199 | + ); | |
| 200 | + | |
| 201 | + /* | |
| 202 | + * "Hide all Plugin Updates related News?" is on: keep the object, drop only the banner. | |
| 203 | + * | |
| 204 | + * The notice is constructed either way because its constructor is what registers | |
| 205 | + * wp_ajax_posimyth_consent_wdk — the handler the Settings panel's Data Sharing toggle saves | |
| 206 | + * through. Skipping construction removed the banner AND broke that toggle on exactly this | |
| 207 | + * configuration. Unhooking render() suppresses the banner while leaving the handler live, so | |
| 208 | + * consent is never asked for unprompted but can still be given from Settings. | |
| 209 | + */ | |
| 210 | + if ( $wl_hide_notice ) { | |
| 211 | + remove_action( 'admin_notices', array( $wdkit_consent_notice, 'render' ) ); | |
| 212 | + } | |
| 213 | + } | |
| 214 | + | |
| 215 | + /* | |
| 216 | + * Reseller has "hide documentation links" on: drop the notice's "See what's shared" anchor. | |
| 217 | + * | |
| 218 | + * Done in CSS rather than by passing an empty docs_url, because the SDK's render() prints the | |
| 219 | + * anchor unconditionally and would emit href="" — and includes/posimyth-sdk/ is sync-managed, | |
| 220 | + * so the notice class itself must not be edited here. Scoped to THIS product's notice, so a | |
| 221 | + * sibling POSIMYTH plugin's notice on the same screen keeps its own link. | |
| 222 | + * | |
| 223 | + * Hooked on the same handle the SDK attaches its own inline CSS to, at a later priority so | |
| 224 | + * this rule always follows and wins on equal specificity. | |
| 225 | + */ | |
| 226 | + if ( $wl_hide_docs ) { | |
| 227 | + add_action( | |
| 228 | + 'admin_enqueue_scripts', | |
| 229 | + function () { | |
| 230 | + wp_add_inline_style( 'wp-admin', '.posi-consent-notice.posi-consent--wdesignkit .posi-notice-text a { display: none; }' ); | |
| 231 | + }, | |
| 232 | + 20 | |
| 233 | + ); | |
| 234 | + } | |
| 235 | + | |
| 236 | + /* | |
| 237 | + * WDesignKit's skin for the shared deactivation dialog — design only. | |
| 238 | + * | |
| 239 | + * Enqueued from here, on the Plugins screen alone, because that is the only screen the dialog | |
| 240 | + * can open on. It overrides the SDK's base rules through `.posi-deact-p-wdesignkit`, the parent | |
| 241 | + * class that file documents for exactly this purpose, so includes/posimyth-sdk/ stays untouched | |
| 242 | + * and a sibling POSIMYTH product's dialog keeps its own look. | |
| 243 | + */ | |
| 244 | + add_action( | |
| 245 | + 'admin_enqueue_scripts', | |
| 246 | + function ( $hook ) { | |
| 247 | + if ( 'plugins.php' !== $hook ) { | |
| 248 | + return; | |
| 249 | + } | |
| 250 | + | |
| 251 | + $skin_rel = 'assets/css/dashborad/wdkit-deactivate-survey.css'; | |
| 252 | + $skin_abs = WDKIT_PATH . $skin_rel; | |
| 253 | + | |
| 254 | + /* | |
| 255 | + * Versioned by mtime, not WDKIT_VERSION. | |
| 256 | + * | |
| 257 | + * WDKIT_VERSION only moves on release, so every edit to this file inside one version | |
| 258 | + * ships under a URL the browser already has cached — the stale copy keeps being served | |
| 259 | + * and the change looks like it did not apply. Falls back to the plugin version if the | |
| 260 | + * file is unreadable. | |
| 261 | + */ | |
| 262 | + $skin_ver = file_exists( $skin_abs ) ? (string) filemtime( $skin_abs ) : WDKIT_VERSION; | |
| 263 | + | |
| 264 | + wp_enqueue_style( | |
| 265 | + 'wdkit-deactivate-survey', | |
| 266 | + WDKIT_URL . $skin_rel, | |
| 267 | + array(), | |
| 268 | + $skin_ver | |
| 269 | + ); | |
| 270 | + | |
| 271 | + /* | |
| 272 | + * Adds the dialog's close button. Injected rather than printed because the markup is | |
| 273 | + * sync-managed; see the file header. Versioned by mtime for the same reason as the | |
| 274 | + * stylesheet above. | |
| 275 | + */ | |
| 276 | + $close_rel = 'assets/js/admin/wdkit-deactivate-survey.js'; | |
| 277 | + $close_abs = WDKIT_PATH . $close_rel; | |
| 278 | + $close_ver = file_exists( $close_abs ) ? (string) filemtime( $close_abs ) : WDKIT_VERSION; | |
| 279 | + | |
| 280 | + wp_enqueue_script( | |
| 281 | + 'wdkit-deactivate-survey', | |
| 282 | + WDKIT_URL . $close_rel, | |
| 283 | + array(), | |
| 284 | + $close_ver, | |
| 285 | + true | |
| 286 | + ); | |
| 287 | + | |
| 288 | + wp_localize_script( | |
| 289 | + 'wdkit-deactivate-survey', | |
| 290 | + 'wdkitDeactSurvey', | |
| 291 | + array( | |
| 292 | + 'close_label' => __( 'Close', 'wdesignkit' ), | |
| 293 | + ) | |
| 294 | + ); | |
| 295 | + } | |
| 296 | + ); | |
| 297 | + | |
| 298 | + if ( ! class_exists( 'Posimyth_Deactivation_Survey' ) ) { | |
| 299 | + return; | |
| 300 | + } | |
| 301 | + | |
| 302 | + /* | |
| 303 | + * Required lazily, inside the is_admin() gate: the config carries eight inline reason icons | |
| 304 | + * that have no business being compiled on a front-end request. | |
| 305 | + */ | |
| 306 | + require_once WDKIT_INCLUDES . 'admin/notices/class-wdkit-deactivate-survey.php'; | |
| 307 | + | |
| 308 | + new Posimyth_Deactivation_Survey( Wdkit_Deactivate_Survey::args() ); | |
| 309 | + } | |
| 310 | +); | |
| 311 | + | |
| 312 | +/** | |
| 313 | + * Developer tool: re-arm the data-sharing consent notice. | |
| 314 | + * | |
| 315 | + * The notice is deliberately hard to see twice — quiet for 2 days after install, snoozed 30 days by | |
| 316 | + * "Dismiss", silenced for good by "Allow", and never rendered while sharing is already on. That is | |
| 317 | + * right for users and leaves no way to review the bar again, so this resets those four gates. | |
| 318 | + * | |
| 319 | + * Three conditions, all required: | |
| 320 | + * | |
| 321 | + * - WP_DEBUG. This never loads on a production site, so it cannot be reached on a real install | |
| 322 | + * however the URL is guessed. | |
| 323 | + * - The same capability the notice itself answers for — network admin on multisite, since the | |
| 324 | + * consent is one answer per install. | |
| 325 | + * - A valid nonce. The reset writes site options, and a bare GET would let a crafted link flip | |
| 326 | + * another admin's consent state from anywhere on the web. | |
| 327 | + * | |
| 328 | + * Use the "Reset Data Sharing Notice" item added to the admin bar, which carries the nonce. There is | |
| 329 | + * deliberately no hand-typeable URL: that was the earlier QA shortcut this replaces. | |
| 330 | + * | |
| 331 | + * @since 2.6.4 | |
| 332 | + */ | |
| 333 | +if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) { | |
| 334 | + | |
| 335 | + add_action( | |
| 336 | + 'admin_bar_menu', | |
| 337 | + function ( $bar ) { | |
| 338 | + $cap = is_multisite() ? 'manage_network_options' : 'manage_options'; | |
| 339 | + | |
| 340 | + if ( ! current_user_can( $cap ) ) { | |
| 341 | + return; | |
| 342 | + } | |
| 343 | + | |
| 344 | + $bar->add_node( | |
| 345 | + array( | |
| 346 | + 'id' => 'wdkit-reset-consent', | |
| 347 | + 'title' => __( 'Reset Data Sharing Notice', 'wdesignkit' ), | |
| 348 | + 'href' => wp_nonce_url( admin_url( 'index.php?wdkit_reset_consent=1' ), 'wdkit_reset_consent' ), | |
| 349 | + 'parent' => 'top-secondary', | |
| 350 | + ) | |
| 351 | + ); | |
| 352 | + }, | |
| 353 | + 100 | |
| 354 | + ); | |
| 355 | + | |
| 356 | + add_action( | |
| 357 | + 'admin_init', | |
| 358 | + function () { | |
| 359 | + if ( empty( $_GET['wdkit_reset_consent'] ) ) { | |
| 360 | + return; | |
| 361 | + } | |
| 362 | + | |
| 363 | + $cap = is_multisite() ? 'manage_network_options' : 'manage_options'; | |
| 364 | + | |
| 365 | + if ( ! current_user_can( $cap ) ) { | |
| 366 | + return; | |
| 367 | + } | |
| 368 | + | |
| 369 | + check_admin_referer( 'wdkit_reset_consent' ); | |
| 370 | + | |
| 371 | + // Site options, matching how the SDK stores them: one consent per install, not per blog. | |
| 372 | + delete_site_option( 'posi_consent_dismissed_wdk_suite' ); | |
| 373 | + delete_site_option( 'posi_consent_snoozed_until_wdk_suite' ); | |
| 374 | + delete_site_option( 'posi_consent_grace_start_wdk_suite' ); | |
| 375 | + | |
| 376 | + // Sharing has to be off for the bar to render at all — the notice never asks for | |
| 377 | + // permission that has already been granted. | |
| 378 | + if ( class_exists( '\Posimyth_Tracker_WDK' ) ) { | |
| 379 | + update_site_option( \Posimyth_Tracker_WDK::OPT_IN_OPTION, 0 ); | |
| 380 | + } | |
| 381 | + | |
| 382 | + /* | |
| 383 | + * grace_period_ends() re-stamps the start it just found missing, so deleting that option is | |
| 384 | + * not enough on its own — the window has to be zeroed for THIS request too. admin_init runs | |
| 385 | + * before admin_notices, so the filter is in place before the notice decides. | |
| 386 | + */ | |
| 387 | + add_filter( 'posimyth_consent_notice_grace_seconds', '__return_zero' ); | |
| 388 | + | |
| 389 | + add_action( | |
| 390 | + 'admin_notices', | |
| 391 | + function () { | |
| 392 | + echo '<div class="notice notice-success is-dismissible"><p>' . | |
| 393 | + esc_html__( 'Data-sharing consent reset. The notice should appear below.', 'wdesignkit' ) . | |
| 394 | + '</p></div>'; | |
| 395 | + }, | |
| 396 | + 5 | |
| 397 | + ); | |
| 398 | + } | |
| 399 | + ); | |
| 400 | +} | |
| 57 | 401 | |
| 58 | 402 | require WDKIT_PATH . 'includes/class-wdkit-wdesignkit.php'; |