| 1 |
<?php |
| 2 |
/** |
| 3 |
* Plugin Name: WDesignKit - AI Templates, Widget Builder & MCP Workflow for WordPress |
| 4 |
* Plugin URI: https://wdesignkit.com/ |
| 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.5 |
| 7 |
* Author: POSIMYTH |
| 8 |
* Author URI: https://posimyth.com/ |
| 9 |
* Text Domain: wdesignkit |
| 10 |
* Domain Path: /languages |
| 11 |
* Requires PHP: 7.4 |
| 12 |
* License: GPLv3 |
| 13 |
* License URI: https://opensource.org/licenses/GPL-3.0 |
| 14 |
* |
| 15 |
* @package wdesignkit |
| 16 |
*/ |
| 17 |
|
| 18 |
/** If this file is called directly, abort. */ |
| 19 |
if ( ! defined( 'ABSPATH' ) ) { |
| 20 |
exit; |
| 21 |
} |
| 22 |
|
| 23 |
if ( version_compare( PHP_VERSION, '7.4', '<' ) ) { |
| 24 |
add_action( |
| 25 |
'admin_notices', |
| 26 |
function () { |
| 27 |
echo '<div class="notice notice-error"><p>' . |
| 28 |
sprintf( |
| 29 |
/* translators: %s: minimum required PHP version */ |
| 30 |
esc_html__( 'WDesignKit requires PHP %s or higher. Please update PHP to use this plugin.', 'wdesignkit' ), |
| 31 |
'7.4' |
| 32 |
) . |
| 33 |
'</p></div>'; |
| 34 |
} |
| 35 |
); |
| 36 |
return; |
| 37 |
} |
| 38 |
|
| 39 |
define( 'WDKIT_VERSION', '2.6.5' ); |
| 40 |
define( 'WDKIT_FILE', __FILE__ ); |
| 41 |
define( 'WDKIT_PATH', plugin_dir_path( __FILE__ ) ); |
| 42 |
define( 'WDKIT_PBNAME', plugin_basename( __FILE__ ) ); |
| 43 |
define( 'WDKIT_BDNAME', basename( dirname( __FILE__ )) ); |
| 44 |
define( 'WDKIT_URL', plugins_url( '/', __FILE__ ) ); |
| 45 |
define( 'WDKIT_HOSTURL', site_url() ); |
| 46 |
define( 'WDKIT_INCLUDES', WDKIT_PATH . '/includes/' ); |
| 47 |
define( 'WDKIT_ASSETS', WDKIT_URL . 'assets/' ); |
| 48 |
define( 'WDKIT_TEXT_DOMAIN', 'wdesignkit' ); |
| 49 |
define( 'WDKIT_SERVER_SITE_URL', 'https://wdesignkit.com/' ); |
| 50 |
define( 'WDKIT_SERVER_API_URL', 'https://api.wdesignkit.com/' ); |
| 51 |
define( 'WDKIT_DOCUMENT', 'https://learn.wdesignkit.com/docs/' ); |
| 52 |
|
| 53 |
/** Widget Builder path*/ |
| 54 |
define( 'WDKIT_SERVER_PATH', wp_upload_dir()['baseurl'] . '/wdesignkit' ); |
| 55 |
define( 'WDKIT_BUILDER_PATH', wp_upload_dir()['basedir'] . '/wdesignkit' ); |
| 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 |
} |
| 401 |
|
| 402 |
require WDKIT_PATH . 'includes/class-wdkit-wdesignkit.php'; |