File "class-wc-brands.php"
Full Path: /home/siazco/grocery.siazco.se/wp-content/plugins/woocommerce/includes/class-wc-brands.php
File size: 30.49 KB
MIME-type: text/x-php
Charset: utf-8
<?php
declare( strict_types = 1);
use Automattic\Jetpack\Constants;
/**
* WC_Brands class.
*
* Important: For internal use only by the Automattic\WooCommerce\Internal\Brands package.
*
* @version 9.4.0
*/
class WC_Brands {
/**
* Template URL -- filterable.
*
* @var mixed|null
*/
public $template_url;
/**
* __construct function.
*/
public function __construct() {
$this->template_url = apply_filters( 'woocommerce_template_url', 'woocommerce/' ); // phpcs:ignore WooCommerce.Commenting.CommentHooks.MissingHookComment
add_action( 'plugins_loaded', array( $this, 'register_hooks' ), 11 );
$this->register_shortcodes();
}
/**
* Register our hooks
*/
public function register_hooks() {
add_action( 'woocommerce_register_taxonomy', array( __CLASS__, 'init_taxonomy' ) );
add_action( 'widgets_init', array( $this, 'init_widgets' ) );
if ( ! wc_current_theme_is_fse_theme() ) {
add_filter( 'template_include', array( $this, 'template_loader' ) );
}
add_action( 'wp_enqueue_scripts', array( $this, 'styles' ) );
add_action( 'wp', array( $this, 'body_class' ) );
add_action( 'woocommerce_product_meta_end', array( $this, 'show_brand' ) );
add_filter( 'woocommerce_structured_data_product', array( $this, 'add_structured_data' ), 20 );
// duplicate product brands.
add_action( 'woocommerce_product_duplicate_before_save', array( $this, 'duplicate_store_temporary_brands' ), 10, 2 );
add_action( 'woocommerce_new_product', array( $this, 'duplicate_add_product_brand_terms' ) );
add_action( 'woocommerce_new_product', array( $this, 'invalidate_wc_layered_nav_counts_cache' ), 10, 0 );
add_action( 'woocommerce_update_product', array( $this, 'invalidate_wc_layered_nav_counts_cache' ), 10, 0 );
add_action( 'transition_post_status', array( $this, 'reset_layered_nav_counts_on_status_change' ), 10, 3 );
add_filter( 'post_type_link', array( $this, 'post_type_link' ), 11, 2 );
if ( 'yes' === get_option( 'wc_brands_show_description' ) ) {
add_action( 'woocommerce_archive_description', array( $this, 'brand_description' ) );
}
add_filter( 'woocommerce_product_query_tax_query', array( $this, 'update_product_query_tax_query' ), 10, 1 );
// REST API.
add_action( 'rest_api_init', array( $this, 'rest_api_register_routes' ) );
add_action( 'woocommerce_rest_insert_product', array( $this, 'rest_api_maybe_set_brands' ), 10, 2 );
add_filter( 'woocommerce_rest_prepare_product', array( $this, 'rest_api_prepare_brands_to_product' ), 10, 2 ); // WC 2.6.x.
add_filter( 'woocommerce_rest_prepare_product_object', array( $this, 'rest_api_prepare_brands_to_product' ), 10, 2 ); // WC 3.x.
add_action( 'woocommerce_rest_insert_product', array( $this, 'rest_api_add_brands_to_product' ), 10, 3 ); // WC 2.6.x.
add_action( 'woocommerce_rest_insert_product_object', array( $this, 'rest_api_add_brands_to_product' ), 10, 3 ); // WC 3.x.
add_filter( 'woocommerce_rest_product_object_query', array( $this, 'rest_api_filter_products_by_brand' ), 10, 2 );
add_filter( 'rest_product_collection_params', array( $this, 'rest_api_product_collection_params' ), 10, 2 );
// Layered nav widget compatibility.
add_filter( 'woocommerce_layered_nav_term_html', array( $this, 'woocommerce_brands_update_layered_nav_link' ), 10, 4 );
// Filter the list of taxonomies overridden for the original term count.
add_filter( 'woocommerce_change_term_counts', array( $this, 'add_brands_to_terms' ) );
add_action( 'woocommerce_product_set_stock_status', array( $this, 'recount_after_stock_change' ) );
add_action( 'woocommerce_update_options_products_inventory', array( $this, 'recount_all_brands' ) );
// Product Editor compatibility.
add_action( 'woocommerce_layout_template_after_instantiation', array( $this, 'wc_brands_on_block_template_register' ), 10, 3 );
}
/**
* Add product_brand to the taxonomies overridden for the original term count.
*
* @param array $taxonomies List of taxonomies.
*
* @return array
*/
public function add_brands_to_terms( $taxonomies ) {
$taxonomies[] = 'product_brand';
return $taxonomies;
}
/**
* Recount the brands after the stock amount changes.
*
* @param int $product_id Product ID.
*/
public function recount_after_stock_change( $product_id ) {
if ( 'yes' !== get_option( 'woocommerce_hide_out_of_stock_items' ) || empty( $product_id ) ) {
return;
}
$product_terms = get_the_terms( $product_id, 'product_brand' );
if ( $product_terms ) {
$product_brands = array();
foreach ( $product_terms as $term ) {
$product_brands[ $term->term_id ] = $term->parent;
}
_wc_term_recount( $product_brands, get_taxonomy( 'product_brand' ), false, false );
}
}
/**
* Recount all brands.
*/
public function recount_all_brands() {
$product_brands = get_terms(
array(
'taxonomy' => 'product_brand',
'hide_empty' => false,
'fields' => 'id=>parent',
)
);
_wc_term_recount( $product_brands, get_taxonomy( 'product_brand' ), true, false );
}
/**
* Update the main product fetch query to filter by selected brands.
*
* @param array $tax_query array of current taxonomy filters.
*
* @return array
*/
public function update_product_query_tax_query( array $tax_query ) {
if ( isset( $_GET['filter_product_brand'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
$filter_product_brand = wc_clean( wp_unslash( $_GET['filter_product_brand'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
$brands_filter = array_filter( array_map( 'absint', explode( ',', $filter_product_brand ) ) );
if ( $brands_filter ) {
$tax_query[] = array(
'taxonomy' => 'product_brand',
'terms' => $brands_filter,
'operator' => 'IN',
);
}
}
return $tax_query;
}
/**
* Filter to allow product_brand in the permalinks for products.
*
* @param string $permalink The existing permalink URL.
* @param WP_Post $post The post.
* @return string
*/
public function post_type_link( $permalink, $post ) {
// Abort if post is not a product.
if ( 'product' !== $post->post_type ) {
return $permalink;
}
// Abort early if the placeholder rewrite tag isn't in the generated URL.
if ( false === strpos( $permalink, '%' ) ) {
return $permalink;
}
// Get the custom taxonomy terms in use by this post.
$terms = get_the_terms( $post->ID, 'product_brand' );
if ( empty( $terms ) ) {
// If no terms are assigned to this post, use a string instead (can't leave the placeholder there).
$product_brand = _x( 'uncategorized', 'slug', 'woocommerce' );
} else {
// Replace the placeholder rewrite tag with the first term's slug.
$first_term = array_shift( $terms );
$product_brand = $first_term->slug;
}
$find = array(
'%product_brand%',
);
$replace = array(
$product_brand,
);
$replace = array_map( 'sanitize_title', $replace );
$permalink = str_replace( $find, $replace, $permalink );
return $permalink;
}
/**
* Adds filter for introducing CSS classes.
*/
public function body_class() {
if ( is_tax( 'product_brand' ) ) {
add_filter( 'body_class', array( $this, 'add_body_class' ) );
}
}
/**
* Adds classes to brand taxonomy pages.
*
* @param array $classes Classes array.
*/
public function add_body_class( $classes ) {
$classes[] = 'woocommerce';
$classes[] = 'woocommerce-page';
return $classes;
}
/**
* Enqueues styles.
*/
public function styles() {
$version = Constants::get_constant( 'WC_VERSION' );
wp_enqueue_style( 'brands-styles', WC()->plugin_url() . '/assets/css/brands.css', array(), $version );
}
/**
* Initializes brand taxonomy.
*/
public static function init_taxonomy() {
$shop_page_id = wc_get_page_id( 'shop' );
$base_slug = $shop_page_id > 0 && get_page( $shop_page_id ) ? get_page_uri( $shop_page_id ) : 'shop';
$category_base = get_option( 'woocommerce_prepend_shop_page_to_urls' ) === 'yes' ? trailingslashit( $base_slug ) : '';
$slug = $category_base . __( 'brand', 'woocommerce' );
if ( '' === $category_base ) {
$slug = get_option( 'woocommerce_brand_permalink', '' );
}
// Can't provide transatable string as get_option default.
if ( '' === $slug ) {
$slug = __( 'brand', 'woocommerce' );
}
register_taxonomy(
'product_brand',
array( 'product' ),
/**
* Filter the brand taxonomy.
*
* @since 9.4.0
*
* @param array $args Args.
*/
apply_filters(
'register_taxonomy_product_brand',
array(
'hierarchical' => true,
'update_count_callback' => '_update_post_term_count',
'label' => __( 'Brands', 'woocommerce' ),
'labels' => array(
'name' => __( 'Brands', 'woocommerce' ),
'singular_name' => __( 'Brand', 'woocommerce' ),
'search_items' => __( 'Search Brands', 'woocommerce' ),
'all_items' => __( 'All Brands', 'woocommerce' ),
'parent_item' => __( 'Parent Brand', 'woocommerce' ),
'parent_item_colon' => __( 'Parent Brand:', 'woocommerce' ),
'edit_item' => __( 'Edit Brand', 'woocommerce' ),
'update_item' => __( 'Update Brand', 'woocommerce' ),
'add_new_item' => __( 'Add New Brand', 'woocommerce' ),
'new_item_name' => __( 'New Brand Name', 'woocommerce' ),
'not_found' => __( 'No Brands Found', 'woocommerce' ),
'back_to_items' => __( '← Go to Brands', 'woocommerce' ),
),
'show_ui' => true,
'show_admin_column' => true,
'show_in_nav_menus' => true,
'show_in_rest' => true,
'capabilities' => array(
'manage_terms' => 'manage_product_terms',
'edit_terms' => 'edit_product_terms',
'delete_terms' => 'delete_product_terms',
'assign_terms' => 'assign_product_terms',
),
'rewrite' => array(
'slug' => $slug,
'with_front' => false,
'hierarchical' => true,
),
)
)
);
}
/**
* Initializes brand widgets.
*/
public function init_widgets() {
// Include.
require_once WC()->plugin_path() . '/includes/widgets/class-wc-widget-brand-description.php';
require_once WC()->plugin_path() . '/includes/widgets/class-wc-widget-brand-nav.php';
require_once WC()->plugin_path() . '/includes/widgets/class-wc-widget-brand-thumbnails.php';
// Register.
register_widget( 'WC_Widget_Brand_Description' );
register_widget( 'WC_Widget_Brand_Nav' );
register_widget( 'WC_Widget_Brand_Thumbnails' );
}
/**
*
* Handles template usage so that we can use our own templates instead of the themes.
*
* Templates are in the 'templates' folder. woocommerce looks for theme
* overides in /theme/woocommerce/ by default
*
* For beginners, it also looks for a woocommerce.php template first. If the user adds
* this to the theme (containing a woocommerce() inside) this will be used for all
* woocommerce templates.
*
* @param string $template Template.
*/
public function template_loader( $template ) {
$find = array( 'woocommerce.php' );
$file = '';
if ( is_tax( 'product_brand' ) ) {
$term = get_queried_object();
$file = 'taxonomy-' . $term->taxonomy . '.php';
$find[] = 'taxonomy-' . $term->taxonomy . '-' . $term->slug . '.php';
$find[] = $this->template_url . 'taxonomy-' . $term->taxonomy . '-' . $term->slug . '.php';
$find[] = $file;
$find[] = $this->template_url . $file;
}
if ( $file ) {
$template = locate_template( $find );
if ( ! $template ) {
$template = WC()->plugin_path() . '/templates/brands/' . $file;
}
}
return $template;
}
/**
* Displays brand description.
*/
public function brand_description() {
if ( ! is_tax( 'product_brand' ) ) {
return;
}
if ( ! get_query_var( 'term' ) ) {
return;
}
$thumbnail = '';
$term = get_term_by( 'slug', get_query_var( 'term' ), 'product_brand' );
$thumbnail = wc_get_brand_thumbnail_url( $term->term_id, 'full' );
wc_get_template(
'brand-description.php',
array(
'thumbnail' => $thumbnail,
),
'woocommerce',
WC()->plugin_path() . '/templates/brands/'
);
}
/**
* Displays brand.
*/
public function show_brand() {
global $post;
if ( is_singular( 'product' ) ) {
$terms = get_the_terms( $post->ID, 'product_brand' );
$brand_count = is_array( $terms ) ? count( $terms ) : 0;
$taxonomy = get_taxonomy( 'product_brand' );
$labels = $taxonomy->labels;
/* translators: %s - Label name */
echo wc_get_brands( $post->ID, ', ', ' <span class="posted_in">' . sprintf( _n( '%s: ', '%s: ', $brand_count, 'woocommerce' ), $labels->singular_name, $labels->name ), '</span>' ); // phpcs:ignore WordPress.Security.EscapeOutput
}
}
/**
* Add structured data to product page.
*
* @param array $markup Markup.
* @return array $markup
*/
public function add_structured_data( $markup ) {
global $post;
if ( array_key_exists( 'brand', $markup ) ) {
return $markup;
}
$brands = get_the_terms( $post->ID, 'product_brand' );
if ( ! empty( $brands ) && is_array( $brands ) ) {
// Can only return one brand, so pick the first.
$markup['brand'] = array(
'@type' => 'Brand',
'name' => $brands[0]->name,
);
}
return $markup;
}
/**
* Registers shortcodes.
*/
public function register_shortcodes() {
add_shortcode( 'product_brand', array( $this, 'output_product_brand' ) );
add_shortcode( 'product_brand_thumbnails', array( $this, 'output_product_brand_thumbnails' ) );
add_shortcode( 'product_brand_thumbnails_description', array( $this, 'output_product_brand_thumbnails_description' ) );
add_shortcode( 'product_brand_list', array( $this, 'output_product_brand_list' ) );
add_shortcode( 'brand_products', array( $this, 'output_brand_products' ) );
}
/**
* Displays product brand.
*
* @param array $atts Attributes from the shortcode.
* @return string The generated output.
*/
public function output_product_brand( $atts ) {
global $post;
$args = shortcode_atts(
array(
'width' => '',
'height' => '',
'class' => 'aligncenter',
'post_id' => '',
),
$atts
);
if ( ! $args['post_id'] && ! $post ) {
return '';
}
if ( ! $args['post_id'] ) {
$args['post_id'] = $post->ID;
}
$brands = wp_get_post_terms( $args['post_id'], 'product_brand', array( 'fields' => 'ids' ) );
// Bail early if we don't have any brands registered.
if ( 0 === count( $brands ) ) {
return '';
}
ob_start();
foreach ( $brands as $brand ) {
$thumbnail = wc_get_brand_thumbnail_url( $brand );
if ( empty( $thumbnail ) ) {
continue;
}
$args['thumbnail'] = $thumbnail;
$args['term'] = get_term_by( 'id', $brand, 'product_brand' );
if ( $args['width'] || $args['height'] ) {
$args['width'] = ! empty( $args['width'] ) ? $args['width'] : 'auto';
$args['height'] = ! empty( $args['height'] ) ? $args['height'] : 'auto';
}
wc_get_template(
'shortcodes/single-brand.php',
$args,
'woocommerce',
WC()->plugin_path() . '/templates/brands/'
);
}
return ob_get_clean();
}
/**
* Displays product brand list.
*
* @param array $atts Attributes from the shortcode.
* @return string
*/
public function output_product_brand_list( $atts ) {
$args = shortcode_atts(
array(
'show_top_links' => true,
'show_empty' => true,
'show_empty_brands' => false,
),
$atts
);
$show_top_links = $args['show_top_links'];
$show_empty = $args['show_empty'];
$show_empty_brands = $args['show_empty_brands'];
if ( 'false' === $show_top_links ) {
$show_top_links = false;
}
if ( 'false' === $show_empty ) {
$show_empty = false;
}
if ( 'false' === $show_empty_brands ) {
$show_empty_brands = false;
}
$product_brands = array();
//phpcs:disable
$terms = get_terms( array( 'taxonomy' => 'product_brand', 'hide_empty' => ( $show_empty_brands ? false : true ) ) );
$alphabet = apply_filters( 'woocommerce_brands_list_alphabet', range( 'a', 'z' ) );
$numbers = apply_filters( 'woocommerce_brands_list_numbers', '0-9' );
/**
* Check for empty brands and remove them from the list.
*/
if ( ! $show_empty_brands ) {
$terms = $this->remove_terms_with_empty_products( $terms );
}
foreach ( $terms as $term ) {
$term_letter = $this->get_brand_name_first_character( $term->name );
// Allow a locale to be set for ctype_alpha().
if ( has_filter( 'woocommerce_brands_list_locale' ) ) {
setLocale( LC_CTYPE, apply_filters( 'woocommerce_brands_list_locale', 'en_US.UTF-8' ) );
}
if ( ctype_alpha( $term_letter ) ) {
foreach ( $alphabet as $i ) {
if ( $i == $term_letter ) {
$product_brands[ $i ][] = $term;
break;
}
}
} else {
$product_brands[ $numbers ][] = $term;
}
}
ob_start();
wc_get_template(
'shortcodes/brands-a-z.php',
array(
'terms' => $terms,
'index' => array_merge( $alphabet, array( $numbers ) ),
'product_brands' => $product_brands,
'show_empty' => $show_empty,
'show_top_links' => $show_top_links,
),
'woocommerce',
WC()->plugin_path() . '/templates/brands/'
);
return ob_get_clean();
}
/**
* Get the first letter of the brand name, returning lowercase and without accents.
*
* @param string $name
*
* @return string
* @since 9.4.0
*/
private function get_brand_name_first_character( $name ) {
// Convert to lowercase and remove accents.
$clean_name = strtolower( sanitize_title( $name ) );
// Return the first letter of the name.
return substr( $clean_name, 0, 1 );
}
/**
* Displays brand thumbnails.
*
* @param mixed $atts
* @return void
*/
public function output_product_brand_thumbnails( $atts ) {
$args = shortcode_atts(
array(
'show_empty' => true,
'columns' => 4,
'hide_empty' => 0,
'orderby' => 'name',
'exclude' => '',
'number' => '',
'fluid_columns' => false,
),
$atts
);
$exclude = array_map( 'intval', explode( ',', $args['exclude'] ) );
$order = 'name' === $args['orderby'] ? 'asc' : 'desc';
if ( 'true' === $args['show_empty'] ) {
$hide_empty = false;
} else {
$hide_empty = true;
}
$brands = get_terms(
'product_brand',
array(
'hide_empty' => $hide_empty,
'orderby' => $args['orderby'],
'exclude' => $exclude,
'number' => $args['number'],
'order' => $order,
)
);
if ( ! $brands ) {
return;
}
if ( $hide_empty ) {
$brands = $this->remove_terms_with_empty_products( $brands );
}
ob_start();
wc_get_template(
'widgets/brand-thumbnails.php',
array(
'brands' => $brands,
'columns' => is_numeric( $args['columns'] ) ? intval( $args['columns'] ) : 4,
'fluid_columns' => wp_validate_boolean( $args['fluid_columns'] ),
),
'woocommerce',
WC()->plugin_path() . '/templates/brands/'
);
return ob_get_clean();
}
/**
* Displays brand thumbnails description.
*
* @param mixed $atts
* @return void
*/
public function output_product_brand_thumbnails_description( $atts ) {
$args = shortcode_atts(
array(
'show_empty' => true,
'columns' => 1,
'hide_empty' => 0,
'orderby' => 'name',
'exclude' => '',
'number' => '',
),
$atts
);
$exclude = array_map( 'intval', explode( ',', $args['exclude'] ) );
$order = 'name' === $args['orderby'] ? 'asc' : 'desc';
if ( 'true' === $args['show_empty'] ) {
$hide_empty = false;
} else {
$hide_empty = true;
}
$brands = get_terms(
'product_brand',
array(
'hide_empty' => $args['hide_empty'],
'orderby' => $args['orderby'],
'exclude' => $exclude,
'number' => $args['number'],
'order' => $order,
)
);
if ( ! $brands ) {
return;
}
if ( $hide_empty ) {
$brands = $this->remove_terms_with_empty_products( $brands );
}
ob_start();
wc_get_template(
'widgets/brand-thumbnails-description.php',
array(
'brands' => $brands,
'columns' => $args['columns'],
),
'woocommerce',
WC()->plugin_path() . '/templates/brands/'
);
return ob_get_clean();
}
/**
* Displays brand products.
*
* @param array $atts
* @return string
*/
public function output_brand_products( $atts ) {
if ( empty( $atts['brand'] ) ) {
return '';
}
// Add the brand attributes and query arguments.
add_filter( 'shortcode_atts_brand_products', array( __CLASS__, 'add_brand_products_shortcode_atts' ), 10, 4 );
add_filter( 'woocommerce_shortcode_products_query', array( __CLASS__, 'get_brand_products_query_args' ), 10, 3 );
$shortcode = new WC_Shortcode_Products( $atts, 'brand_products' );
// Remove the brand attributes and query arguments.
remove_filter( 'shortcode_atts_brand_products', array( __CLASS__, 'add_brand_products_shortcode_atts' ), 10 );
remove_filter( 'woocommerce_shortcode_products_query', array( __CLASS__, 'get_brand_products_query_args' ), 10 );
return $shortcode->get_content();
}
/**
* Adds the taxonomy query to the WooCommerce products shortcode query arguments.
*
* @param array $query_args
* @param array $attributes
* @param string $type
*
* @return array
*/
public static function get_brand_products_query_args( $query_args, $attributes, $type ) {
if ( 'brand_products' !== $type || empty( $attributes['brand'] ) ) {
return $query_args;
}
$query_args['tax_query'][] = array(
'taxonomy' => 'product_brand',
'terms' => array_map( 'sanitize_title', explode( ',', $attributes['brand'] ) ),
'field' => 'slug',
'operator' => 'IN',
);
return $query_args;
}
/**
* Adds the "brand" attribute to the list of WooCommerce products shortcode attributes.
*
* @param array $out The output array of shortcode attributes.
* @param array $pairs The supported attributes and their defaults.
* @param array $atts The user defined shortcode attributes.
* @param string $shortcode The shortcode name.
*
* @return array The output array of shortcode attributes.
*/
public static function add_brand_products_shortcode_atts( $out, $pairs, $atts, $shortcode ) {
$out['brand'] = array_key_exists( 'brand', $atts ) ? $atts['brand'] : '';
return $out;
}
/**
* Register REST API route for /products/brands.
*
* @since 9.4.0
*
* @return void
*/
public function rest_api_register_routes() {
require_once WC()->plugin_path() . '/includes/rest-api/Controllers/Version2/class-wc-rest-product-brands-v2-controller.php';
require_once WC()->plugin_path() . '/includes/rest-api/Controllers/Version3/class-wc-rest-product-brands-controller.php';
$controllers = array(
'WC_REST_Product_Brands_V2_Controller',
'WC_REST_Product_Brands_Controller'
);
foreach ( $controllers as $controller ) {
( new $controller() )->register_routes();
}
}
/**
* Maybe set brands when requesting PUT /products/<id>.
*
* @since 9.4.0
*
* @param WP_Post $post Post object
* @param WP_REST_Request $request Request object
*
* @return void
*/
public function rest_api_maybe_set_brands( $post, $request ) {
if ( isset( $request['brands'] ) && is_array( $request['brands'] ) ) {
$terms = array_map( 'absint', $request['brands'] );
wp_set_object_terms( $post->ID, $terms, 'product_brand' );
}
}
/**
* Prepare brands in product response.
*
* @param WP_REST_Response $response The response object.
* @param WP_Post|WC_Data $post Post object or WC object.
* @version 9.4.0
* @return WP_REST_Response
*/
public function rest_api_prepare_brands_to_product( $response, $post ) {
$post_id = is_callable( array( $post, 'get_id' ) ) ? $post->get_id() : ( ! empty( $post->ID ) ? $post->ID : null );
if ( empty( $response->data['brands'] ) ) {
$terms = array();
foreach ( wp_get_post_terms( $post_id, 'product_brand' ) as $term ) {
$terms[] = array(
'id' => $term->term_id,
'name' => $term->name,
'slug' => $term->slug,
);
}
$response->data['brands'] = $terms;
}
return $response;
}
/**
* Add brands in product response.
*
* @param WC_Data $product Inserted product object.
* @param WP_REST_Request $request Request object.
* @param boolean $creating True when creating object, false when updating.
* @version 9.4.0
*/
public function rest_api_add_brands_to_product( $product, $request, $creating = true ) {
$product_id = is_callable( array( $product, 'get_id' ) ) ? $product->get_id() : ( ! empty( $product->ID ) ? $product->ID : null );
$params = $request->get_params();
$brands = isset( $params['brands'] ) ? $params['brands'] : array();
if ( ! empty( $brands ) ) {
if ( is_array( $brands[0] ) && array_key_exists( 'id', $brands[0] ) ) {
$brands = array_map(
function ( $brand ) {
return absint( $brand['id'] );
},
$brands
);
} else {
$brands = array_map( 'absint', $brands );
}
wp_set_object_terms( $product_id, $brands, 'product_brand' );
}
}
/**
* Filters products by taxonomy product_brand.
*
* @param array $args Request args.
* @param WP_REST_Request $request Request data.
* @return array Request args.
* @version 9.4.0
*/
public function rest_api_filter_products_by_brand( $args, $request ) {
if ( ! empty( $request['brand'] ) ) {
$args['tax_query'][] = array(
'taxonomy' => 'product_brand',
'field' => 'term_id',
'terms' => $request['brand'],
);
}
return $args;
}
/**
* Documents additional query params for collections of products.
*
* @param array $params JSON Schema-formatted collection parameters.
* @param WP_Post_Type $post_type Post type object.
* @return array JSON Schema-formatted collection parameters.
* @version 9.4.0
*/
public function rest_api_product_collection_params( $params, $post_type ) {
$params['brand'] = array(
'description' => __( 'Limit result set to products assigned a specific brand ID.', 'woocommerce' ),
'type' => 'string',
'sanitize_callback' => 'wp_parse_id_list',
'validate_callback' => 'rest_validate_request_arg',
);
return $params;
}
/**
* Injects Brands filters into layered nav links.
*
* @param string $term_html Original link html.
* @param mixed $term Term that is currently added.
* @param string $link Original layered nav item link.
* @param number $count Number of items in that filter.
* @return string Term html.
* @version 9.4.0
*/
public function woocommerce_brands_update_layered_nav_link( $term_html, $term, $link, $count ) {
if ( empty( $_GET['filter_product_brand'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
return $term_html;
}
$filter_product_brand = wc_clean( wp_unslash( $_GET['filter_product_brand'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
$current_attributes = array_map( 'intval', explode( ',', $filter_product_brand ) );
$current_values = ! empty( $current_attributes ) ? $current_attributes : array();
$link = add_query_arg(
array(
'filtering' => '1',
'filter_product_brand' => implode( ',', $current_values ),
),
wp_specialchars_decode( $link )
);
$term_html = '<a rel="nofollow" href="' . esc_url( $link ) . '">' . esc_html( $term->name ) . '</a>';
$term_html .= ' ' . apply_filters( 'woocommerce_layered_nav_count', '<span class="count">(' . absint( $count ) . ')</span>', $count, $term );
return $term_html;
}
/**
* Temporarily tag a post with meta before it is saved in order
* to allow us to be able to use the meta when the product is saved to add
* the brands when an ID has been generated.
*
*
* @param WC_Product $duplicate
* @return WC_Product $original
*/
public function duplicate_store_temporary_brands( $duplicate, $original ) {
$terms = get_the_terms( $original->get_id(), 'product_brand' );
if ( ! is_array( $terms ) ) {
return;
}
$ids = array();
foreach ( $terms as $term ) {
$ids[] = $term->term_id;
}
$duplicate->add_meta_data( 'duplicate_temp_brand_ids', $ids );
}
/**
* After product was added check if there are temporary brands and
* add them officially and remove the temporary brands.
*
* @since 9.4.0
*
* @param int $product_id
*/
public function duplicate_add_product_brand_terms( $product_id ) {
$product = wc_get_product( $product_id );
// Bail if product isn't found.
if ( ! $product instanceof WC_Product ) {
return;
}
$term_ids = $product->get_meta( 'duplicate_temp_brand_ids' );
if ( empty( $term_ids ) ) {
return;
}
$term_taxonomy_ids = wp_set_object_terms( $product_id, $term_ids, 'product_brand' );
$product->delete_meta_data( 'duplicate_temp_brand_ids' );
$product->save();
}
/**
* Remove terms with empty products.
*
* @param WP_Term[] $terms The terms array that needs to be removed of empty products.
*
* @return WP_Term[]
*/
private function remove_terms_with_empty_products( $terms ) {
return array_filter(
$terms,
function ( $term ) {
return $term->count > 0;
}
);
}
/**
* Invalidates the layered nav counts cache.
*
* @return void
*/
public function invalidate_wc_layered_nav_counts_cache() {
$taxonomy = 'product_brand';
delete_transient( 'wc_layered_nav_counts_' . sanitize_title( $taxonomy ) );
}
/**
* Reset Layered Nav cached counts on product status change.
*
* @param $new_status
* @param $old_status
* @param $post
*
* @return void
*/
function reset_layered_nav_counts_on_status_change( $new_status, $old_status, $post ) {
if ( $post->post_type === 'product' && $old_status !== $new_status ) {
$this->invalidate_wc_layered_nav_counts_cache();
}
}
/**
* Add a new block to the template.
*
* @param string $template_id Template ID.
* @param string $template_area Template area.
* @param BlockTemplateInterface $template Template instance.
*/
public function wc_brands_on_block_template_register( $template_id, $template_area, $template ) {
if ( 'simple-product' === $template->get_id() ) {
$section = $template->get_section_by_id( 'product-catalog-section' );
if ( $section !== null ) {
$section->add_block(
array(
'id' => 'woocommerce-brands-select',
'blockName' => 'woocommerce/product-taxonomy-field',
'order' => 15,
'attributes' => array(
'label' => __( 'Brands', 'woocommerce-brands' ),
'createTitle' => __( 'Create new brand', 'woocommerce-brands' ),
'slug' => 'product_brand',
'property' => 'brands',
),
)
);
}
}
}
}
$GLOBALS['WC_Brands'] = new WC_Brands();