Merge pull request #16644 from woocommerce/feature/15979-4

Allow select visibility in product shortcodes
This commit is contained in:
Mike Jolley 2017-08-30 12:16:46 +01:00 committed by GitHub
commit 8ffbd331e0
3 changed files with 294 additions and 81 deletions

View File

@ -261,8 +261,6 @@ class WC_Shortcodes {
$type = 'best_selling_products'; $type = 'best_selling_products';
} elseif ( isset( $atts['top_rated'] ) && wc_string_to_bool( $atts['top_rated'] ) ) { } elseif ( isset( $atts['top_rated'] ) && wc_string_to_bool( $atts['top_rated'] ) ) {
$type = 'top_rated_products'; $type = 'top_rated_products';
} elseif ( isset( $atts['featured'] ) && wc_string_to_bool( $atts['featured'] ) ) {
$type = 'featured_products';
} }
$shortcode = new WC_Shortcode_Products( $atts, $type ); $shortcode = new WC_Shortcode_Products( $atts, $type );
@ -456,6 +454,8 @@ class WC_Shortcodes {
'cat_operator' => 'IN', 'cat_operator' => 'IN',
), (array) $atts ); ), (array) $atts );
$atts['visibility'] = 'featured';
$shortcode = new WC_Shortcode_Products( $atts, 'featured_products' ); $shortcode = new WC_Shortcode_Products( $atts, 'featured_products' );
return $shortcode->get_content(); return $shortcode->get_content();

View File

@ -41,6 +41,14 @@ class WC_Shortcode_Products {
*/ */
protected $query_args = array(); protected $query_args = array();
/**
* Set custom visibility.
*
* @since 3.2.0
* @var bool
*/
protected $custom_visibility = false;
/** /**
* Initialize shortcode. * Initialize shortcode.
* *
@ -116,6 +124,7 @@ class WC_Shortcode_Products {
'attribute' => '', // Single attribute slug. 'attribute' => '', // Single attribute slug.
'terms' => '', // Comma separated term slugs. 'terms' => '', // Comma separated term slugs.
'terms_operator' => 'IN', // Operator to compare terms. Possible values are 'IN', 'NOT IN', 'AND'. 'terms_operator' => 'IN', // Operator to compare terms. Possible values are 'IN', 'NOT IN', 'AND'.
'visibility' => 'visible', // Possible values are 'visible', 'catalog', 'search', 'hidden'.
'class' => '', // HTML class. 'class' => '', // HTML class.
), $attributes, $this->type ); ), $attributes, $this->type );
} }
@ -163,9 +172,12 @@ class WC_Shortcode_Products {
// @codingStandardsIgnoreStart // @codingStandardsIgnoreStart
$query_args['posts_per_page'] = (int) $this->attributes['limit']; $query_args['posts_per_page'] = (int) $this->attributes['limit'];
$query_args['meta_query'] = WC()->query->get_meta_query(); $query_args['meta_query'] = WC()->query->get_meta_query();
$query_args['tax_query'] = WC()->query->get_tax_query(); $query_args['tax_query'] = array();
// @codingStandardsIgnoreEnd // @codingStandardsIgnoreEnd
// Visibility.
$this->set_visibility_query_args( $query_args );
// SKUs. // SKUs.
$this->set_skus_query_args( $query_args ); $this->set_skus_query_args( $query_args );
@ -228,7 +240,7 @@ class WC_Shortcode_Products {
* @param array $query_args Query args. * @param array $query_args Query args.
*/ */
protected function set_attributes_query_args( &$query_args ) { protected function set_attributes_query_args( &$query_args ) {
if ( ! empty( $this->attributes['attribute'] ) || ! empty( $this->attributes['filter'] ) ) { if ( ! empty( $this->attributes['attribute'] ) || ! empty( $this->attributes['terms'] ) ) {
$query_args['tax_query'][] = array( $query_args['tax_query'][] = array(
'taxonomy' => strstr( $this->attributes['attribute'], 'pa_' ) ? sanitize_title( $this->attributes['attribute'] ) : 'pa_' . sanitize_title( $this->attributes['attribute'] ), 'taxonomy' => strstr( $this->attributes['attribute'], 'pa_' ) ? sanitize_title( $this->attributes['attribute'] ) : 'pa_' . sanitize_title( $this->attributes['attribute'] ),
'terms' => array_map( 'sanitize_title', explode( ',', $this->attributes['terms'] ) ), 'terms' => array_map( 'sanitize_title', explode( ',', $this->attributes['terms'] ) ),
@ -290,18 +302,87 @@ class WC_Shortcode_Products {
} }
/** /**
* Set featured products query args. * Set visibility query args.
* *
* @since 3.2.0 * @since 3.2.0
* @param array $query_args Query args. * @param array $query_args Query args.
*/ */
protected function set_featured_products_query_args( &$query_args ) { protected function set_visibility_query_args( &$query_args ) {
switch ( $this->attributes['visibility'] ) {
case 'hidden' :
$this->custom_visibility = true;
$query_args['tax_query'][] = array(
'taxonomy' => 'product_visibility',
'terms' => array( 'exclude-from-catalog', 'exclude-from-search' ),
'field' => 'name',
'operator' => 'AND',
'include_children' => false,
);
break;
case 'catalog' :
$this->custom_visibility = true;
$query_args['tax_query'][] = array(
'taxonomy' => 'product_visibility',
'terms' => 'exclude-from-search',
'field' => 'name',
'operator' => 'IN',
'include_children' => false,
);
$query_args['tax_query'][] = array(
'taxonomy' => 'product_visibility',
'terms' => 'exclude-from-catalog',
'field' => 'name',
'operator' => 'NOT IN',
'include_children' => false,
);
break;
case 'search' :
$this->custom_visibility = true;
$query_args['tax_query'][] = array(
'taxonomy' => 'product_visibility',
'terms' => 'exclude-from-catalog',
'field' => 'name',
'operator' => 'IN',
'include_children' => false,
);
$query_args['tax_query'][] = array(
'taxonomy' => 'product_visibility',
'terms' => 'exclude-from-search',
'field' => 'name',
'operator' => 'NOT IN',
'include_children' => false,
);
break;
case 'featured' :
$query_args['tax_query'] = array_merge( $query_args['tax_query'], WC()->query->get_tax_query() );
$query_args['tax_query'][] = array( $query_args['tax_query'][] = array(
'taxonomy' => 'product_visibility', 'taxonomy' => 'product_visibility',
'terms' => 'featured', 'terms' => 'featured',
'field' => 'name', 'field' => 'name',
'operator' => 'IN', 'operator' => 'IN',
'include_children' => false,
); );
break;
default :
$query_args['tax_query'] = array_merge( $query_args['tax_query'], WC()->query->get_tax_query() );
break;
}
}
/**
* Set product as visible when quering for hidden products.
*
* @since 3.2.0
* @param bool $visibility Product visibility.
* @return bool
*/
public function set_product_as_visible( $visibility ) {
if ( $this->custom_visibility ) {
return true;
}
return $visibility;
} }
/** /**
@ -324,18 +405,12 @@ class WC_Shortcode_Products {
} }
/** /**
* Loop over found products. * Get products.
* *
* @since 3.2.0 * @since 3.2.0
* @return string * @return array
*/ */
protected function product_loop() { protected function get_products() {
global $woocommerce_loop;
$columns = absint( $this->attributes['columns'] );
$classes = $this->get_wrapper_classes( $columns );
$woocommerce_loop['columns'] = $columns;
$woocommerce_loop['name'] = $this->type;
$transient_name = 'wc_loop' . substr( md5( wp_json_encode( $this->query_args ) . $this->type ), 28 ) . WC_Cache_Helper::get_transient_version( 'product_query' ); $transient_name = 'wc_loop' . substr( md5( wp_json_encode( $this->query_args ) . $this->type ), 28 ) . WC_Cache_Helper::get_transient_version( 'product_query' );
$products = get_transient( $transient_name ); $products = get_transient( $transient_name );
@ -348,14 +423,32 @@ class WC_Shortcode_Products {
$products = new WP_Query( $this->query_args ); $products = new WP_Query( $this->query_args );
} }
set_transient( $transient_name, $products, DAY_IN_SECONDS * 30 );
}
// Remove ordering query arguments. // Remove ordering query arguments.
if ( ! empty( $this->attributes['category'] ) ) { if ( ! empty( $this->attributes['category'] ) ) {
WC()->query->remove_ordering_args(); WC()->query->remove_ordering_args();
} }
set_transient( $transient_name, $products, DAY_IN_SECONDS * 30 );
}
return $products;
}
/**
* Loop over found products.
*
* @since 3.2.0
* @return string
*/
protected function product_loop() {
global $woocommerce_loop;
$columns = absint( $this->attributes['columns'] );
$classes = $this->get_wrapper_classes( $columns );
$woocommerce_loop['columns'] = $columns;
$woocommerce_loop['name'] = $this->type;
$products = $this->get_products();
ob_start(); ob_start();
if ( $products->have_posts() ) { if ( $products->have_posts() ) {
@ -368,7 +461,15 @@ class WC_Shortcode_Products {
while ( $products->have_posts() ) { while ( $products->have_posts() ) {
$products->the_post(); $products->the_post();
// Set custom product visibility when quering hidden products.
add_action( 'woocommerce_product_is_visible', array( $this, 'set_product_as_visible' ) );
// Render product template.
wc_get_template_part( 'content', 'product' ); wc_get_template_part( 'content', 'product' );
// Restore product visibility.
remove_action( 'woocommerce_product_is_visible', array( $this, 'set_product_as_visible' ) );
} }
woocommerce_product_loop_end(); woocommerce_product_loop_end();

View File

@ -24,6 +24,7 @@ class WC_Test_Shortcode_Products extends WC_Unit_Test_Case {
'attribute' => '', 'attribute' => '',
'terms' => '', 'terms' => '',
'terms_operator' => 'IN', 'terms_operator' => 'IN',
'visibility' => 'visible',
'class' => '', 'class' => '',
); );
$this->assertEquals( $expected, $shortcode->get_attributes() ); $this->assertEquals( $expected, $shortcode->get_attributes() );
@ -44,6 +45,7 @@ class WC_Test_Shortcode_Products extends WC_Unit_Test_Case {
'attribute' => '', 'attribute' => '',
'terms' => '', 'terms' => '',
'terms_operator' => 'IN', 'terms_operator' => 'IN',
'visibility' => 'visible',
'class' => '', 'class' => '',
); );
$this->assertEquals( $expected2, $shortcode2->get_attributes() ); $this->assertEquals( $expected2, $shortcode2->get_attributes() );
@ -89,11 +91,11 @@ class WC_Test_Shortcode_Products extends WC_Unit_Test_Case {
); );
$this->assertEquals( $expected2, $shortcode2->get_query_args() ); $this->assertEquals( $expected2, $shortcode2->get_query_args() );
$shortcode2 = new WC_Shortcode_Products( array( $shortcode3 = new WC_Shortcode_Products( array(
'ids' => '1,2,3', 'ids' => '1,2,3',
'skus' => 'foo,bar', 'skus' => 'foo,bar',
) ); ) );
$expected2 = array( $expected3 = array(
'post_type' => 'product', 'post_type' => 'product',
'post_status' => 'publish', 'post_status' => 'publish',
'ignore_sticky_posts' => true, 'ignore_sticky_posts' => true,
@ -105,16 +107,16 @@ class WC_Test_Shortcode_Products extends WC_Unit_Test_Case {
'tax_query' => $tax_query, 'tax_query' => $tax_query,
'post__in' => array( '1', '2', '3' ), 'post__in' => array( '1', '2', '3' ),
); );
$expected2['meta_query'][] = array( $expected3['meta_query'][] = array(
'key' => '_sku', 'key' => '_sku',
'value' => array( 'foo', 'bar' ), 'value' => array( 'foo', 'bar' ),
'compare' => 'IN', 'compare' => 'IN',
); );
$this->assertEquals( $expected2, $shortcode2->get_query_args() ); $this->assertEquals( $expected3, $shortcode3->get_query_args() );
// product_category shortcode. // product_category shortcode.
$shortcode3 = new WC_Shortcode_Products( array( $shortcode4 = new WC_Shortcode_Products( array(
'per_page' => '12', 'per_page' => '12',
'columns' => '4', 'columns' => '4',
'orderby' => 'menu_order title', 'orderby' => 'menu_order title',
@ -122,7 +124,7 @@ class WC_Test_Shortcode_Products extends WC_Unit_Test_Case {
'category' => 'clothing', 'category' => 'clothing',
'operator' => 'IN', 'operator' => 'IN',
), 'product_category' ); ), 'product_category' );
$expected3 = array( $expected4 = array(
'post_type' => 'product', 'post_type' => 'product',
'post_status' => 'publish', 'post_status' => 'publish',
'ignore_sticky_posts' => true, 'ignore_sticky_posts' => true,
@ -134,16 +136,17 @@ class WC_Test_Shortcode_Products extends WC_Unit_Test_Case {
'tax_query' => $tax_query, 'tax_query' => $tax_query,
'meta_key' => '', 'meta_key' => '',
); );
$expected3['tax_query'][] = array( $expected4['tax_query'][] = array(
'taxonomy' => 'product_cat', 'taxonomy' => 'product_cat',
'terms' => array( 'clothing' ), 'terms' => array( 'clothing' ),
'field' => 'slug', 'field' => 'slug',
'operator' => 'IN', 'operator' => 'IN',
); );
$this->assertEquals( $expected3, $shortcode3->get_query_args() );
$this->assertEquals( $expected4, $shortcode4->get_query_args() );
// recent_products shortcode. // recent_products shortcode.
$shortcode4 = new WC_Shortcode_Products( array( $shortcode5 = new WC_Shortcode_Products( array(
'per_page' => '12', 'per_page' => '12',
'columns' => '4', 'columns' => '4',
'orderby' => 'date', 'orderby' => 'date',
@ -151,7 +154,7 @@ class WC_Test_Shortcode_Products extends WC_Unit_Test_Case {
'category' => '', 'category' => '',
'operator' => 'IN', 'operator' => 'IN',
), 'recent_products' ); ), 'recent_products' );
$expected4 = array( $expected5 = array(
'post_type' => 'product', 'post_type' => 'product',
'post_status' => 'publish', 'post_status' => 'publish',
'ignore_sticky_posts' => true, 'ignore_sticky_posts' => true,
@ -163,14 +166,14 @@ class WC_Test_Shortcode_Products extends WC_Unit_Test_Case {
'tax_query' => $tax_query, 'tax_query' => $tax_query,
); );
$this->assertEquals( $expected4, $shortcode4->get_query_args() ); $this->assertEquals( $expected5, $shortcode5->get_query_args() );
// product shortcode. // product shortcode.
$shortcode5 = new WC_Shortcode_Products( array( $shortcode6 = new WC_Shortcode_Products( array(
'ids' => '1', 'ids' => '1',
'per_page' => '1', 'per_page' => '1',
), 'product' ); ), 'product' );
$expected5 = array( $expected6 = array(
'post_type' => 'product', 'post_type' => 'product',
'post_status' => 'publish', 'post_status' => 'publish',
'ignore_sticky_posts' => true, 'ignore_sticky_posts' => true,
@ -183,10 +186,10 @@ class WC_Test_Shortcode_Products extends WC_Unit_Test_Case {
'p' => '1', 'p' => '1',
); );
$this->assertEquals( $expected5, $shortcode5->get_query_args() ); $this->assertEquals( $expected6, $shortcode6->get_query_args() );
// sale_products shortcode. // sale_products shortcode.
$shortcode6 = new WC_Shortcode_Products( array( $shortcode7 = new WC_Shortcode_Products( array(
'per_page' => '12', 'per_page' => '12',
'columns' => '4', 'columns' => '4',
'orderby' => 'title', 'orderby' => 'title',
@ -194,7 +197,7 @@ class WC_Test_Shortcode_Products extends WC_Unit_Test_Case {
'category' => '', 'category' => '',
'operator' => 'IN', 'operator' => 'IN',
), 'sale_products' ); ), 'sale_products' );
$expected6 = array( $expected7 = array(
'post_type' => 'product', 'post_type' => 'product',
'post_status' => 'publish', 'post_status' => 'publish',
'ignore_sticky_posts' => true, 'ignore_sticky_posts' => true,
@ -207,16 +210,16 @@ class WC_Test_Shortcode_Products extends WC_Unit_Test_Case {
'post__in' => array_merge( array( 0 ), wc_get_product_ids_on_sale() ), 'post__in' => array_merge( array( 0 ), wc_get_product_ids_on_sale() ),
); );
$this->assertEquals( $expected6, $shortcode6->get_query_args() ); $this->assertEquals( $expected7, $shortcode7->get_query_args() );
// best_selling_products shortcode. // best_selling_products shortcode.
$shortcode7 = new WC_Shortcode_Products( array( $shortcode8 = new WC_Shortcode_Products( array(
'per_page' => '12', 'per_page' => '12',
'columns' => '4', 'columns' => '4',
'category' => '', 'category' => '',
'operator' => 'IN', 'operator' => 'IN',
), 'best_selling_products' ); ), 'best_selling_products' );
$expected7 = array( $expected8 = array(
'post_type' => 'product', 'post_type' => 'product',
'post_status' => 'publish', 'post_status' => 'publish',
'ignore_sticky_posts' => true, 'ignore_sticky_posts' => true,
@ -229,10 +232,10 @@ class WC_Test_Shortcode_Products extends WC_Unit_Test_Case {
'meta_key' => 'total_sales', 'meta_key' => 'total_sales',
); );
$this->assertEquals( $expected7, $shortcode7->get_query_args() ); $this->assertEquals( $expected8, $shortcode8->get_query_args() );
// top_rated_products shortcode. // top_rated_products shortcode.
$shortcode8 = new WC_Shortcode_Products( array( $shortcode9 = new WC_Shortcode_Products( array(
'per_page' => '12', 'per_page' => '12',
'columns' => '4', 'columns' => '4',
'orderby' => 'title', 'orderby' => 'title',
@ -240,7 +243,7 @@ class WC_Test_Shortcode_Products extends WC_Unit_Test_Case {
'category' => '', 'category' => '',
'operator' => 'IN', 'operator' => 'IN',
), 'top_rated_products' ); ), 'top_rated_products' );
$expected8 = array( $expected9 = array(
'post_type' => 'product', 'post_type' => 'product',
'post_status' => 'publish', 'post_status' => 'publish',
'ignore_sticky_posts' => true, 'ignore_sticky_posts' => true,
@ -252,16 +255,19 @@ class WC_Test_Shortcode_Products extends WC_Unit_Test_Case {
'tax_query' => $tax_query, 'tax_query' => $tax_query,
); );
$this->assertEquals( $expected9, $shortcode9->get_query_args() );
// featured_products shortcode. // featured_products shortcode.
$shortcode9 = new WC_Shortcode_Products( array( $shortcode10 = new WC_Shortcode_Products( array(
'per_page' => '12', 'per_page' => '12',
'columns' => '4', 'columns' => '4',
'orderby' => 'date', 'orderby' => 'date',
'order' => 'DESC', 'order' => 'DESC',
'category' => '', 'category' => '',
'operator' => 'IN', 'operator' => 'IN',
), 'featured_products' ); 'visibility' => 'featured',
$expected9 = array( ) );
$expected10 = array(
'post_type' => 'product', 'post_type' => 'product',
'post_status' => 'publish', 'post_status' => 'publish',
'ignore_sticky_posts' => true, 'ignore_sticky_posts' => true,
@ -273,15 +279,18 @@ class WC_Test_Shortcode_Products extends WC_Unit_Test_Case {
'tax_query' => array_merge( $tax_query, array( 'tax_query' => array_merge( $tax_query, array(
array( array(
'taxonomy' => 'product_visibility', 'taxonomy' => 'product_visibility',
'field' => 'name',
'terms' => 'featured', 'terms' => 'featured',
'field' => 'name',
'operator' => 'IN', 'operator' => 'IN',
'include_children' => false,
), ),
) ), ) ),
); );
$this->assertEquals( $expected10, $shortcode10->get_query_args() );
// product_attribute shortcode. // product_attribute shortcode.
$shortcode10 = new WC_Shortcode_Products( array( $shortcode11 = new WC_Shortcode_Products( array(
'per_page' => '12', 'per_page' => '12',
'columns' => '4', 'columns' => '4',
'orderby' => 'title', 'orderby' => 'title',
@ -289,7 +298,7 @@ class WC_Test_Shortcode_Products extends WC_Unit_Test_Case {
'attribute' => 'color', 'attribute' => 'color',
'filter' => 'black', 'filter' => 'black',
), 'product_attribute' ); ), 'product_attribute' );
$expected10 = array( $expected11 = array(
'post_type' => 'product', 'post_type' => 'product',
'post_status' => 'publish', 'post_status' => 'publish',
'ignore_sticky_posts' => true, 'ignore_sticky_posts' => true,
@ -308,7 +317,97 @@ class WC_Test_Shortcode_Products extends WC_Unit_Test_Case {
) ), ) ),
); );
$this->assertEquals( $expected10, $shortcode10->get_query_args() ); $this->assertEquals( $expected11, $shortcode11->get_query_args() );
// Check for visibility shortcode.
$shortcode12 = new WC_Shortcode_Products( array(
'visibility' => 'hidden',
) );
$expected12 = array(
'post_type' => 'product',
'post_status' => 'publish',
'ignore_sticky_posts' => true,
'no_found_rows' => true,
'orderby' => 'title',
'order' => 'ASC',
'posts_per_page' => -1,
'meta_query' => $meta_query,
'tax_query' => array(
array(
'taxonomy' => 'product_visibility',
'terms' => array( 'exclude-from-catalog', 'exclude-from-search' ),
'field' => 'name',
'operator' => 'AND',
'include_children' => false,
),
),
);
$this->assertEquals( $expected12, $shortcode12->get_query_args() );
$shortcode13 = new WC_Shortcode_Products( array(
'visibility' => 'catalog',
) );
$expected13 = array(
'post_type' => 'product',
'post_status' => 'publish',
'ignore_sticky_posts' => true,
'no_found_rows' => true,
'orderby' => 'title',
'order' => 'ASC',
'posts_per_page' => -1,
'meta_query' => $meta_query,
'tax_query' => array(
array(
'taxonomy' => 'product_visibility',
'terms' => 'exclude-from-search',
'field' => 'name',
'operator' => 'IN',
'include_children' => false,
),
array(
'taxonomy' => 'product_visibility',
'terms' => 'exclude-from-catalog',
'field' => 'name',
'operator' => 'NOT IN',
'include_children' => false,
),
),
);
$this->assertEquals( $expected13, $shortcode13->get_query_args() );
$shortcode14 = new WC_Shortcode_Products( array(
'visibility' => 'search',
) );
$expected14 = array(
'post_type' => 'product',
'post_status' => 'publish',
'ignore_sticky_posts' => true,
'no_found_rows' => true,
'orderby' => 'title',
'order' => 'ASC',
'posts_per_page' => -1,
'meta_query' => $meta_query,
'tax_query' => array(
array(
'taxonomy' => 'product_visibility',
'terms' => 'exclude-from-catalog',
'field' => 'name',
'operator' => 'IN',
'include_children' => false,
),
array(
'taxonomy' => 'product_visibility',
'terms' => 'exclude-from-search',
'field' => 'name',
'operator' => 'NOT IN',
'include_children' => false,
),
),
);
$this->assertEquals( $expected14, $shortcode14->get_query_args() );
} }
/** /**
@ -330,6 +429,19 @@ class WC_Test_Shortcode_Products extends WC_Unit_Test_Case {
$this->assertTrue( ! empty( $result ) ); $this->assertTrue( ! empty( $result ) );
} }
/**
* Test: WC_Shortcode_Products::set_product_as_visible.
*/
public function test_set_product_as_visible() {
$shortcode = new WC_Shortcode_Products();
$this->assertFalse( $shortcode->set_product_as_visible( false ) );
$shortcode2 = new WC_Shortcode_Products( array(
'visibility' => 'hidden',
) );
$this->assertTrue( $shortcode2->set_product_as_visible( false ) );
}
/** /**
* Test: WC_Shortcode_Products::order_by_rating_post_clauses. * Test: WC_Shortcode_Products::order_by_rating_post_clauses.
*/ */