PluginProbe
ShopBuilder – WooCommerce Builder For Elementor / 3.2.6
ShopBuilder – WooCommerce Builder For Elementor v3.2.6
3.4.2 3.4.1 3.4.0 2.0.1 2.0.2 2.0.3 2.1.0 2.1.1 2.1.10 2.1.11 2.1.12 2.1.13 2.1.14 2.1.15 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.1.9 2.2.0 2.2.1 2.2.2 All 63 releases
← All changes | app/Controllers/Hooks/ActionHooks.php +259 -24 2.1.133.2.6 View file →
@@ -7,12 +7,14 @@
7 7
8 8 namespace RadiusTheme\SB\Controllers\Hooks;
9 9
10 10 use RadiusTheme\SB\Helpers\Fns;
11 +use RadiusTheme\SB\Helpers\Cache;
11 12 use RadiusTheme\SB\Models\GeneralList;
12 13 use RadiusTheme\SB\Helpers\BuilderFns;
13 14 use RadiusTheme\SB\Models\TemplateSettings;
14 15 use RadiusTheme\SB\Elementor\Render\Render;
16 +use RadiusTheme\SB\Elementor\Helper\RenderHelpers;
15 17
16 18 defined( 'ABSPATH' ) || exit();
17 19
18 20 /**
@@ -24,8 +26,9 @@
24 26 *
25 27 * @return void
26 28 */
27 29 public static function init_hooks() {
30 + add_action( 'rtsb/before/save/options', [ __CLASS__, 'clear_cron_schedule' ], 10, 3 );
28 31 add_action( 'wp_head', [ __CLASS__, 'og_metatags_for_sharing' ], 1 );
29 32 add_action( 'woocommerce_share', [ __CLASS__, 'shopbuilder_share' ], 20 );
30 33 add_action( 'rtsb/wcqv/product/summary', [ __CLASS__, 'shopbuilder_share' ], 40 );
31 34 add_action( 'rtsb/shop/product/image', [ __CLASS__, 'render_image' ], 10, 2 );
@@ -60,9 +63,8 @@
60 63
61 64 /**
62 65 * Notices.
63 66 */
64 - // add_action( 'woocommerce_cart_is_empty', [ Fns::class, 'woocommerce_output_all_notices' ], 5 );
65 67 add_action( 'woocommerce_shortcode_before_product_cat_loop', [ Fns::class, 'woocommerce_output_all_notices' ], 10 );
66 68 add_action( 'woocommerce_before_shop_loop', [ Fns::class, 'woocommerce_output_all_notices' ], 10 );
67 69 add_action( 'woocommerce_before_single_product', [ Fns::class, 'woocommerce_output_all_notices' ], 10 );
68 70 add_action( 'woocommerce_before_cart', [ Fns::class, 'woocommerce_output_all_notices' ], 10 );
@@ -81,11 +83,58 @@
81 83 add_action( 'woocommerce_before_checkout_form', [ __CLASS__, 'woocommerce_checkout_coupon_form' ], 10 );
82 84 // My Account Order Page.
83 85 add_action( 'woocommerce_before_account_orders', [ __CLASS__, 'before_account_orders' ], 10 );
84 86 add_action( 'woocommerce_after_account_orders', [ __CLASS__, 'after_account_orders' ], 10 );
87 +
88 + // Product Filter Widget Hooks.
89 + add_action( 'rtsb/before/archive/default/filter/items', [ __CLASS__,'default_filter_header' ], 10 );
90 + add_action( 'rtsb/before/archive/default/filter/items', [ __CLASS__,'default_filter_search' ], 15 );
91 +
92 + // WC Query modifier. Always registered so the free `rtsb-product-filters`
93 + // widget's URL params (product_cat, product_tag, product_brand, rating_filter,
94 + // sale_filter) are applied to the main WooCommerce product query regardless
95 + // of whether the Pro add-on is active.
96 + add_action( 'woocommerce_product_query', [ __CLASS__, 'query_modifier' ], 15 );
97 +
98 + add_action( 'switch_theme', [ __CLASS__, 'clear_cache' ] );
85 99 }
100 + /**
101 + * Clear scheduled cron events when a module is deactivated.
102 + *
103 + * Checks the given block ID against predefined schedules and clears
104 + * related cron hooks if the corresponding module is turned off.
105 + *
106 + * @param string $section_id Section identifier (not used in this function).
107 + * @param string $block_id Module/block identifier to check scheduled hooks.
108 + * @param array $rawOptions Module options array containing 'active' status.
109 + *
110 + * @return void
111 + */
112 + public static function clear_cron_schedule( $section_id, $block_id, $rawOptions ) {
113 + $schedule = [
114 + 'abandoned_cart_recovery' => [
115 + 'rtsb_abandoned_cart_recovery_action',
116 + 'rtsb_send_abandoned_cart_emails',
117 + ],
118 + 'currency_switcher' => [
119 + 'update_exchange_rates_hourly',
120 + ],
121 + ];
122 + if ( ! isset( $schedule[ $block_id ] ) ) {
123 + return;
124 + }
125 + if ( ! isset( $rawOptions['active'] ) ) {
126 + return;
127 + }
128 + if ( 'on' === $rawOptions['active'] ) {
129 + return;
130 + }
131 + // CLear All Custom Schedule If module disabled.
132 + foreach ( $schedule[ $block_id ] as $hook ) {
133 + wp_clear_scheduled_hook( $hook );
134 + }
135 + }
86 136
87 -
88 137 /**
89 138 * @param boolen $has_orders Order exist or not.
90 139 *
91 140 * @return void
@@ -112,9 +161,9 @@
112 161 * @return void
113 162 */
114 163 public static function woocommerce_checkout_coupon_form() {
115 164 echo '<div class="rtsb-notice">';
116 - woocommerce_checkout_coupon_form();
165 + woocommerce_checkout_coupon_form();
117 166 echo '</div>';
118 167 }
119 168
120 169 /**
@@ -134,9 +183,8 @@
134 183 wc_empty_cart_message();
135 184 echo '</div>';
136 185 }
137 186
138 -
139 187 /**
140 188 * @param int $post_id Post Ids.
141 189 * @param object $post Post Object.
142 190 *
@@ -145,34 +193,57 @@
145 193 public static function deleted_post( $post_id, $post ) {
146 194 if ( BuilderFns::$post_type_tb !== $post->post_type ) {
147 195 return;
148 196 }
197 +
149 198 $options = BuilderFns::option_name_for_specific_product_set_default( $post_id );
199 + TemplateSettings::instance()->delete_option( $options );
150 200
151 - if ( TemplateSettings::instance()->get_option( $options ) ) {
152 - TemplateSettings::instance()->delete_option( $options );
153 - }
154 -
155 201 $template_options = BuilderFns::option_name_by_template_id( $post_id );
156 - if ( TemplateSettings::instance()->get_option( $template_options ) ) {
157 - TemplateSettings::instance()->delete_option( $template_options );
158 - }
202 + TemplateSettings::instance()->delete_option( $template_options );
159 203
160 204 $archive_options = BuilderFns::archive_option_name_by_template_id( $post_id );
161 - if ( TemplateSettings::instance()->get_option( $archive_options ) ) {
162 - TemplateSettings::instance()->delete_option( $archive_options );
163 - }
205 + TemplateSettings::instance()->delete_option( $archive_options );
164 206
165 207 $category_options = BuilderFns::option_name_for_specific_category_set_default( $post_id );
166 - if ( TemplateSettings::instance()->get_option( $category_options ) ) {
167 - TemplateSettings::instance()->delete_option( $category_options );
208 + TemplateSettings::instance()->delete_option( $category_options );
209 +
210 + $selected_category_options = BuilderFns::archive_option_name_by_template_id( $post_id );
211 + TemplateSettings::instance()->delete_option( $selected_category_options );
212 +
213 + // Delete Data From Options.
214 + $options_product_selected_cat = BuilderFns::option_name_product_page_selected_cat( $post_id );
215 + $cat_list = TemplateSettings::instance()->get_option( $options_product_selected_cat );
216 + if ( ! empty( $cat_list ) ) {
217 + foreach ( $cat_list as $old_slug ) {
218 + $OldcatList = get_term_by( 'slug', $old_slug, 'product_cat' );
219 + if ( ! empty( $OldcatList ) && ! is_wp_error( $OldcatList ) ) {
220 + delete_term_meta( $OldcatList->term_id, BuilderFns::$categories_product_page_template, $post_id );
221 + }
222 + }
168 223 }
224 + TemplateSettings::instance()->delete_option( $options_product_selected_cat );
169 225
170 - $selected_category_options = BuilderFns::archive_option_name_by_template_id( $post_id );
171 - if ( TemplateSettings::instance()->get_option( $selected_category_options ) ) {
172 - TemplateSettings::instance()->delete_option( $selected_category_options );
226 + $set_default_option = BuilderFns::option_name_product_page_specific_cat_set_default( $post_id );
227 + TemplateSettings::instance()->delete_option( $set_default_option );
228 +
229 + // Tags Remove.
230 + $options_product_selected_tag = BuilderFns::option_name_product_page_selected_tag( $post_id );
231 + $tag_list = TemplateSettings::instance()->get_option( $options_product_selected_tag );
232 + if ( ! empty( $tag_list ) ) {
233 + foreach ( $tag_list as $old_slug ) {
234 + $OldTagList = get_term_by( 'slug', $old_slug, 'product_tag' );
235 + if ( ! empty( $OldTagList ) && ! is_wp_error( $OldTagList ) ) {
236 + delete_term_meta( $OldTagList->term_id, BuilderFns::$tags_product_page_template, $post_id );
237 + }
238 + }
173 239 }
240 + TemplateSettings::instance()->delete_option( $options_product_selected_tag );
174 241
242 + // Tag Set Default Option.
243 + $tag_set_default_option = BuilderFns::option_name_product_page_specific_tag_set_default( $post_id );
244 + TemplateSettings::instance()->delete_option( $tag_set_default_option );
245 +
175 246 global $wpdb;
176 247 // Prepare and execute the SQL query.
177 248 $sql = $wpdb->prepare( "DELETE FROM $wpdb->postmeta WHERE meta_key = %s AND meta_value = %d", BuilderFns::$view_template_for_products_meta, $post_id );
178 249 $wpdb->query( $sql ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.NoCaching
@@ -209,9 +280,11 @@
209 280 $settings['share_platforms'] = $share_platforms;
210 281 $settings['layout'] = ! empty( $generalList['social_share']['share_icon_layout'] ) ? $generalList['social_share']['share_icon_layout'] : 1;
211 282 $settings['show_share_icon'] = 1;
212 283
213 - // TODO:: Implement Later ! empty( $generalList['social_share']['share_icon_show_to_product_page'] ) && 'on' === $generalList['social_share']['share_icon_show_to_product_page'];
284 + /**
285 + * Implement Later ! empty( $generalList['social_share']['share_icon_show_to_product_page'] ) && 'on' === $generalList['social_share']['share_icon_show_to_product_page'];
286 + */
214 287 Fns::print_html( Render::instance()->social_share_view( 'elementor/general/social-share', $settings ), true );
215 288 }
216 289
217 290 /**
@@ -248,13 +321,12 @@
248 321 /**
249 322 * Render image.
250 323 *
251 324 * @param array $args Image args.
252 - * @param array $settings Settings array.
253 325 *
254 326 * @return void
255 327 */
256 - public static function render_image( $args, $settings ) {
328 + public static function render_image( $args ) {
257 329 if ( $args['image_link'] ) {
258 330 $aria_label = esc_attr(
259 331 /* translators: Product Name */
260 332 sprintf( __( 'Image link for Product: %s', 'shopbuilder' ), $args['title'] )
@@ -284,10 +356,14 @@
284 356 */
285 357 public static function modify_wc_query_args( $settings ) {
286 358 if ( ( isset( $settings['tax_relation'] ) && 'OR' === $settings['tax_relation'] ) ||
287 359 ( isset( $settings['relation'] ) && 'OR' === $settings['relation'] ) ) {
288 - add_filter( 'woocommerce_product_data_store_cpt_get_products_query', [ FilterHooks::class, 'extra_query_args' ], 10, 2 );
360 + add_filter( 'woocommerce_product_data_store_cpt_get_products_query', [ FilterHooks::class, 'extra_query_args_or' ], 10, 2 );
289 361 }
362 + if ( ( isset( $settings['tax_relation'] ) && 'AND' === $settings['tax_relation'] ) ||
363 + ( isset( $settings['relation'] ) && 'AND' === $settings['relation'] ) ) {
364 + add_filter( 'woocommerce_product_data_store_cpt_get_products_query', [ FilterHooks::class, 'extra_query_args_and' ], 10, 2 );
365 + }
290 366
291 367 if ( 'yes' === get_option( 'woocommerce_hide_out_of_stock_items' ) ) {
292 368 add_filter( 'woocommerce_product_data_store_cpt_get_products_query', [ FilterHooks::class, 'extra_query_args_outofstock' ] );
293 369 }
@@ -302,12 +378,171 @@
302 378 */
303 379 public static function reset_wc_query_args( $settings ) {
304 380 if ( ( isset( $settings['tax_relation'] ) && 'OR' === $settings['tax_relation'] ) ||
305 381 ( isset( $settings['relation'] ) && 'OR' === $settings['relation'] ) ) {
306 - remove_filter( 'woocommerce_product_data_store_cpt_get_products_query', [ FilterHooks::class, 'extra_query_args' ] );
382 + remove_filter( 'woocommerce_product_data_store_cpt_get_products_query', [ FilterHooks::class, 'extra_query_args_or' ] );
307 383 }
384 + if ( ( isset( $settings['tax_relation'] ) && 'AND' === $settings['tax_relation'] ) ||
385 + ( isset( $settings['relation'] ) && 'AND' === $settings['relation'] ) ) {
386 + remove_filter( 'woocommerce_product_data_store_cpt_get_products_query', [ FilterHooks::class, 'extra_query_args_and' ] );
387 + }
308 388
309 389 if ( 'yes' === get_option( 'woocommerce_hide_out_of_stock_items' ) ) {
310 390 remove_filter( 'woocommerce_product_data_store_cpt_get_products_query', [ FilterHooks::class, 'extra_query_args_outofstock' ] );
311 391 }
392 + }
393 + /**
394 + * Display a filter header.
395 + *
396 + * @param array $settings The settings.
397 + *
398 + * @return void
399 + */
400 + public static function default_filter_header( $settings ) {
401 + if ( empty( $settings['show_filter_header'] ) && empty( $settings['filter_header_text'] ) ) {
402 + return;
403 + }
404 +
405 + $wrapper_class = 'rtsb-default-filter-header ';
406 +
407 + ?>
408 +
409 + <div class="<?php echo esc_attr( $wrapper_class ); ?>">
410 + <h3><?php echo esc_html( $settings['filter_header_text'] ); ?></h3>
411 + </div>
412 +
413 + <?php
414 + }
415 + /**
416 + * Display a filter search form.
417 + *
418 + * @param array $settings The settings.
419 + *
420 + * @return void
421 + */
422 + public static function default_filter_search( $settings ) {
423 + if ( empty( $settings['search_form'] ) ) {
424 + return;
425 + }
426 +
427 + $title = [
428 + 'title' => ! empty( $settings['search_title'] ) ? $settings['search_title'] : '',
429 + 'show_icon' => ! empty( $settings['show_search_title_icon'] ),
430 + 'icon' => ! empty( $settings['filter_search_title_icon'] ) ? $settings['filter_search_title_icon'] : [],
431 + ];
432 + $placeholder = ! empty( $settings['search_placeholder'] ) ? $settings['search_placeholder'] : '';
433 + $btn_icon = ! empty( $settings['search_title_icon'] ) ? $settings['search_title_icon'] : [];
434 + $wrapper_class = 'rtsb-default-filter-search rtsb-default-product-search';
435 + $unique_id = substr( uniqid(), -6 );
436 + $search_term = isset( $_REQUEST['s'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['s'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
437 + ?>
438 +
439 + <div class="<?php echo esc_attr( $wrapper_class ); ?>">
440 + <?php
441 + Fns::print_html( RenderHelpers::get_default_filter_title( $title ) );
442 + ?>
443 + <div class="default-search-content">
444 + <div class="woocommerce-product-search<?php echo ! empty( $search_term ) ? ' active' : ''; ?>">
445 + <div class="search-input">
446 + <label class="screen-reader-text" for="rtsb-product-default-search-form-<?php echo esc_attr( $unique_id ); ?>"><?php echo esc_html( $placeholder ); ?></label>
447 + <input type="search" id="rtsb-product-default-search-form-<?php echo esc_attr( $unique_id ); ?>" class="rtsb-default-search-field" placeholder="<?php echo esc_html( $placeholder ); ?>" value="<?php echo esc_attr( $search_term ); ?>" name="s" autocomplete="off">
448 + </div>
449 + <button class="rtsb-search-submit">
450 + <?php
451 +
452 + Fns::print_html( Fns::icons_manager( $btn_icon, 'search-icon' ) );
453 +
454 + ?>
455 + <span></span>
456 + </button>
457 + </div>
458 + </div>
459 + </div>
460 +
461 + <?php
462 + }
463 + /**
464 + * Query modifier.
465 + *
466 + * @param object $query Query.
467 + * @return object
468 + */
469 + public static function query_modifier( $query ) {
470 + // phpcs:disable WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
471 +
472 + // Sale filter.
473 + $onsale_filter = isset( $_GET['sale_filter'] ) ? sanitize_text_field( wp_unslash( $_GET['sale_filter'] ) ) : '';
474 + $on_sale_products = wc_get_product_ids_on_sale();
475 +
476 + if ( 'onsale' === $onsale_filter ) {
477 + $query->set( 'post__in', ! empty( $on_sale_products ) ? $on_sale_products : [ 0 ] );
478 + } elseif ( 'regular' === $onsale_filter ) {
479 + $query->set( 'post__not_in', $on_sale_products );
480 + }
481 +
482 + // Taxonomy filters (product_cat, product_tag, product_brand) from URL.
483 + $tax_query = (array) $query->get( 'tax_query' );
484 +
485 + $taxonomy_map = [
486 + 'product_cat' => 'product_cat',
487 + 'product_tag' => 'product_tag',
488 + 'product_brand' => 'product_brand',
489 + ];
490 +
491 + foreach ( $taxonomy_map as $param => $taxonomy ) {
492 + if ( empty( $_GET[ $param ] ) || ! taxonomy_exists( $taxonomy ) ) {
493 + continue;
494 + }
495 +
496 + $raw_values = wc_clean( wp_unslash( $_GET[ $param ] ) );
497 + $slugs = array_filter( array_map( 'urldecode', explode( ',', $raw_values ) ) );
498 +
499 + if ( empty( $slugs ) ) {
500 + continue;
501 + }
502 +
503 + $tax_query[] = [
504 + 'taxonomy' => $taxonomy,
505 + 'field' => 'slug',
506 + 'terms' => $slugs,
507 + 'operator' => 'IN',
508 + ];
509 + }
510 +
511 + // Rating filter (rating_filter=4,5).
512 + if ( ! empty( $_GET['rating_filter'] ) ) {
513 + $raw_ratings = wc_clean( wp_unslash( $_GET['rating_filter'] ) );
514 + $ratings = array_filter( array_map( 'intval', explode( ',', $raw_ratings ) ) );
515 +
516 + if ( ! empty( $ratings ) ) {
517 + $rating_terms = [];
518 + foreach ( $ratings as $rating ) {
519 + $rating_terms[] = 'rated-' . $rating;
520 + }
521 +
522 + $tax_query[] = [
523 + 'taxonomy' => 'product_visibility',
524 + 'field' => 'name',
525 + 'terms' => $rating_terms,
526 + 'operator' => 'IN',
527 + ];
528 + }
529 + }
530 +
531 + if ( ! empty( $tax_query ) ) {
532 + $query->set( 'tax_query', $tax_query );
533 + }
534 +
535 + // phpcs:enable WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
536 +
537 + return $query;
538 + }
539 +
540 + /**
541 + * Delete cache when switching to another theme.
542 + *
543 + * @return void
544 + */
545 + public static function clear_cache() {
546 + Cache::clear_all_cache();
312 547 }
313 548 }