Product Visibility Taxonomies (#12527)
* Convert visibility and featured to taxonomy * Comment * Add missing tax_queries * Only check SKU after read. * Added visibility term for outofstock products to speed those queries up al * wc_bool_to_string
This commit is contained in:
parent
af3f735664
commit
47fbae4d26
File diff suppressed because one or more lines are too long
|
@ -2174,13 +2174,9 @@ table.wp-list-table {
|
|||
}
|
||||
|
||||
span.wc-featured {
|
||||
margin: 0;
|
||||
cursor: pointer;
|
||||
|
||||
&::before {
|
||||
content: '\f155';
|
||||
}
|
||||
|
||||
&.not-featured {
|
||||
&::before {
|
||||
content: '\f154';
|
||||
|
@ -2191,12 +2187,11 @@ table.wp-list-table {
|
|||
td.column-featured {
|
||||
span.wc-featured {
|
||||
font-size: 1.6em;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
span.wc-type {
|
||||
margin: 0;
|
||||
|
||||
&::before {
|
||||
font-family: 'WooCommerce';
|
||||
content: '\e006';
|
||||
|
@ -2206,6 +2201,7 @@ table.wp-list-table {
|
|||
span.product-type {
|
||||
@include ir();
|
||||
font-size: 1.6em;
|
||||
margin: 0 auto;
|
||||
|
||||
&::before {
|
||||
@include icon( '\e006' );
|
||||
|
|
|
@ -299,6 +299,7 @@ abstract class WC_Data {
|
|||
|
||||
/**
|
||||
* Read Meta Data from the database. Ignore any internal properties.
|
||||
* Uses it's own caches because get_metadata does not provide meta_ids.
|
||||
*
|
||||
* @since 2.6.0
|
||||
* @param bool $force_read True to force a new DB read (and update cache).
|
||||
|
|
|
@ -807,7 +807,7 @@ class WC_Product extends WC_Abstract_Legacy_Product {
|
|||
*/
|
||||
public function set_sku( $sku ) {
|
||||
$sku = (string) $sku;
|
||||
if ( ! empty( $sku ) && ! wc_product_has_unique_sku( $this->get_id(), $sku ) ) {
|
||||
if ( $this->get_object_read() && ! empty( $sku ) && ! wc_product_has_unique_sku( $this->get_id(), $sku ) ) {
|
||||
$this->error( 'product_invalid_sku', __( 'Invalid or duplicated SKU.', 'woocommerce' ) );
|
||||
}
|
||||
$this->set_prop( 'sku', $sku );
|
||||
|
|
|
@ -736,7 +736,6 @@ class WC_Admin_Post_Types {
|
|||
public function product_sortable_columns( $columns ) {
|
||||
$custom = array(
|
||||
'price' => 'price',
|
||||
'featured' => array( 'featured', 1 ),
|
||||
'sku' => 'sku',
|
||||
'name' => 'title',
|
||||
);
|
||||
|
@ -1671,12 +1670,6 @@ class WC_Admin_Post_Types {
|
|||
'orderby' => 'meta_value_num',
|
||||
) );
|
||||
}
|
||||
if ( 'featured' == $vars['orderby'] ) {
|
||||
$vars = array_merge( $vars, array(
|
||||
'meta_key' => '_featured',
|
||||
'orderby' => 'meta_value',
|
||||
) );
|
||||
}
|
||||
if ( 'sku' == $vars['orderby'] ) {
|
||||
$vars = array_merge( $vars, array(
|
||||
'meta_key' => '_sku',
|
||||
|
@ -1876,27 +1869,23 @@ class WC_Admin_Post_Types {
|
|||
* Output product visibility options.
|
||||
*/
|
||||
public function product_data_visibility() {
|
||||
global $post;
|
||||
global $post, $thepostid, $product_object;
|
||||
|
||||
if ( 'product' != $post->post_type ) {
|
||||
if ( 'product' !== $post->post_type ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$current_visibility = ( $current_visibility = get_post_meta( $post->ID, '_visibility', true ) ) ? $current_visibility : apply_filters( 'woocommerce_product_visibility_default' , 'visible' );
|
||||
$current_featured = ( $current_featured = get_post_meta( $post->ID, '_featured', true ) ) ? $current_featured : 'no';
|
||||
|
||||
$visibility_options = apply_filters( 'woocommerce_product_visibility_options', array(
|
||||
'visible' => __( 'Catalog/search', 'woocommerce' ),
|
||||
'catalog' => __( 'Catalog', 'woocommerce' ),
|
||||
'search' => __( 'Search', 'woocommerce' ),
|
||||
'hidden' => __( 'Hidden', 'woocommerce' ),
|
||||
) );
|
||||
$thepostid = $post->ID;
|
||||
$product_object = $thepostid ? wc_get_product( $thepostid ) : new WC_Product;
|
||||
$current_visibility = $product_object->get_catalog_visibility();
|
||||
$current_featured = wc_bool_to_string( $product_object->get_featured() );
|
||||
$visibility_options = wc_get_product_visibility_options();
|
||||
?>
|
||||
<div class="misc-pub-section" id="catalog-visibility">
|
||||
<?php _e( 'Catalog visibility:', 'woocommerce' ); ?> <strong id="catalog-visibility-display"><?php
|
||||
echo isset( $visibility_options[ $current_visibility ] ) ? esc_html( $visibility_options[ $current_visibility ] ) : esc_html( $current_visibility );
|
||||
|
||||
if ( 'yes' == $current_featured ) {
|
||||
if ( 'yes' === $current_featured ) {
|
||||
echo ', ' . __( 'Featured', 'woocommerce' );
|
||||
}
|
||||
?></strong>
|
||||
|
|
|
@ -12,15 +12,15 @@
|
|||
</label>
|
||||
|
||||
<?php foreach ( self::get_product_type_options() as $key => $option ) :
|
||||
if ( $thepostid ) {
|
||||
$selected_value = is_callable( array( $product_object, "is_$key" ) ) ? $product_object->{"is_$key"}() : get_post_meta( $post->ID, '_' . $key, true );
|
||||
if ( $product_object ) {
|
||||
$selected_value = is_callable( array( $product_object, "is_$key" ) ) ? $product_object->{"is_$key"}() : 'yes' === get_post_meta( $post->ID, '_' . $key, true );
|
||||
} else {
|
||||
$selected_value = isset( $option['default'] ) ? $option['default'] : 'no';
|
||||
$selected_value = 'yes' === ( isset( $option['default'] ) ? $option['default'] : 'no' );
|
||||
}
|
||||
?>
|
||||
<label for="<?php echo esc_attr( $option['id'] ); ?>" class="<?php echo esc_attr( $option['wrapper_class'] ); ?> tips" data-tip="<?php echo esc_attr( $option['description'] ); ?>">
|
||||
<?php echo esc_html( $option['label'] ); ?>:
|
||||
<input type="checkbox" name="<?php echo esc_attr( $option['id'] ); ?>" id="<?php echo esc_attr( $option['id'] ); ?>" <?php echo checked( $selected_value, 'yes', false ); ?> />
|
||||
<input type="checkbox" name="<?php echo esc_attr( $option['id'] ); ?>" id="<?php echo esc_attr( $option['id'] ); ?>" <?php echo checked( $selected_value, true, false ); ?> />
|
||||
</label>
|
||||
<?php endforeach; ?>
|
||||
</span>
|
||||
|
|
|
@ -169,6 +169,15 @@ class WC_REST_Products_Controller extends WC_REST_Posts_Controller {
|
|||
$args['tax_query'] = $tax_query;
|
||||
}
|
||||
|
||||
// Filter featured.
|
||||
if ( is_bool( $request['featured'] ) ) {
|
||||
$args['tax_query'][] = array(
|
||||
'taxonomy' => 'product_visibility',
|
||||
'field' => 'name',
|
||||
'terms' => 'featured',
|
||||
);
|
||||
}
|
||||
|
||||
// Filter by sku.
|
||||
if ( ! empty( $request['sku'] ) ) {
|
||||
$args['meta_query'] = $this->add_meta_query( $args, array(
|
||||
|
@ -177,14 +186,6 @@ class WC_REST_Products_Controller extends WC_REST_Posts_Controller {
|
|||
) );
|
||||
}
|
||||
|
||||
// Filter featured.
|
||||
if ( is_bool( $request['featured'] ) ) {
|
||||
$args['meta_query'] = $this->add_meta_query( $args, array(
|
||||
'key' => '_featured',
|
||||
'value' => true === $request['featured'] ? 'yes' : 'no',
|
||||
) );
|
||||
}
|
||||
|
||||
// Filter by tax class.
|
||||
if ( ! empty( $request['tax_class'] ) ) {
|
||||
$args['meta_query'] = $this->add_meta_query( $args, array(
|
||||
|
|
|
@ -75,6 +75,8 @@ class WC_Install {
|
|||
'2.7.0' => array(
|
||||
'wc_update_270_webhooks',
|
||||
'wc_update_270_grouped_products',
|
||||
'wc_update_270_settings',
|
||||
'wc_update_270_product_visibility',
|
||||
),
|
||||
);
|
||||
|
||||
|
@ -366,6 +368,12 @@ class WC_Install {
|
|||
'variable',
|
||||
'external',
|
||||
),
|
||||
'product_visibility' => array(
|
||||
'exclude-from-search',
|
||||
'exclude-from-catalog',
|
||||
'featured',
|
||||
'outofstock',
|
||||
),
|
||||
);
|
||||
|
||||
foreach ( $taxonomies as $taxonomy => $terms ) {
|
||||
|
|
|
@ -61,6 +61,18 @@ class WC_Post_types {
|
|||
) )
|
||||
);
|
||||
|
||||
register_taxonomy( 'product_visibility',
|
||||
apply_filters( 'woocommerce_taxonomy_objects_product_visibility', array( 'product', 'product_variation' ) ),
|
||||
apply_filters( 'woocommerce_taxonomy_args_product_visibility', array(
|
||||
'hierarchical' => false,
|
||||
'show_ui' => false,
|
||||
'show_in_nav_menus' => false,
|
||||
'query_var' => is_admin(),
|
||||
'rewrite' => false,
|
||||
'public' => false,
|
||||
) )
|
||||
);
|
||||
|
||||
register_taxonomy( 'product_cat',
|
||||
apply_filters( 'woocommerce_taxonomy_objects_product_cat', array( 'product' ) ),
|
||||
apply_filters( 'woocommerce_taxonomy_args_product_cat', array(
|
||||
|
|
|
@ -390,8 +390,8 @@ class WC_Query {
|
|||
}
|
||||
|
||||
// Query vars that affect posts shown
|
||||
$q->set( 'meta_query', $this->get_meta_query( $q->get( 'meta_query' ) ) );
|
||||
$q->set( 'tax_query', $this->get_tax_query( $q->get( 'tax_query' ) ) );
|
||||
$q->set( 'meta_query', $this->get_meta_query( $q->get( 'meta_query' ), true ) );
|
||||
$q->set( 'tax_query', $this->get_tax_query( $q->get( 'tax_query' ), true ) );
|
||||
$q->set( 'posts_per_page', $q->get( 'posts_per_page' ) ? $q->get( 'posts_per_page' ) : apply_filters( 'loop_shop_per_page', get_option( 'posts_per_page' ) ) );
|
||||
$q->set( 'wc_query', 'product_query' );
|
||||
$q->set( 'post__in', array_unique( (array) apply_filters( 'loop_shop_post_in', array() ) ) );
|
||||
|
@ -526,15 +526,14 @@ class WC_Query {
|
|||
* Appends meta queries to an array.
|
||||
*
|
||||
* @param array $meta_query
|
||||
* @param bool $main_query
|
||||
* @return array
|
||||
*/
|
||||
public function get_meta_query( $meta_query = array() ) {
|
||||
public function get_meta_query( $meta_query = array(), $main_query = false ) {
|
||||
if ( ! is_array( $meta_query ) ) {
|
||||
$meta_query = array();
|
||||
}
|
||||
|
||||
$meta_query['visibility'] = $this->visibility_meta_query();
|
||||
$meta_query['stock_status'] = $this->stock_status_meta_query();
|
||||
$meta_query['price_filter'] = $this->price_filter_meta_query();
|
||||
$meta_query['rating_filter'] = $this->rating_filter_meta_query();
|
||||
|
||||
|
@ -572,55 +571,64 @@ class WC_Query {
|
|||
|
||||
/**
|
||||
* Returns a meta query to handle product visibility.
|
||||
*
|
||||
* @deprecated 2.7.0 Replaced with taxonomy.
|
||||
* @param string $compare (default: 'IN')
|
||||
* @return array
|
||||
*/
|
||||
public function visibility_meta_query( $compare = 'IN' ) {
|
||||
return array(
|
||||
'key' => '_visibility',
|
||||
'value' => is_search() ? array( 'visible', 'search' ) : array( 'visible', 'catalog' ),
|
||||
'compare' => $compare,
|
||||
);
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a meta query to handle product stock status.
|
||||
*
|
||||
* @access public
|
||||
* @deprecated 2.7.0 Replaced with taxonomy.
|
||||
* @param string $status (default: 'instock')
|
||||
* @return array
|
||||
*/
|
||||
public function stock_status_meta_query( $status = 'instock' ) {
|
||||
return 'yes' === get_option( 'woocommerce_hide_out_of_stock_items' ) ? array(
|
||||
'key' => '_stock_status',
|
||||
'value' => $status,
|
||||
'compare' => '=',
|
||||
) : array();
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends tax queries to an array.
|
||||
* @param array $tax_query
|
||||
* @param bool $main_query
|
||||
* @return array
|
||||
*/
|
||||
public function get_tax_query( $tax_query = array() ) {
|
||||
public function get_tax_query( $tax_query = array(), $main_query = false ) {
|
||||
if ( ! is_array( $tax_query ) ) {
|
||||
$tax_query = array();
|
||||
$tax_query = array( 'relation' => 'AND' );
|
||||
}
|
||||
|
||||
// Layered nav filters on terms
|
||||
if ( $_chosen_attributes = $this->get_layered_nav_chosen_attributes() ) {
|
||||
// Layered nav filters on terms.
|
||||
if ( $main_query && ( $_chosen_attributes = $this->get_layered_nav_chosen_attributes() ) ) {
|
||||
foreach ( $_chosen_attributes as $taxonomy => $data ) {
|
||||
$tax_query[] = array(
|
||||
'taxonomy' => $taxonomy,
|
||||
'field' => 'slug',
|
||||
'terms' => $data['terms'],
|
||||
'operator' => 'and' === $data['query_type'] ? 'AND' : 'IN',
|
||||
'taxonomy' => $taxonomy,
|
||||
'field' => 'slug',
|
||||
'terms' => $data['terms'],
|
||||
'operator' => 'and' === $data['query_type'] ? 'AND' : 'IN',
|
||||
'include_children' => false,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
$product_visibility_not_in = array( is_search() && $main_query ? 'exclude-from-search' : 'exclude-from-catalog' );
|
||||
|
||||
// Hide out of stock products.
|
||||
if ( 'yes' === get_option( 'woocommerce_hide_out_of_stock_items' ) ) {
|
||||
$product_visibility_not_in[] = 'outofstock';
|
||||
}
|
||||
|
||||
$tax_query[] = array(
|
||||
'taxonomy' => 'product_visibility',
|
||||
'field' => 'name',
|
||||
'terms' => $product_visibility_not_in,
|
||||
'operator' => 'NOT IN',
|
||||
);
|
||||
|
||||
return array_filter( apply_filters( 'woocommerce_product_query_tax_query', $tax_query, $this ) );
|
||||
}
|
||||
|
||||
|
|
|
@ -195,6 +195,7 @@ class WC_Shortcodes {
|
|||
'order' => $ordering_args['order'],
|
||||
'posts_per_page' => $atts['per_page'],
|
||||
'meta_query' => $meta_query,
|
||||
'tax_query' => WC()->query->get_tax_query(),
|
||||
);
|
||||
|
||||
$query_args = self::_maybe_add_category_args( $query_args, $atts['category'], $atts['operator'] );
|
||||
|
@ -308,6 +309,7 @@ class WC_Shortcodes {
|
|||
'orderby' => $atts['orderby'],
|
||||
'order' => $atts['order'],
|
||||
'meta_query' => WC()->query->get_meta_query(),
|
||||
'tax_query' => WC()->query->get_tax_query(),
|
||||
);
|
||||
|
||||
$query_args = self::_maybe_add_category_args( $query_args, $atts['category'], $atts['operator'] );
|
||||
|
@ -338,6 +340,7 @@ class WC_Shortcodes {
|
|||
'order' => $atts['order'],
|
||||
'posts_per_page' => -1,
|
||||
'meta_query' => WC()->query->get_meta_query(),
|
||||
'tax_query' => WC()->query->get_tax_query(),
|
||||
);
|
||||
|
||||
if ( ! empty( $atts['skus'] ) ) {
|
||||
|
@ -346,16 +349,10 @@ class WC_Shortcodes {
|
|||
'value' => array_map( 'trim', explode( ',', $atts['skus'] ) ),
|
||||
'compare' => 'IN',
|
||||
);
|
||||
|
||||
// Ignore catalog visibility
|
||||
$query_args['meta_query'] = array_merge( $query_args['meta_query'], WC()->query->stock_status_meta_query() );
|
||||
}
|
||||
|
||||
if ( ! empty( $atts['ids'] ) ) {
|
||||
$query_args['post__in'] = array_map( 'trim', explode( ',', $atts['ids'] ) );
|
||||
|
||||
// Ignore catalog visibility
|
||||
$query_args['meta_query'] = array_merge( $query_args['meta_query'], WC()->query->stock_status_meta_query() );
|
||||
}
|
||||
|
||||
return self::product_loop( $query_args, $atts, 'products' );
|
||||
|
@ -380,6 +377,7 @@ class WC_Shortcodes {
|
|||
'no_found_rows' => 1,
|
||||
'post_status' => 'publish',
|
||||
'meta_query' => $meta_query,
|
||||
'tax_query' => WC()->query->get_tax_query(),
|
||||
);
|
||||
|
||||
if ( isset( $atts['sku'] ) ) {
|
||||
|
@ -537,6 +535,7 @@ class WC_Shortcodes {
|
|||
'post_status' => 'publish',
|
||||
'post_type' => 'product',
|
||||
'meta_query' => WC()->query->get_meta_query(),
|
||||
'tax_query' => WC()->query->get_tax_query(),
|
||||
'post__in' => array_merge( array( 0 ), wc_get_product_ids_on_sale() ),
|
||||
);
|
||||
|
||||
|
@ -567,6 +566,7 @@ class WC_Shortcodes {
|
|||
'meta_key' => 'total_sales',
|
||||
'orderby' => 'meta_value_num',
|
||||
'meta_query' => WC()->query->get_meta_query(),
|
||||
'tax_query' => WC()->query->get_tax_query(),
|
||||
);
|
||||
|
||||
$query_args = self::_maybe_add_category_args( $query_args, $atts['category'], $atts['operator'] );
|
||||
|
@ -598,6 +598,7 @@ class WC_Shortcodes {
|
|||
'order' => $atts['order'],
|
||||
'posts_per_page' => $atts['per_page'],
|
||||
'meta_query' => WC()->query->get_meta_query(),
|
||||
'tax_query' => WC()->query->get_tax_query(),
|
||||
);
|
||||
|
||||
$query_args = self::_maybe_add_category_args( $query_args, $atts['category'], $atts['operator'] );
|
||||
|
@ -627,10 +628,13 @@ class WC_Shortcodes {
|
|||
'operator' => 'IN', // Possible values are 'IN', 'NOT IN', 'AND'.
|
||||
), $atts, 'featured_products' );
|
||||
|
||||
$meta_query = WC()->query->get_meta_query();
|
||||
$meta_query[] = array(
|
||||
'key' => '_featured',
|
||||
'value' => 'yes',
|
||||
$meta_query = WC()->query->get_meta_query();
|
||||
$tax_query = WC()->query->get_tax_query();
|
||||
$tax_query[] = array(
|
||||
'taxonomy' => 'product_visibility',
|
||||
'field' => 'name',
|
||||
'terms' => 'featured',
|
||||
'operator' => 'IN',
|
||||
);
|
||||
|
||||
$query_args = array(
|
||||
|
@ -641,6 +645,7 @@ class WC_Shortcodes {
|
|||
'orderby' => $atts['orderby'],
|
||||
'order' => $atts['order'],
|
||||
'meta_query' => $meta_query,
|
||||
'tax_query' => $tax_query,
|
||||
);
|
||||
|
||||
$query_args = self::_maybe_add_category_args( $query_args, $atts['category'], $atts['operator'] );
|
||||
|
@ -795,13 +800,13 @@ class WC_Shortcodes {
|
|||
'orderby' => $atts['orderby'],
|
||||
'order' => $atts['order'],
|
||||
'meta_query' => WC()->query->get_meta_query(),
|
||||
'tax_query' => array(
|
||||
array(
|
||||
'taxonomy' => strstr( $atts['attribute'], 'pa_' ) ? sanitize_title( $atts['attribute'] ) : 'pa_' . sanitize_title( $atts['attribute'] ),
|
||||
'terms' => array_map( 'sanitize_title', explode( ',', $atts['filter'] ) ),
|
||||
'field' => 'slug',
|
||||
),
|
||||
),
|
||||
'tax_query' => WC()->query->get_tax_query(),
|
||||
);
|
||||
|
||||
$query_args['tax_query'][] = array(
|
||||
'taxonomy' => strstr( $atts['attribute'], 'pa_' ) ? sanitize_title( $atts['attribute'] ) : 'pa_' . sanitize_title( $atts['attribute'] ),
|
||||
'terms' => array_map( 'sanitize_title', explode( ',', $atts['filter'] ) ),
|
||||
'field' => 'slug',
|
||||
);
|
||||
|
||||
return self::product_loop( $query_args, $atts, 'product_attribute' );
|
||||
|
@ -840,7 +845,10 @@ class WC_Shortcodes {
|
|||
*/
|
||||
private static function _maybe_add_category_args( $args, $category, $operator ) {
|
||||
if ( ! empty( $category ) ) {
|
||||
$args['tax_query'] = array(
|
||||
if ( empty( $args['tax_query'] ) ) {
|
||||
$args['tax_query'] = array();
|
||||
}
|
||||
$args['tax_query'][] = array(
|
||||
array(
|
||||
'taxonomy' => 'product_cat',
|
||||
'terms' => array_map( 'sanitize_title', explode( ',', $category ) ),
|
||||
|
|
|
@ -132,6 +132,7 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
|
|||
$product->read_meta_data();
|
||||
$this->read_attributes( $product );
|
||||
$this->read_downloads( $product );
|
||||
$this->read_visibility( $product );
|
||||
$this->read_product_data( $product );
|
||||
$product->set_object_read( true );
|
||||
}
|
||||
|
@ -155,6 +156,7 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
|
|||
|
||||
$this->update_post_meta( $product );
|
||||
$this->update_terms( $product );
|
||||
$this->update_visibility( $product );
|
||||
$this->update_attributes( $product );
|
||||
$this->update_downloads( $product );
|
||||
$product->save_meta_data();
|
||||
|
@ -224,8 +226,6 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
|
|||
}
|
||||
|
||||
$product->set_props( array(
|
||||
'featured' => get_post_meta( $id, '_featured', true ),
|
||||
'catalog_visibility' => get_post_meta( $id, '_visibility', true ),
|
||||
'sku' => get_post_meta( $id, '_sku', true ),
|
||||
'regular_price' => get_post_meta( $id, '_regular_price', true ),
|
||||
'sale_price' => get_post_meta( $id, '_sale_price', true ),
|
||||
|
@ -269,6 +269,36 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert visibility terms to props.
|
||||
* Catalog visibility valid values are 'visible', 'catalog', 'search', and 'hidden'.
|
||||
*
|
||||
* @param WC_Product
|
||||
* @since 2.7.0
|
||||
*/
|
||||
protected function read_visibility( &$product ) {
|
||||
$terms = get_the_terms( $product->get_id(), 'product_visibility' );
|
||||
$term_names = is_array( $terms ) ? wp_list_pluck( $terms, 'name' ) : array();
|
||||
$featured = in_array( 'featured', $term_names );
|
||||
$exclude_search = in_array( 'exclude-from-search', $term_names );
|
||||
$exclude_catalog = in_array( 'exclude-from-catalog', $term_names );
|
||||
|
||||
if ( $exclude_search && $exclude_catalog ) {
|
||||
$catalog_visibility = 'hidden';
|
||||
} elseif ( $exclude_search ) {
|
||||
$catalog_visibility = 'catalog';
|
||||
} elseif ( $exclude_catalog ) {
|
||||
$catalog_visibility = 'search';
|
||||
} else {
|
||||
$catalog_visibility = 'visible';
|
||||
}
|
||||
|
||||
$product->set_props( array(
|
||||
'featured' => $featured,
|
||||
'catalog_visibility' => $catalog_visibility,
|
||||
) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Read attributes from post meta.
|
||||
*
|
||||
|
@ -334,7 +364,6 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
|
|||
$updated_props = array();
|
||||
$changed_props = array_keys( $product->get_changes() );
|
||||
$meta_key_to_props = array(
|
||||
'_visibility' => 'catalog_visibility',
|
||||
'_sku' => 'sku',
|
||||
'_regular_price' => 'regular_price',
|
||||
'_sale_price' => 'sale_price',
|
||||
|
@ -359,7 +388,6 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
|
|||
'_product_image_gallery' => 'gallery_image_ids',
|
||||
'_download_limit' => 'download_limit',
|
||||
'_download_expiry' => 'download_expiry',
|
||||
'_featured' => 'featured',
|
||||
'_thumbnail_id' => 'image_id',
|
||||
'_stock' => 'stock_quantity',
|
||||
'_stock_status' => 'stock_status',
|
||||
|
@ -377,7 +405,6 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
|
|||
case 'virtual' :
|
||||
case 'downloadable' :
|
||||
case 'manage_stock' :
|
||||
case 'featured' :
|
||||
case 'sold_individually' :
|
||||
$updated = update_post_meta( $product->get_id(), $meta_key, wc_bool_to_string( $value ) );
|
||||
break;
|
||||
|
@ -411,14 +438,6 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
|
|||
}
|
||||
}
|
||||
|
||||
if ( in_array( 'featured', $updated_props ) ) {
|
||||
delete_transient( 'wc_featured_products' );
|
||||
}
|
||||
|
||||
if ( in_array( 'catalog_visibility', $updated_props ) ) {
|
||||
do_action( 'woocommerce_product_set_visibility', $product->get_id(), $product->get_catalog_visibility() );
|
||||
}
|
||||
|
||||
if ( in_array( 'stock_quantity', $updated_props ) ) {
|
||||
do_action( $product->is_type( 'variation' ) ? 'woocommerce_variation_set_stock' : 'woocommerce_product_set_stock' , $product );
|
||||
}
|
||||
|
@ -451,6 +470,42 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
|
|||
wp_set_post_terms( $product->get_id(), array( $product->get_shipping_class_id( 'edit' ) ), 'product_shipping_class', false );
|
||||
}
|
||||
|
||||
/**
|
||||
* Update visibility terms based on props.
|
||||
*
|
||||
* @param WC_Product
|
||||
* @since 2.7.0
|
||||
*/
|
||||
protected function update_visibility( &$product ) {
|
||||
$terms = array();
|
||||
|
||||
if ( $product->get_featured() ) {
|
||||
$terms[] = 'featured';
|
||||
}
|
||||
|
||||
if ( 'outofstock' === $product->get_stock_status() ) {
|
||||
$terms[] = 'outofstock';
|
||||
}
|
||||
|
||||
switch ( $product->get_catalog_visibility() ) {
|
||||
case 'hidden' :
|
||||
$terms[] = 'exclude-from-search';
|
||||
$terms[] = 'exclude-from-catalog';
|
||||
break;
|
||||
case 'catalog' :
|
||||
$terms[] = 'exclude-from-search';
|
||||
break;
|
||||
case 'search' :
|
||||
$terms[] = 'exclude-from-catalog';
|
||||
break;
|
||||
}
|
||||
|
||||
if ( ! is_wp_error( wp_set_post_terms( $product->get_id(), $terms, 'product_visibility', false ) ) ) {
|
||||
delete_transient( 'wc_featured_products' );
|
||||
do_action( 'woocommerce_product_set_visibility', $product->get_id(), $product->get_catalog_visibility() );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update attributes which are a mix of terms and meta data.
|
||||
*
|
||||
|
@ -604,15 +659,18 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
|
|||
'post_type' => array( 'product', 'product_variation' ),
|
||||
'posts_per_page' => -1,
|
||||
'post_status' => 'publish',
|
||||
'meta_query' => array(
|
||||
'tax_query' => array(
|
||||
'relation' => 'AND',
|
||||
array(
|
||||
'key' => '_visibility',
|
||||
'value' => array( 'catalog', 'visible' ),
|
||||
'compare' => 'IN',
|
||||
'taxonomy' => 'product_visibility',
|
||||
'field' => 'name',
|
||||
'terms' => array( 'featured' ),
|
||||
),
|
||||
array(
|
||||
'key' => '_featured',
|
||||
'value' => 'yes',
|
||||
'taxonomy' => 'product_visibility',
|
||||
'field' => 'name',
|
||||
'terms' => array( 'exclude-from-catalog' ),
|
||||
'operator' => 'NOT IN',
|
||||
),
|
||||
),
|
||||
'fields' => 'id=>parent',
|
||||
|
@ -803,23 +861,20 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
|
|||
$limit = absint( $limit );
|
||||
$query = array();
|
||||
$query['fields'] = "SELECT DISTINCT ID FROM {$wpdb->posts} p";
|
||||
$query['join'] = " INNER JOIN {$wpdb->postmeta} pm ON ( pm.post_id = p.ID AND pm.meta_key='_visibility' )";
|
||||
$query['join'] .= " INNER JOIN {$wpdb->term_relationships} tr ON (p.ID = tr.object_id)";
|
||||
$query['join'] = " INNER JOIN {$wpdb->term_relationships} tr ON (p.ID = tr.object_id)";
|
||||
$query['join'] .= " INNER JOIN {$wpdb->term_taxonomy} tt ON (tr.term_taxonomy_id = tt.term_taxonomy_id)";
|
||||
$query['join'] .= " INNER JOIN {$wpdb->terms} t ON (t.term_id = tt.term_id)";
|
||||
|
||||
if ( 'yes' === get_option( 'woocommerce_hide_out_of_stock_items' ) ) {
|
||||
$query['join'] .= " INNER JOIN {$wpdb->postmeta} pm2 ON ( pm2.post_id = p.ID AND pm2.meta_key='_stock_status' )";
|
||||
}
|
||||
|
||||
$query['where'] = ' WHERE 1=1';
|
||||
$query['where'] .= " AND p.post_status = 'publish'";
|
||||
$query['where'] .= " AND p.post_type = 'product'";
|
||||
$query['where'] .= " AND p.ID NOT IN ( {$exclude_ids} )";
|
||||
$query['where'] .= " AND pm.meta_value IN ( 'visible', 'catalog' )";
|
||||
|
||||
if ( 'yes' === get_option( 'woocommerce_hide_out_of_stock_items' ) ) {
|
||||
$query['where'] .= " AND pm2.meta_value = 'instock'";
|
||||
if ( $exclude_catalog_term = get_term_by( 'name', 'exclude-from-catalog', 'product_visibility' ) ) {
|
||||
$query['where'] .= " AND t.term_id !=" . absint( $exclude_catalog_term->term_id );
|
||||
}
|
||||
|
||||
if ( 'yes' === get_option( 'woocommerce_hide_out_of_stock_items' ) && ( $outofstock_term = get_term_by( 'name', 'outofstock', 'product_visibility' ) ) ) {
|
||||
$query['where'] .= " AND t.term_id !=" . absint( $outofstock_term->term_id );
|
||||
}
|
||||
|
||||
if ( $cats_array || $tags_array ) {
|
||||
|
|
|
@ -55,10 +55,11 @@ class WC_Product_Variable_Data_Store_CPT extends WC_Product_Data_Store_CPT imple
|
|||
'numberposts' => -1,
|
||||
);
|
||||
if ( 'yes' === get_option( 'woocommerce_hide_out_of_stock_items' ) ) {
|
||||
$visible_only_args['meta_query'][] = array(
|
||||
'key' => '_stock_status',
|
||||
'value' => 'instock',
|
||||
'compare' => '=',
|
||||
$visible_only_args['tax_query'][] = array(
|
||||
'taxonomy' => 'product_visibility',
|
||||
'field' => 'name',
|
||||
'terms' => 'outofstock',
|
||||
'operator' => 'NOT IN',
|
||||
);
|
||||
}
|
||||
$children['all'] = get_posts( apply_filters( 'woocommerce_variable_children_args', $all_args, $product, false ) );
|
||||
|
|
|
@ -687,7 +687,7 @@ function wc_get_product_attachment_props( $attachment_id, $product = false ) {
|
|||
*/
|
||||
function wc_get_product_visibility_options() {
|
||||
return apply_filters( 'woocommerce_product_visibility_options', array(
|
||||
'visible' => __( 'Catalog/search', 'woocommerce' ),
|
||||
'visible' => __( 'Visible', 'woocommerce' ),
|
||||
'catalog' => __( 'Catalog', 'woocommerce' ),
|
||||
'search' => __( 'Search', 'woocommerce' ),
|
||||
'hidden' => __( 'Hidden', 'woocommerce' ),
|
||||
|
|
|
@ -550,31 +550,23 @@ function _wc_term_recount( $terms, $taxonomy, $callback = true, $terms_are_term_
|
|||
_update_post_term_count( $terms, $taxonomy );
|
||||
}
|
||||
|
||||
// Stock query
|
||||
if ( 'yes' === get_option( 'woocommerce_hide_out_of_stock_items' ) ) {
|
||||
$stock_join = "LEFT JOIN {$wpdb->postmeta} AS meta_stock ON posts.ID = meta_stock.post_id";
|
||||
$stock_query = "
|
||||
AND meta_stock.meta_key = '_stock_status'
|
||||
AND meta_stock.meta_value = 'instock'
|
||||
";
|
||||
} else {
|
||||
$stock_query = $stock_join = '';
|
||||
}
|
||||
|
||||
// Main query
|
||||
$count_query = "
|
||||
SELECT COUNT( DISTINCT posts.ID ) FROM {$wpdb->posts} as posts
|
||||
LEFT JOIN {$wpdb->postmeta} AS meta_visibility ON posts.ID = meta_visibility.post_id
|
||||
LEFT JOIN {$wpdb->term_relationships} AS rel ON posts.ID=rel.object_ID
|
||||
LEFT JOIN {$wpdb->term_taxonomy} AS tax USING( term_taxonomy_id )
|
||||
$stock_join
|
||||
WHERE post_status = 'publish'
|
||||
AND post_type = 'product'
|
||||
AND meta_visibility.meta_key = '_visibility'
|
||||
AND meta_visibility.meta_value IN ( 'visible', 'catalog' )
|
||||
$stock_query
|
||||
";
|
||||
|
||||
if ( $exclude_catalog_term = get_term_by( 'name', 'exclude-from-catalog', 'product_visibility' ) ) {
|
||||
$count_query .= "AND term_id !=" . absint( $exclude_catalog_term->term_id );
|
||||
}
|
||||
|
||||
if ( 'yes' === get_option( 'woocommerce_hide_out_of_stock_items' ) && ( $outofstock_term = get_term_by( 'name', 'outofstock', 'product_visibility' ) ) ) {
|
||||
$count_query .= "AND term_id !=" . absint( $outofstock_term->term_id );
|
||||
}
|
||||
|
||||
// Pre-process term taxonomy ids
|
||||
if ( ! $terms_are_term_taxonomy_ids ) {
|
||||
// We passed in an array of TERMS in format id=>parent
|
||||
|
@ -634,8 +626,9 @@ function _wc_term_recount( $terms, $taxonomy, $callback = true, $terms_are_term_
|
|||
* @param int $product_id
|
||||
*/
|
||||
function wc_recount_after_stock_change( $product_id ) {
|
||||
if ( get_option( 'woocommerce_hide_out_of_stock_items' ) != 'yes' )
|
||||
if ( 'yes' !== get_option( 'woocommerce_hide_out_of_stock_items' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$product_terms = get_the_terms( $product_id, 'product_cat' );
|
||||
|
||||
|
|
|
@ -1027,3 +1027,31 @@ function wc_update_270_settings() {
|
|||
update_option( 'woocommerce_shipping_tax_class', '' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert meta values into term for product visibility.
|
||||
*/
|
||||
function wc_update_270_product_visibility() {
|
||||
global $wpdb;
|
||||
|
||||
$featured_term = get_term_by( 'name', 'featured', 'product_visibility' );
|
||||
$exclude_search_term = get_term_by( 'name', 'exclude-from-search', 'product_visibility' );
|
||||
$exclude_catalog_term = get_term_by( 'name', 'exclude-from-catalog', 'product_visibility' );
|
||||
$outofstock_term = get_term_by( 'name', 'out-of-stock', 'product_visibility' );
|
||||
|
||||
if ( $featured_term ) {
|
||||
$wpdb->query( $wpdb->prepare( "INSERT INTO {$wpdb->term_relationships} SELECT post_id, %d, 0 FROM {$wpdb->postmeta} WHERE meta_key = '_featured' AND meta_value = 'yes';", $featured_term->term_id ) );
|
||||
}
|
||||
|
||||
if ( $exclude_search_term ) {
|
||||
$wpdb->query( $wpdb->prepare( "INSERT INTO {$wpdb->term_relationships} SELECT post_id, %d, 0 FROM {$wpdb->postmeta} WHERE meta_key = '_visibility' AND meta_value IN ('hidden', 'catalog');", $exclude_search_term->term_id ) );
|
||||
}
|
||||
|
||||
if ( $exclude_catalog_term ) {
|
||||
$wpdb->query( $wpdb->prepare( "INSERT INTO {$wpdb->term_relationships} SELECT post_id, %d, 0 FROM {$wpdb->postmeta} WHERE meta_key = '_visibility' AND meta_value IN ('hidden', 'search');", $exclude_catalog_term->term_id ) );
|
||||
}
|
||||
|
||||
if ( $outofstock_term ) {
|
||||
$wpdb->query( $wpdb->prepare( "INSERT INTO {$wpdb->term_relationships} SELECT post_id, %d, 0 FROM {$wpdb->postmeta} WHERE meta_key = '_stock_status' AND meta_value IN 'outofstock';", $outofstock_term->term_id ) );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -345,7 +345,7 @@ class WC_Widget_Layered_Nav extends WC_Widget {
|
|||
|
||||
if ( 'or' === $query_type ) {
|
||||
foreach ( $tax_query as $key => $query ) {
|
||||
if ( $taxonomy === $query['taxonomy'] ) {
|
||||
if ( is_array( $query ) && $taxonomy === $query['taxonomy'] ) {
|
||||
unset( $tax_query[ $key ] );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -101,10 +101,18 @@ class WC_Widget_Products extends WC_Widget {
|
|||
'no_found_rows' => 1,
|
||||
'order' => $order,
|
||||
'meta_query' => array(),
|
||||
'tax_query' => array(
|
||||
'relation' => 'AND',
|
||||
),
|
||||
);
|
||||
|
||||
if ( empty( $instance['show_hidden'] ) ) {
|
||||
$query_args['meta_query'][] = WC()->query->visibility_meta_query();
|
||||
$query_args['tax_query'][] = array(
|
||||
'taxonomy' => 'product_visibility',
|
||||
'field' => 'name',
|
||||
'terms' => is_search() ? 'exclude-from-search' : 'exclude-from-catalog',
|
||||
'operator' => 'NOT IN',
|
||||
);
|
||||
$query_args['post_parent'] = 0;
|
||||
}
|
||||
|
||||
|
@ -117,14 +125,23 @@ class WC_Widget_Products extends WC_Widget {
|
|||
);
|
||||
}
|
||||
|
||||
$query_args['meta_query'][] = WC()->query->stock_status_meta_query();
|
||||
$query_args['meta_query'] = array_filter( $query_args['meta_query'] );
|
||||
if ( 'yes' === get_option( 'woocommerce_hide_out_of_stock_items' ) ) {
|
||||
$query_args['tax_query'] = array(
|
||||
array(
|
||||
'taxonomy' => 'product_visibility',
|
||||
'field' => 'name',
|
||||
'terms' => 'outofstock',
|
||||
'operator' => 'NOT IN',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
switch ( $show ) {
|
||||
case 'featured' :
|
||||
$query_args['meta_query'][] = array(
|
||||
'key' => '_featured',
|
||||
'value' => 'yes',
|
||||
$query_args['tax_query'][] = array(
|
||||
'taxonomy' => 'product_visibility',
|
||||
'field' => 'name',
|
||||
'terms' => 'featured',
|
||||
);
|
||||
break;
|
||||
case 'onsale' :
|
||||
|
|
|
@ -63,11 +63,25 @@ class WC_Widget_Recently_Viewed extends WC_Widget {
|
|||
|
||||
$number = ! empty( $instance['number'] ) ? absint( $instance['number'] ) : $this->settings['number']['std'];
|
||||
|
||||
$query_args = array( 'posts_per_page' => $number, 'no_found_rows' => 1, 'post_status' => 'publish', 'post_type' => 'product', 'post__in' => $viewed_products, 'orderby' => 'post__in' );
|
||||
$query_args = array(
|
||||
'posts_per_page' => $number,
|
||||
'no_found_rows' => 1,
|
||||
'post_status' => 'publish',
|
||||
'post_type' => 'product',
|
||||
'post__in' => $viewed_products,
|
||||
'orderby' => 'post__in',
|
||||
);
|
||||
|
||||
$query_args['meta_query'] = array();
|
||||
$query_args['meta_query'][] = WC()->query->stock_status_meta_query();
|
||||
$query_args['meta_query'] = array_filter( $query_args['meta_query'] );
|
||||
if ( 'yes' === get_option( 'woocommerce_hide_out_of_stock_items' ) ) {
|
||||
$query_args['tax_query'] = array(
|
||||
array(
|
||||
'taxonomy' => 'product_visibility',
|
||||
'field' => 'name',
|
||||
'terms' => 'outofstock',
|
||||
'operator' => 'NOT IN',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
$r = new WP_Query( $query_args );
|
||||
|
||||
|
|
|
@ -70,10 +70,10 @@ class WC_Widget_Top_Rated_Products extends WC_Widget {
|
|||
'meta_key' => '_wc_average_rating',
|
||||
'orderby' => 'meta_value_num',
|
||||
'order' => 'DESC',
|
||||
'meta_query' => WC()->query->get_meta_query(),
|
||||
'tax_query' => WC()->query->get_tax_query(),
|
||||
);
|
||||
|
||||
$query_args['meta_query'] = WC()->query->get_meta_query();
|
||||
|
||||
$r = new WP_Query( $query_args );
|
||||
|
||||
if ( $r->have_posts() ) {
|
||||
|
|
|
@ -188,6 +188,8 @@ Yes you can! Join in on our [GitHub repository](http://github.com/woocommerce/wo
|
|||
* Added tool to clear orphaned variations in system status.
|
||||
* Remove checkbox options in system status tools and replace with constants.
|
||||
* Added security section in system status report.
|
||||
* Performance - Converted _featured and _visibility meta data to terms for faster catalog queries. Upgrade routine handles migration. Developers may need to update queries to reflect this change.
|
||||
* Performance - Added visibility term for outofstock products to speed those queries up also.
|
||||
* Performance - Introduced a new CRUD (create, read, update, delete) system for Products, Orders, Customers and Shipping Zones.
|
||||
* Performance - Optimised variable product sync. Upper/lower price meta is no longer stored, just the main prices, if a child has weight, and if a child has dimensions.
|
||||
* Performance - Removed WP_Query from up-sells.php and related.php and replaced with PHP foreach loop (since we already have the product IDs).
|
||||
|
|
|
@ -39,7 +39,6 @@ class WC_Helper_Product {
|
|||
update_post_meta( $product, '_tax_status', 'taxable' );
|
||||
update_post_meta( $product, '_downloadable', 'no' );
|
||||
update_post_meta( $product, '_virtual', 'no' );
|
||||
update_post_meta( $product, '_visibility', 'visible' );
|
||||
update_post_meta( $product, '_stock_status', 'instock' );
|
||||
wp_set_object_terms( $product, 'simple', 'product_type' );
|
||||
|
||||
|
@ -93,7 +92,6 @@ class WC_Helper_Product {
|
|||
update_post_meta( $product, '_tax_status', 'taxable' );
|
||||
update_post_meta( $product, '_downloadable', 'no' );
|
||||
update_post_meta( $product, '_virtual', 'no' );
|
||||
update_post_meta( $product, '_visibility', 'visible' );
|
||||
update_post_meta( $product, '_stock_status', 'instock' );
|
||||
wp_set_object_terms( $product, 'grouped', 'product_type' );
|
||||
|
||||
|
@ -136,7 +134,6 @@ class WC_Helper_Product {
|
|||
update_post_meta( $product_id, '_tax_status', 'taxable' );
|
||||
update_post_meta( $product_id, '_downloadable', 'no' );
|
||||
update_post_meta( $product_id, '_virtual', 'no' );
|
||||
update_post_meta( $product_id, '_visibility', 'visible' );
|
||||
update_post_meta( $product_id, '_stock_status', 'instock' );
|
||||
|
||||
// Attributes
|
||||
|
|
|
@ -157,7 +157,6 @@ class WC_Tests_Product_Functions extends WC_Unit_Test_Case {
|
|||
update_post_meta( $product->get_id(), '_regular_price', wc_format_decimal( 10 ) );
|
||||
update_post_meta( $product->get_id(), '_price', wc_format_decimal( 5 ) );
|
||||
update_post_meta( $product->get_id(), '_sale_price', wc_format_decimal( 5 ) );
|
||||
update_post_meta( $product->get_id(), '_featured', 'yes' );
|
||||
|
||||
wc_get_product_ids_on_sale(); // Creates the transient for on sale products
|
||||
wc_get_featured_product_ids(); // Creates the transient for featured products
|
||||
|
@ -205,8 +204,8 @@ class WC_Tests_Product_Functions extends WC_Unit_Test_Case {
|
|||
|
||||
// Create product
|
||||
$product = WC_Helper_Product::create_simple_product();
|
||||
|
||||
update_post_meta( $product->get_id(), '_featured', 'yes' );
|
||||
$product->set_featured( true );
|
||||
$product->save();
|
||||
|
||||
$this->assertEquals( array( $product->get_id() ), wc_get_featured_product_ids() );
|
||||
|
||||
|
|
Loading…
Reference in New Issue