PluginProbe
Post Grid Gutenberg Blocks – PostX / 5.1.0
Post Grid Gutenberg Blocks – PostX v5.1.0
5.1.1 5.1.0 5.0.41 5.0.39 5.0.38 5.0.37 5.0.36 5.0.35 5.0.34 5.0.33 5.0.32 5.0.31 5.0.30 5.0.29 5.0.28 5.0.27 5.0.26 5.0.25 5.0.23 5.0.24 5.0.22 5.0.21 5.0.20 5.0.19 5.0.18 All 240 releases
ultimate-post / includes / durbin / class-xpo.php

class-xpo.php in Post Grid Gutenberg Blocks – PostX 5.1.0, at includes/durbin/class-xpo.php

554 lines 16.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php // phpcs:ignore
2
3 namespace ULTP\Includes\Durbin;
4
5 defined( 'ABSPATH' ) || exit;
6
7 /**
8 * Core class for managing plugin actions and integrations.
9 */
10 class Xpo {
11
12 /**
13 * Gets license key
14 *
15 * PostX Pro answers through the `ultp_license_key` filter.
16 *
17 * @return string
18 */
19 public static function get_lc_key() {
20 if ( has_filter( 'ultp_license_key' ) ) {
21 $key = apply_filters( 'ultp_license_key', '' );
22 return is_string( $key ) ? $key : '';
23 }
24 if ( self::is_pro_before_1_9_0() ) {
25 return get_option( 'edd_ultp_license_key', '' );
26 }
27 return '';
28 }
29
30 /**
31 * Checks if the license is active.
32 *
33 * PostX Pro answers through the `ultp_license_active` filter.
34 *
35 * @return bool
36 */
37 public static function is_lc_active() {
38 if ( has_filter( 'ultp_license_active' ) ) {
39 return true === apply_filters( 'ultp_license_active', false );
40 }
41 if ( self::is_pro_before_1_9_0() ) {
42 $license_data = get_option( 'edd_ultp_license_data', array() );
43 return isset( $license_data['license'] ) && 'valid' === $license_data['license'];
44 }
45 return false;
46 }
47
48 /**
49 * Checks if PostX Pro is a version before 1.9.0.
50 *
51 * Those versions hook none of the filters PostX now asks PostX Pro through (the
52 * `ultp_license_*` ones, `ultp_template_request_body`, `ultp_seo_meta_excerpt`),
53 * so PostX still does that work itself for them.
54 *
55 * @return bool
56 */
57 public static function is_pro_before_1_9_0() {
58 return defined( 'ULTP_PRO_VER' ) && version_compare( ULTP_PRO_VER, '1.9.0', '<' );
59 }
60
61 /**
62 * Checks if the license has expired.
63 *
64 * PostX Pro answers through the `ultp_license_expired` filter.
65 *
66 * @return bool True if the license is expired, otherwise false.
67 */
68 public static function is_lc_expired() {
69 if ( has_filter( 'ultp_license_expired' ) ) {
70 return true === apply_filters( 'ultp_license_expired', false );
71 }
72 if ( self::is_pro_before_1_9_0() ) {
73 $license_data = get_option( 'edd_ultp_license_data', array() );
74 return isset( $license_data['license'] ) && 'expired' === $license_data['license'];
75 }
76 return false;
77 }
78
79 /**
80 * Get Option Value bypassing cache
81 * Inspired By WordPress Core get_option
82 *
83 * @since v.1.0.7
84 * @param string $option Option Name.
85 * @param boolean $default_value option default value.
86 * @return mixed
87 */
88 public static function get_option_without_cache( $option, $default_value = false ) {
89 global $wpdb;
90
91 if ( is_scalar( $option ) ) {
92 $option = trim( $option );
93 }
94
95 if ( empty( $option ) ) {
96 return false;
97 }
98
99 $value = $default_value;
100
101 $row = $wpdb->get_row( $wpdb->prepare( "SELECT option_value FROM $wpdb->options WHERE option_name = %s LIMIT 1", $option ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
102
103 if ( is_object( $row ) ) {
104 $value = $row->option_value;
105 } else {
106 return apply_filters( "ultp_default_option_{$option}", $default_value, $option );
107 }
108
109 return apply_filters( "ultp_option_{$option}", maybe_unserialize( $value ), $option );
110 }
111
112 /**
113 * Add option without adding to the cache
114 * Inspired By WordPress Core set_transient
115 *
116 * @since v.1.0.7
117 * @param string $option option name.
118 * @param string $value option value.
119 * @param string $autoload whether to load WordPress startup.
120 * @return bool
121 */
122 public static function add_option_without_cache( $option, $value = '', $autoload = 'yes' ) {
123 global $wpdb;
124
125 if ( is_scalar( $option ) ) {
126 $option = trim( $option );
127 }
128
129 if ( empty( $option ) ) {
130 return false;
131 }
132
133 wp_protect_special_option( $option );
134
135 if ( is_object( $value ) ) {
136 $value = clone $value;
137 }
138
139 $value = sanitize_option( $option, $value );
140
141 /*
142 * Make sure the option doesn't already exist.
143 */
144
145 if ( apply_filters( "ultp_default_option_{$option}", false, $option, false ) !== self::get_option_without_cache( $option ) ) {
146 return false;
147 }
148
149 $serialized_value = maybe_serialize( $value );
150 $autoload = ( 'no' === $autoload || false === $autoload ) ? 'no' : 'yes';
151
152 $result = $wpdb->query( $wpdb->prepare( "INSERT INTO `$wpdb->options` (`option_name`, `option_value`, `autoload`) VALUES (%s, %s, %s) ON DUPLICATE KEY UPDATE `option_name` = VALUES(`option_name`), `option_value` = VALUES(`option_value`), `autoload` = VALUES(`autoload`)", $option, $serialized_value, $autoload ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching
153 if ( ! $result ) {
154 return false;
155 }
156
157 return true;
158 }
159
160 /**
161 * Get Transient Value bypassing cache
162 * Inspired By WordPress Core get_transient
163 *
164 * @since v.1.0.7
165 * @param string $transient Transient Name.
166 * @return mixed
167 */
168 public static function get_transient_without_cache( $transient ) {
169 $transient_option = '_transient_' . $transient;
170 $transient_timeout = '_transient_timeout_' . $transient;
171 $timeout = self::get_option_without_cache( $transient_timeout );
172
173 if ( false !== $timeout && $timeout < time() ) {
174 delete_option( $transient_option );
175 delete_option( $transient_timeout );
176 $value = false;
177 }
178
179 if ( ! isset( $value ) ) {
180 $value = self::get_option_without_cache( $transient_option );
181 }
182
183 return apply_filters( "ultp_transient_{$transient}", $value, $transient );
184 }
185
186 /**
187 * Set transient without adding to the cache
188 * Inspired By WordPress Core set_transient
189 *
190 * @since v.1.0.7
191 * @param string $transient Transient Name.
192 * @param mixed $value Transient Value.
193 * @param integer $expiration Time until expiration in seconds.
194 * @return bool
195 */
196 public static function set_transient_without_cache( $transient, $value, $expiration = 0 ) {
197
198 $expiration = (int) $expiration;
199
200 $transient_timeout = '_transient_timeout_' . $transient;
201 $transient_option = '_transient_' . $transient;
202
203 $result = false;
204
205 if ( false === self::get_option_without_cache( $transient_option ) ) {
206 $autoload = 'yes';
207 if ( $expiration ) {
208 $autoload = 'no';
209 self::add_option_without_cache( $transient_timeout, time() + $expiration, 'no' );
210 }
211 $result = self::add_option_without_cache( $transient_option, $value, $autoload );
212 } else {
213 /*
214 * If expiration is requested, but the transient has no timeout option,
215 * delete, then re-create transient rather than update.
216 */
217 $update = true;
218
219 if ( $expiration ) {
220 if ( false === self::get_option_without_cache( $transient_timeout ) ) {
221 delete_option( $transient_option );
222 self::add_option_without_cache( $transient_timeout, time() + $expiration, 'no' );
223 $result = self::add_option_without_cache( $transient_option, $value, 'no' );
224 $update = false;
225 } else {
226 update_option( $transient_timeout, time() + $expiration );
227 }
228 }
229
230 if ( $update ) {
231 $result = update_option( $transient_option, $value );
232 }
233 }
234
235 return $result;
236 }
237
238 public static function generate_utm_link( $params = array() ) {
239 $default_config = array(
240 'example' => array(
241 'source' => 'db-postx-featurename',
242 'medium' => 'block-feature',
243 'campaign' => 'postx-dashboard',
244 ),
245 'summer_db' => array(
246 'source' => 'db-postx-notice',
247 'medium' => 'summer-sale',
248 'campaign' => 'postx-dashboard',
249 ),
250 'plugin_dir_pro' => array(
251 'source' => 'db-postx-plugin',
252 'medium' => 'upgrade-pro',
253 'campaign' => 'postx-dashboard',
254 ),
255 'post_type_page' => array(
256 'source' => 'db-postx-posttype',
257 'medium' => 'upgrade-pro',
258 'campaign' => 'postx-dashboard',
259 ),
260 'plugin_dir_support' => array(
261 'source' => 'db-postx-pluginmeta',
262 'medium' => 'meta-support',
263 'campaign' => 'postx-dashboard',
264 ),
265 'dashboard_go_pro' => array(
266 'source' => 'db-postx-submenu',
267 'medium' => 'left-menu-upgrade',
268 'campaign' => 'postx-dashboard',
269 ),
270 'sub_menu' => array(
271 'source' => 'db-postx-submenu',
272 'medium' => 'upgrade-pro',
273 'campaign' => 'postx-dashboard',
274 ),
275 'content_notice' => array(
276 'source' => 'db-postx-notice',
277 'medium' => 'spring-sale',
278 'campaign' => 'postx-dashboard',
279 ),
280 'summer_sale_meta' => array(
281 'source' => 'db-postx-plugin-meta',
282 'medium' => 'summer-sale',
283 'campaign' => 'postx-dashboard',
284 ),
285 'base_price_meta' => array(
286 'source' => 'db-postx-plugin-meta',
287 'medium' => 'base-price',
288 'campaign' => 'postx-dashboard',
289 ),
290
291 // Flash sale.
292 'flash_sale_content' => array(
293 'source' => 'db-postx-notice-content',
294 'medium' => 'summer-flash-sale',
295 'campaign' => 'postx-dashboard',
296 ),
297 'flash_sale' => array(
298 'source' => 'db-postx-notice',
299 'medium' => 'summer-flash-sale',
300 'campaign' => 'postx-dashboard',
301 ),
302 'flash_sale_meta' => array(
303 'source' => 'db-postx-plugin-meta',
304 'medium' => 'summer-flash-sale',
305 'campaign' => 'postx-dashboard',
306 ),
307 // Massive Sale
308 'massive_sale_content' => array(
309 'source' => 'db-postx-notice-content',
310 'medium' => 'summer-massive-sale',
311 'campaign' => 'postx-dashboard',
312 ),
313 'massive_sale' => array(
314 'source' => 'db-postx-notice',
315 'medium' => 'summer-massive-sale',
316 'campaign' => 'postx-dashboard',
317 ),
318 'massive_sale_meta' => array(
319 'source' => 'db-postx-plugin-meta',
320 'medium' => 'summer-massive-sale',
321 'campaign' => 'postx-dashboard',
322 ),
323 // Surprise Sale
324 'surprise_sale_content' => array(
325 'source' => 'db-postx-notice-content',
326 'medium' => 'summer-surprise-sale',
327 'campaign' => 'postx-dashboard',
328 ),
329 'surprise_sale' => array(
330 'source' => 'db-postx-notice',
331 'medium' => 'summer-surprise-sale',
332 'campaign' => 'postx-dashboard',
333 ),
334 'surprise_sale_meta' => array(
335 'source' => 'db-postx-plugin-meta',
336 'medium' => 'summer-surprise-sale',
337 'campaign' => 'postx-dashboard',
338 ),
339 // Final Hours Sale
340 'final_hours_content' => array(
341 'source' => 'db-postx-notice-content',
342 'medium' => 'summer-final-sale',
343 'campaign' => 'postx-dashboard',
344 ),
345 'final_hour' => array(
346 'source' => 'db-postx-notice',
347 'medium' => 'summer-final-sale',
348 'campaign' => 'postx-dashboard',
349 ),
350 'final_hour_meta' => array(
351 'source' => 'db-postx-plugin-meta',
352 'medium' => 'summer-final-sale',
353 'campaign' => 'postx-dashboard',
354 ),
355 );
356
357 // Step 1: Get parameters
358 $base_url = $params['url'] ?? 'https://www.wpxpo.com/postx/';
359 $utm_key = $params['utmKey'] ?? null;
360 $affiliate = $params['affiliate'] ?? apply_filters( 'ultp_affiliate_id', '' );
361 $hash = $params['hash'] ?? 'pricing';
362 $custom_config = $params['config'] ?? null;
363
364 $parsed_url = wp_parse_url( $base_url );
365 $scheme = $parsed_url['scheme'] ?? 'https';
366 $host = $parsed_url['host'] ?? '';
367 $path = $parsed_url['path'] ?? '';
368 $query = array();
369
370 // Step 3: Extract existing query params if present
371 if ( isset( $parsed_url['query'] ) ) {
372 parse_str( $parsed_url['query'], $query );
373 }
374
375 // Step 4: Determine config
376 $utm_config = $custom_config ?? ( $utm_key && isset( $default_config[ $utm_key ] ) ? $default_config[ $utm_key ] : array() );
377
378 // Step 5: Add UTM parameters
379 if ( ! empty( $utm_config ) ) {
380 $query = array_merge(
381 $query,
382 array(
383 'utm_source' => $utm_config['source'],
384 'utm_medium' => $utm_config['medium'],
385 'utm_campaign' => $utm_config['campaign'],
386 )
387 );
388 }
389
390 // Step 6: Add affiliate if present
391 if ( $affiliate ) {
392 $query['ref'] = $affiliate;
393 }
394
395 // Step 7: Reconstruct URL
396 $final_url = $scheme . '://' . $host . $path;
397
398 if ( ! empty( $query ) ) {
399 $final_url .= '?' . http_build_query( $query );
400 }
401
402 if ( $hash ) {
403 $final_url .= '#' . $hash;
404 }
405
406 return $final_url;
407 }
408
409
410 /**
411 * Get WOW Products Details
412 *
413 * @return array
414 */
415 public static function get_wow_products_details() {
416 return array(
417 'products' => array(
418 'wow_shipping' => file_exists( WP_PLUGIN_DIR . '/wow-table-rate-shipping/wow-table-rate-shipping.php' ),
419 'post_x' => file_exists( WP_PLUGIN_DIR . '/ultimate-post/ultimate-post.php' ),
420 'wow_store' => file_exists( WP_PLUGIN_DIR . '/product-blocks/product-blocks.php' ),
421 'wow_optin' => file_exists( WP_PLUGIN_DIR . '/optin/optin.php' ),
422 'wow_revenue' => file_exists( WP_PLUGIN_DIR . '/revenue/revenue.php' ),
423 'wholesale_x' => file_exists( WP_PLUGIN_DIR . '/wholesalex/wholesalex.php' ),
424 'wow_addon' => file_exists( WP_PLUGIN_DIR . '/product-addons/product-addons.php' ),
425 'wow_invoice' => file_exists( WP_PLUGIN_DIR . '/wow-pdf-invoices-packing-slips/wow-pdf-invoices-packing-slips.php' ),
426 'wow_recommend' => file_exists( WP_PLUGIN_DIR . '/wow-ai-product-recommendations/wow-ai-product-recommendations.php' ),
427 ),
428 'products_active' => array(
429 'wow_shipping' => defined( 'WTRS_VER' ),
430 'post_x' => defined( 'ULTP_VER' ),
431 'wow_store' => defined( 'WOPB_VER' ),
432 'wow_optin' => defined( 'OPTN_VERSION' ),
433 'wow_revenue' => defined( 'REVENUE_VER' ),
434 'wholesale_x' => defined( 'WHOLESALEX_VER' ),
435 'wow_addon' => defined( 'PRAD_VER' ),
436 'wow_invoice' => defined( 'WINV_VER' ),
437 'wow_recommend' => defined( 'PRECO_VER' ),
438 ),
439 );
440 }
441
442
443 /**
444 * Installs and activates a plugin by its name only.
445 *
446 * @param string $name The name or slug of the plugin to install and activate.
447 */
448 public static function install_and_active_plugin( $name ) {
449 $to_r = array( 'done' => true );
450 $plugin_slug = '';
451 switch ( $name ) {
452 case 'wow_shipping':
453 $plugin_slug = 'wow-table-rate-shipping';
454 break;
455 case 'post_x':
456 $plugin_slug = 'ultimate-post';
457 break;
458 case 'wow_store':
459 $plugin_slug = 'product-blocks';
460 break;
461 case 'wow_optin':
462 $plugin_slug = 'optin';
463 break;
464 case 'wow_revenue':
465 $plugin_slug = 'revenue';
466 break;
467 case 'wholesale_x':
468 $plugin_slug = 'wholesalex';
469 break;
470 case 'wow_addon':
471 $plugin_slug = 'product-addons';
472 break;
473 case 'woocommerce':
474 $plugin_slug = 'woocommerce';
475 break;
476 case 'wow_invoice':
477 $plugin_slug = 'wow-pdf-invoices-packing-slips';
478 $active_url = admin_url( 'admin.php?page=winv-dashboard#overview' );
479 break;
480 case 'wow_recommend':
481 $plugin_slug = 'wow-ai-product-recommendations';
482 break;
483 }
484
485 if ( ! file_exists( WP_PLUGIN_DIR . '/' . $plugin_slug . '/' . $plugin_slug . '.php' ) ) {
486 $to_r = self::plugin_install( $plugin_slug . '/' . $plugin_slug . '.php', $plugin_slug );
487 } else {
488 activate_plugin( $plugin_slug . '/' . $plugin_slug . '.php' );
489 }
490 return $to_r;
491 }
492
493 /**
494 * Installs a plugin based on the provided plugin file and slug.
495 *
496 * This function is expected to handle the logic required to install a plugin,
497 * such as downloading, unpacking, and activating the plugin using the provided
498 * plugin file and slug.
499 *
500 * @param string $plugin The plugin file path or identifier (e.g., 'plugin-directory/plugin-file.php').
501 * @param string $slug The plugin slug (typically the directory name of the plugin).
502 */
503 public static function plugin_install( $plugin, $slug ) {
504 include ABSPATH . 'wp-admin/includes/plugin-install.php';
505 include ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
506
507 if ( ! class_exists( 'Plugin_Upgrader' ) ) {
508 include ABSPATH . 'wp-admin/includes/class-plugin-upgrader.php';
509 }
510 if ( ! class_exists( 'WP_Ajax_Upgrader_Skin' ) ) {
511 include ABSPATH . 'wp-admin/includes/class-wp-ajax-upgrader-skin.php';
512 }
513
514 $api = plugins_api(
515 'plugin_information',
516 array(
517 'slug' => $slug,
518 'fields' => array(
519 'short_description' => false,
520 'sections' => false,
521 'requires' => false,
522 'rating' => false,
523 'ratings' => false,
524 'downloaded' => false,
525 'last_updated' => false,
526 'added' => false,
527 'tags' => false,
528 'compatibility' => false,
529 'homepage' => false,
530 'donate_link' => false,
531 ),
532 )
533 );
534
535 if ( is_wp_error( $api ) ) {
536 wp_die( esc_html( $api->get_error_message() ) );
537 }
538 $title = '';
539 $url = '';
540 $nonce = '';
541 $upgrader = new \Plugin_Upgrader( new \WP_Ajax_Upgrader_Skin( compact( 'title', 'url', 'nonce', 'plugin', 'api' ) ) );
542 $install_result = $upgrader->install( $api->download_link );
543
544 if ( ! is_wp_error( $install_result ) ) {
545 activate_plugin( $plugin );
546 return array(
547 'done' => false,
548 );
549 }
550
551 return array( 'done' => true );
552 }
553 }
554