Add related product functions and deprecate those in class.

This commit is contained in:
Mike Jolley 2016-10-17 15:57:09 +01:00
parent a74de70dc3
commit 803709cb94
4 changed files with 151 additions and 130 deletions

View File

@ -21,6 +21,36 @@ if ( ! defined( 'ABSPATH' ) ) {
*/
abstract class WC_Abstract_Legacy_Product extends WC_Data {
/**
* Get and return related products.
* @deprecated 2.7.0 Use wc_get_related_products instead.
*/
public function get_related( $limit = 5 ) {
_deprecated_function( 'WC_Product::get_related', '2.7', 'wc_get_related_products' );
return wc_get_related_products( $this->get_id(), $limit );
}
/**
* Retrieves related product terms.
* @deprecated 2.7.0 Use wc_get_related_terms instead.
*/
protected function get_related_terms( $term ) {
_deprecated_function( 'WC_Product::get_related_terms', '2.7', 'wc_get_related_terms' );
return array_merge( array( 0 ), wc_get_related_terms( $this->get_id(), $term ) );
}
/**
* Builds the related posts query.
* @deprecated 2.7.0 Use wc_get_related_products_query instead.
*/
protected function build_related_query( $cats_array, $tags_array, $exclude_ids, $limit ) {
_deprecated_function( 'WC_Product::build_related_query', '2.7', 'wc_get_related_products_query' );
return wc_get_related_products_query( $cats_array, $tags_array, $exclude_ids, $limit );
}
/**
* The product's type (simple, variable etc).
*

View File

@ -2074,57 +2074,6 @@ class WC_Product extends WC_Abstract_Legacy_Product {
return absint( $this->shipping_class_id );
}
/**
* Get and return related products.
*
* Notes:
* - Results are cached in a transient for faster queries.
* - To make results appear random, we query and extra 10 products and shuffle them.
* - To ensure we always have enough results, it will check $limit before returning the cached result, if not recalc.
* - This used to rely on transient version to invalidate cache, but to avoid multiple transients we now just expire daily.
* This means if a related product is edited and no longer related, it won't be removed for 24 hours. Acceptable trade-off for performance.
* - Saving a product will flush caches for that product.
*
* @param int $limit (default: 5) Should be an integer greater than 0.
* @return array Array of post IDs
*/
public function get_related( $limit = 5 ) {
global $wpdb;
$transient_name = 'wc_related_' . $this->get_id();
$related_posts = get_transient( $transient_name );
$limit = $limit > 0 ? $limit : 5;
// We want to query related posts if they are not cached, or we don't have enough
if ( false === $related_posts || sizeof( $related_posts ) < $limit ) {
// Related products are found from category and tag
$tags_array = $this->get_related_terms( 'product_tag' );
$cats_array = $this->get_related_terms( 'product_cat' );
// Don't bother if none are set
if ( 1 === sizeof( $cats_array ) && 1 === sizeof( $tags_array ) ) {
$related_posts = array();
} else {
// Sanitize
$exclude_ids = array_map( 'absint', array_merge( array( 0, $this->get_id() ), $this->get_upsells() ) );
// Generate query - but query an extra 10 results to give the appearance of random results
$query = $this->build_related_query( $cats_array, $tags_array, $exclude_ids, $limit + 10 );
// Get the posts
$related_posts = $wpdb->get_col( implode( ' ', $query ) );
}
set_transient( $transient_name, $related_posts, DAY_IN_SECONDS );
}
// Randomise the results
shuffle( $related_posts );
// Limit the returned results
return array_slice( $related_posts, 0, $limit );
}
/**
* Returns a single product attribute.
*
@ -2301,84 +2250,6 @@ class WC_Product extends WC_Abstract_Legacy_Product {
return sprintf( '%s &ndash; %s', $identifier, $this->get_title() );
}
/**
* Retrieves related product terms.
*
* @param string $term
* @return array
*/
protected function get_related_terms( $term ) {
$terms_array = array( 0 );
$terms = apply_filters( 'woocommerce_get_related_' . $term . '_terms', wp_get_post_terms( $this->get_id(), $term ), $this->get_id() );
foreach ( $terms as $term ) {
$terms_array[] = $term->term_id;
}
return array_map( 'absint', $terms_array );
}
/**
* Builds the related posts query.
*
* @param array $cats_array
* @param array $tags_array
* @param array $exclude_ids
* @param int $limit
* @return string
*/
protected function build_related_query( $cats_array, $tags_array, $exclude_ids, $limit ) {
global $wpdb;
$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_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 ( get_option( 'woocommerce_hide_out_of_stock_items' ) === 'yes' ) {
$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 ( " . implode( ',', $exclude_ids ) . " )";
$query['where'] .= " AND pm.meta_value IN ( 'visible', 'catalog' )";
if ( get_option( 'woocommerce_hide_out_of_stock_items' ) === 'yes' ) {
$query['where'] .= " AND pm2.meta_value = 'instock'";
}
$relate_by_category = apply_filters( 'woocommerce_product_related_posts_relate_by_category', true, $this->get_id() );
$relate_by_tag = apply_filters( 'woocommerce_product_related_posts_relate_by_tag', true, $this->get_id() );
if ( $relate_by_category || $relate_by_tag ) {
$query['where'] .= ' AND (';
if ( $relate_by_category ) {
$query['where'] .= " ( tt.taxonomy = 'product_cat' AND t.term_id IN ( " . implode( ',', $cats_array ) . " ) ) ";
if ( $relate_by_tag ) {
$query['where'] .= ' OR ';
}
}
if ( $relate_by_tag ) {
$query['where'] .= " ( tt.taxonomy = 'product_tag' AND t.term_id IN ( " . implode( ',', $tags_array ) . " ) ) ";
}
$query['where'] .= ')';
}
$query['limits'] = " LIMIT {$limit} ";
$query = apply_filters( 'woocommerce_product_related_posts_query', $query, $this->get_id() );
return $query;
}
/**
* Save taxonomy terms.
*

View File

@ -751,3 +751,123 @@ function wc_get_product_visibility_options() {
'hidden' => __( 'Hidden', 'woocommerce' ),
) );
}
/**
* Get relateed products.
* @param integer $product_id
* @param integer $limit
* @param array $exclude_ids
* @return array
*/
function wc_get_related_products( $product_id, $limit = 5, $exclude_ids = array() ) {
global $wpdb;
$product_id = absint( $product_id );
$exclude_ids = array_map( 'absint', array_merge( array( 0, $product_id ), $exclude_ids ) );
$transient_name = 'wc_related_' . $product_id;
$related_posts = get_transient( $transient_name );
$limit = $limit > 0 ? $limit : 5;
// We want to query related posts if they are not cached, or we don't have enough
if ( false === $related_posts || sizeof( $related_posts ) < $limit ) {
// Related products are found from category and tags
if ( apply_filters( 'woocommerce_product_related_posts_relate_by_category', true, $product_id ) ) {
$cats_array = wc_get_related_terms( $product_id, 'product_cat' );
} else {
$cats_array = array();
}
if ( apply_filters( 'woocommerce_product_related_posts_relate_by_tag', true, $product_id ) ) {
$tags_array = wc_get_related_terms( $product_id, 'product_tag' );
} else {
$tags_array = array();
}
// Don't bother if none are set, unless woocommerce_product_related_posts_force_display is set to true in which case all products are related.
if ( empty( $cats_array ) && empty( $tags_array ) && ! apply_filters( 'woocommerce_product_related_posts_force_display', false, $product_id ) ) {
$related_posts = array();
} else {
// Generate query - but query an extra 10 results to give the appearance of random results
$query = apply_filters( 'woocommerce_product_related_posts_query', wc_get_related_products_query( $cats_array, $tags_array, $exclude_ids, $limit + 10 ), $product_id );
// Get the posts
$related_posts = $wpdb->get_col( implode( ' ', $query ) );
}
set_transient( $transient_name, $related_posts, DAY_IN_SECONDS );
}
// Randomise the results
shuffle( $related_posts );
// Limit the returned results
return array_slice( $related_posts, 0, $limit );
}
/**
* Retrieves related product terms.
* @since 2.7.0
* @param integer $product_id
* @param string $taxonomy
* @return array
*/
function wc_get_related_terms( $product_id, $taxonomy ) {
$terms = apply_filters( 'woocommerce_get_related_' . $taxonomy . '_terms', wp_get_post_terms( $product_id, $term ), $product_id );
return array_map( 'absint', wp_list_pluck( $terms, 'term_id' ) );
}
/**
* Builds the related posts query.
*
* @param array $cats_array
* @param array $tags_array
* @param array $exclude_ids
* @param int $limit
* @return string
*/
function wc_get_related_products_query( $cats_array, $tags_array, $exclude_ids, $limit ) {
global $wpdb;
$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_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 ( " . implode( ',', $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 ( $cats_array || $tags_array ) {
$query['where'] .= ' AND (';
if ( $cats_array ) {
$query['where'] .= " ( tt.taxonomy = 'product_cat' AND t.term_id IN ( " . implode( ',', $cats_array ) . " ) ) ";
if ( $relate_by_tag ) {
$query['where'] .= ' OR ';
}
}
if ( $tags_array ) {
$query['where'] .= " ( tt.taxonomy = 'product_tag' AND t.term_id IN ( " . implode( ',', $tags_array ) . " ) ) ";
}
$query['where'] .= ')';
}
$query['limits'] = " LIMIT {$limit} ";
return $query;
}

View File

@ -26,7 +26,7 @@ if ( empty( $product ) || ! $product->exists() ) {
return;
}
if ( ! $related = $product->get_related( $posts_per_page ) ) {
if ( ! $related = wc_get_related_products( $product->get_id(), $posts_per_page, $product->get_upsells() ) ) {
return;
}