PluginProbe
Product Labels, Quick View, Buy Now, Pre-Orders, Frequently Bought Together & More for WooCommerce – Merchant / 2.3.2
Product Labels, Quick View, Buy Now, Pre-Orders, Frequently Bought Together & More for WooCommerce – Merchant v2.3.2
2.3.2 2.3.1 2.3.0 2.2.8 2.2.7 trunk 1.10.0 1.10.1 1.10.2 1.10.3 1.10.4 1.10.5 1.11.0 1.11.1 1.11.2 1.6 1.7 1.8 1.8.1 1.8.2 1.8.3 1.9.0 1.9.1 1.9.10 1.9.11 All 60 releases
← All changes | inc/helpers.php +91 -3 2.2.82.3.2 View file →
@@ -393,9 +393,9 @@
393 393 * @param mixed $value The raw SVG markup.
394 394 *
395 395 * @return string The sanitized SVG markup.
396 396 *
397 - * @since 2.2.9
397 + * @since 2.3.0
398 398 */
399 399 if ( ! function_exists( 'merchant_sanitize_svg' ) ) {
400 400 function merchant_sanitize_svg( $value ) {
401 401 return wp_kses( (string) $value, merchant_kses_allowed_tags( array(), false ) );
@@ -522,8 +522,96 @@
522 522 }
523 523 }
524 524
525 525 /**
526 + * Get every descendant category slug of a given category term.
527 + *
528 + * Uses a single `child_of` term query, so the whole branch is returned in one
529 + * call regardless of how deeply the tree is nested.
530 + *
531 + * @param int $term_id Parent product category term ID.
532 + *
533 + * @return string[] Descendant category slugs. Empty when the term has no children.
534 + */
535 +if ( ! function_exists( 'merchant_get_category_descendant_slugs' ) ) {
536 + function merchant_get_category_descendant_slugs( $term_id ) {
537 + $descendants = get_terms(
538 + array(
539 + 'taxonomy' => 'product_cat',
540 + 'child_of' => (int) $term_id,
541 + 'fields' => 'slugs',
542 + 'hide_empty' => false,
543 + )
544 + );
545 +
546 + if ( is_wp_error( $descendants ) || ! is_array( $descendants ) ) {
547 + return array();
548 + }
549 +
550 + return $descendants;
551 + }
552 +}
553 +
554 +/**
555 + * Expand category slugs to include all of their descendant categories.
556 + *
557 + * Products are only ever assigned to the categories picked for them, so a
558 + * product sitting in "Hoodies" is not matched by a rule targeting its parent
559 + * "Clothing". Expanding the parent into its whole branch makes that match work.
560 + *
561 + * Slugs that do not resolve to a category are passed through untouched, so an
562 + * unknown slug never silently disappears from a rule.
563 + *
564 + * @param string[] $slugs Category slugs to expand.
565 + *
566 + * @return string[] The given slugs plus every descendant slug, de-duplicated.
567 + */
568 +if ( ! function_exists( 'merchant_expand_categories_with_children' ) ) {
569 + function merchant_expand_categories_with_children( $slugs ) {
570 + $slugs = array_filter( array_map( 'strval', (array) $slugs ), 'strlen' );
571 +
572 + if ( empty( $slugs ) ) {
573 + return array();
574 + }
575 +
576 + $expanded = $slugs;
577 +
578 + foreach ( $slugs as $slug ) {
579 + $term = get_term_by( 'slug', $slug, 'product_cat' );
580 +
581 + if ( empty( $term ) || is_wp_error( $term ) ) {
582 + continue;
583 + }
584 +
585 + $expanded = array_merge( $expanded, merchant_get_category_descendant_slugs( $term->term_id ) );
586 + }
587 +
588 + return array_values( array_unique( $expanded ) );
589 + }
590 +}
591 +
592 +/**
593 + * Expand category slugs only when a campaign opted into subcategories.
594 + *
595 + * Call this at the point a campaign's category slugs are read, so matching
596 + * behaviour stays byte-for-byte identical while the toggle is off.
597 + *
598 + * @param string[] $slugs Category slugs from the campaign.
599 + * @param array<string, mixed> $settings Campaign settings holding the toggle.
600 + *
601 + * @return string[] Expanded slugs when the toggle is on, otherwise the input.
602 + */
603 +if ( ! function_exists( 'merchant_maybe_expand_categories' ) ) {
604 + function merchant_maybe_expand_categories( $slugs, $settings ) {
605 + if ( empty( $settings['include_subcategories'] ) ) {
606 + return (array) $slugs;
607 + }
608 +
609 + return merchant_expand_categories_with_children( $slugs );
610 + }
611 +}
612 +
613 +/**
526 614 * Get the product tags.
527 615 */
528 616 if ( ! function_exists( 'merchant_get_product_tags' ) ) {
529 617 function merchant_get_product_tags() {
@@ -874,9 +962,9 @@
874 962 }
875 963
876 964 // Exclude categories
877 965 if ( in_array( $display_rule, array( 'all', 'all_products', 'categories', 'category', 'by_category' ), true ) ) {
878 - $excluded_categories_slugs = $args['excluded_categories'] ?? array();
966 + $excluded_categories_slugs = merchant_maybe_expand_categories( $args['excluded_categories'] ?? array(), $args );
879 967
880 968 if ( ! empty( $excluded_categories_slugs ) && has_term( $excluded_categories_slugs, 'product_cat', $_product_id ) ) {
881 969 return true;
882 970 }
@@ -901,9 +989,9 @@
901 989 }
902 990
903 991 // Exclude categories with toggle
904 992 if ( ! empty( $args['exclude_categories_toggle'] ) && in_array( $display_rule, array( 'all', 'all_products', 'categories', 'category', 'by_category' ), true ) ) {
905 - $excluded_categories_slugs = $args['excluded_categories'] ?? array();
993 + $excluded_categories_slugs = merchant_maybe_expand_categories( $args['excluded_categories'] ?? array(), $args );
906 994
907 995 if ( ! empty( $excluded_categories_slugs ) && has_term( $excluded_categories_slugs, 'product_cat', $_product_id ) ) {
908 996 return true;
909 997 }