File "class-products.php"
Full Path: /home/romayxjt/public_html/wp-content/plugins/orderable/inc/class-products.php
File size: 32.08 KB
MIME-type: text/x-php
Charset: utf-8
<?php
/**
* Product methods.
*
* @package Orderable/Classes
*/
defined( 'ABSPATH' ) || exit;
/**
* Products class.
*/
class Orderable_Products {
/**
* Init
*/
public static function run() {
add_filter( 'woocommerce_format_price_range', array( __CLASS__, 'format_price_range' ), 10, 3 );
add_filter( 'woocommerce_product_is_visible', array( __CLASS__, 'set_product_visibility' ), 10, 2 );
add_action( 'template_redirect', array( __CLASS__, 'products_404' ) );
add_filter( 'woocommerce_cart_item_permalink', array( __CLASS__, 'disable_cart_link' ), 10, 3 );
add_filter( 'woocommerce_product_query_tax_query', array( __CLASS__, 'remove_hidden_categories_from_products_query' ), 10, 2 );
add_filter( 'get_terms_args', array( __CLASS__, 'remove_hidden_categories_from_terms_query' ), 10, 2 );
add_filter( 'wp_sitemaps_posts_query_args', array( __CLASS__, 'remove_hidden_products_from_sitemap' ), 10, 2 );
add_filter( 'wp_sitemaps_taxonomies_query_args', array( __CLASS__, 'remove_hidden_categories_from_sitemap' ), 10, 2 );
add_filter( 'orderable_add_to_cart_button_args', array( __CLASS__, 'update_button_args_to_allow_add_to_cart_without_side_drawer' ), 10, 3 );
add_filter( 'woocommerce_add_to_cart_fragments', array( __CLASS__, 'handle_adding_product_without_side_drawer' ) );
add_filter( 'orderable_main_class', array( __CLASS__, 'add_quantity_roller_class' ), 10, 2 );
add_action( 'woocommerce_cart_item_removed', array( __CLASS__, 'update_product_counter_fragments_for_removed_item' ), 10, 2 );
}
/**
* Format price range.
*
* @param string $price
* @param float $from
* @param float $to
*
* @return string
*/
public static function format_price_range( $price, $from, $to ) {
return sprintf( '%s: %s', __( 'From', 'orderable' ), wc_price( $from ) );
}
/**
* Get products, sorted by category.
*
* @param array $args
*
* @return array
*/
public static function get_products_by_category( $args = array() ) {
// Disable this filter as we don't want to disable categories during our own calls to them.
remove_filter( 'get_terms_args', array( __CLASS__, 'remove_hidden_categories_from_terms_query' ), 10 );
$categories = ! empty( $args['categories'] ) ? $args['categories'] : array();
$categories = is_string( $categories ) ? array_filter( explode( ',', $categories ) ) : $categories;
$has_categories = ! empty( $categories );
$categories = self::order_categories_by_menu_order( $categories );
$orderby = ! defined( 'ORDERABLE_PRO_VERSION' ) || empty( $_GET['order_by'] ) ? '' : sanitize_text_field( wp_unslash( $_GET['order_by'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
if ( empty( $orderby ) ) {
$orderby = ! defined( 'ORDERABLE_PRO_VERSION' ) || empty( $args['sort'] ) ? 'menu_order' : $args['sort'];
}
$products = array();
/**
* Filter description.
*
* @since 1.0.0
* @hook orderable_flatten_products_by_category_level
* @param string $flatten_level The flatten level. Default: `all`.
* @param array $args The layout args.
* @return string New value
*/
$flatten_level = apply_filters( 'orderable_flatten_products_by_category_level', 'all', $args );
if ( 'all' === $flatten_level ) {
$products[] = array(
'category' => array(),
'products' => array(),
);
$categories_slug = array_filter(
array_map(
function( $category_id ) {
$category = get_term_by( 'id', $category_id, 'product_cat' );
return empty( $category->slug ) ? false : $category->slug;
},
$categories
)
);
$products[0]['products'] = self::get_products(
array(
'category' => $categories_slug,
'orderby' => $orderby,
'limit' => 500,
)
);
/**
* Filter the products sorted by categories to be shown in the product layout.
*
* @since 1.0.0
* @hook orderable_get_products_by_category
* @param array $products The products.
* @param array $args The args to retrieve the products.
* @param string $flatten_level The flatten level e.g. `all` and `children`.
* @return array New value
*/
return apply_filters( 'orderable_get_products_by_category', $products, $args, $flatten_level );
}
if ( $has_categories ) {
foreach ( $categories as $category_id ) {
$category = get_term( $category_id, 'product_cat' );
if ( is_wp_error( $category ) || empty( $category ) ) {
continue;
}
$products[ $category_id ] = array(
'category' => array(
'name' => $category->name,
'slug' => $category->slug,
'description' => $category->description,
'depth' => 0,
'children' => null,
),
'products' => array(),
);
$children_categories = get_terms(
array(
'taxonomy' => 'product_cat',
'orderby' => 'menu_order',
'hide_empty' => true,
'parent' => $category->term_id,
)
);
if ( ! empty( $children_categories ) ) {
$products[ $category_id ]['category']['children'] = array();
foreach ( $children_categories as $child_category ) {
$category_products = self::get_products(
array(
'limit' => 500,
'category' => array( $child_category->slug ),
'orderby' => $orderby,
)
);
if ( empty( $category_products ) ) {
continue;
}
if ( 'children' === $flatten_level ) {
$products_in_category = empty( $products[ $category_id ]['products'] ) ? array() : $products[ $category_id ]['products'];
$products[ $category_id ]['products'] = array_merge( $products_in_category, $category_products );
continue;
}
$products[ $category_id ]['category']['children'][ $child_category->term_id ] = array(
'category' => array(
'name' => $child_category->name,
'description' => $child_category->description,
'depth' => 1,
'parent' => $category_id,
),
'products' => $category_products,
);
}
} else {
$category_products = self::get_products(
array(
'limit' => 500,
'category' => array( $category->slug ),
'orderby' => $orderby,
)
);
if ( ! empty( $category_products ) ) {
$products[ $category_id ]['products'] = $category_products;
// Add parent attribute if parent is a root category.
if ( in_array( $category->parent, $categories, true ) ) {
$products[ $category_id ]['category']['parent'] = $category->parent;
}
}
}
}
} else {
$category_products = self::get_products(
array(
'limit' => 500,
'orderby' => $orderby,
)
);
if ( ! empty( $category_products ) ) {
$products[] = array(
'category' => null,
'products' => $category_products,
);
}
}
// Remove categories with no products.
foreach ( $products as $key => $product_collection ) {
if ( ! empty( $product_collection['products'] ) || ! empty( $product_collection['category']['children'] ) ) {
continue;
}
unset( $products[ $key ] );
}
// Turn this back on to re-disable hidden categories.
add_filter( 'get_terms_args', array( __CLASS__, 'remove_hidden_categories_from_terms_query' ), 10, 2 );
$products = self::maybe_flatten_products_by_category( array_filter( $products ), $args );
// phpcs:ignore WooCommerce.Commenting.CommentHooks
return apply_filters( 'orderable_get_products_by_category', $products, $args, $flatten_level );
}
/**
* Get Products.
*
* A wrapper around the WooCommerce `wc_get_products` and `wc_products_array_orderby` functions.
*
* @param array $args Arguments.
*
* @return array
*/
public static function get_products( $args ) {
$args['status'] = 'publish'; // Ensure only published products are returned.
if ( 'yes' === get_option( 'woocommerce_hide_out_of_stock_items' ) ) {
$args['stock_status'] = 'instock';
}
/**
* Filter arguments used to retrieve products from database
*
* @param array $args WC_Product_Query arguments
*
* @return array New query arguments
* @since 1.2.1
* @hook orderable_get_products_args
*/
$products = wc_get_products( apply_filters( 'orderable_get_products_args', $args ) );
if ( ! empty( $products ) ) {
$orderby = empty( $args['orderby'] ) ? 'menu_order' : $args['orderby'];
$order = 'price-desc' === $orderby ? 'desc' : 'asc';
$orderby = 'price-desc' === $orderby ? 'price' : $orderby;
$products = wc_products_array_orderby( $products, $orderby, $order );
}
return apply_filters( 'orderable_get_products', $products, $args );
}
/**
* Order Categories by menu order
*
* @param array $categories Categories.
*
* @return array
*/
public static function order_categories_by_menu_order( $categories ) {
$categories_ordered = array();
$category_terms = get_terms(
array(
'taxonomy' => 'product_cat',
'orderby' => 'menu_order',
'hide_empty' => true,
)
);
foreach ( $category_terms as $term ) {
if ( ! in_array( $term->term_id, $categories, true ) ) {
continue;
}
$categories_ordered[] = $term->term_id;
}
return $categories_ordered;
}
/**
* Maybe flatten products by category.
*
* @param array $products
* @param array $args
*
* @return array
*/
public static function maybe_flatten_products_by_category( $products, $args = array() ) {
// If we're already listing all products with no categories, escape.
if ( empty( $products ) || isset( $products[0] ) ) {
return $products;
}
$flatten_level = apply_filters( 'orderable_flatten_products_by_category_level', 'all', $args );
// Don't flatten if set to "none".
if ( 'none' === $flatten_level ) {
return $products;
}
$flattened_products = array();
if ( 'children' === $flatten_level ) {
$orderby = empty( $args['sort'] ) ? 'menu_order' : $args['sort'];
$order = 'price-desc' === $orderby ? 'desc' : 'asc';
$orderby = 'price-desc' === $orderby ? 'price' : $orderby;
foreach ( $products as $category_id => $product_group ) {
$product_group['products'] = wc_products_array_orderby( $product_group['products'], $orderby, $order );
$flattened_products[ $category_id ] = $product_group;
}
} else {
$flattened_products[] = array(
'category' => null,
'products' => array(),
);
foreach ( $products as $product_group ) {
if ( ! empty( $product_group['products'] ) ) {
// Add category products to list.
$flattened_products[0]['products'] = array_merge( $flattened_products[0]['products'], $product_group['products'] );
continue;
} elseif ( ! empty( $product_group['category']['children'] ) ) {
foreach ( $product_group['category']['children'] as $child_product_group ) {
// Add category products to list.
$flattened_products[0]['products'] = array_merge( $flattened_products[0]['products'], $child_product_group['products'] );
continue;
}
}
}
}
return $flattened_products;
}
/**
* Get add to cart button.
*
* @param WC_Product $product Product.
* @param string $classes Button classes.
* @param array $layout_settings The product layout settings.
*
* @return string
*/
public static function get_add_to_cart_button( $product, $classes = '', $layout_settings = array() ) {
global $orderable_single_product;
$args = array(
'trigger' => self::get_add_to_cart_trigger( $product ),
'product_id' => $product->get_id(),
'product_type' => $product->get_type(),
'variation_id' => null,
'variation_attributes' => array(),
'text' => __( 'Add', 'orderable' ),
'classes' => $classes,
);
if ( Orderable_Helpers::is_variable_product( $args['product_type'] ) ) {
$args['trigger'] = 'product-options';
$args['text'] = empty( $orderable_single_product ) ? __( 'Select', 'orderable' ) : $args['text'];
} elseif ( 'variation' === $args['product_type'] ) {
$args['product_id'] = $product->get_parent_id();
$args['variation_id'] = $product->get_id();
}
if ( ! $product->is_in_stock() ) {
$args['classes'] .= ' orderable-button--out-of-stock';
$args['text'] = __( 'Out of Stock', 'orderable' );
}
if ( Orderable_Helpers::is_product_in_the_cart( $product->get_id() ) ) {
$args['classes'] .= ' orderable-button--product-in-the-cart';
}
$product_quantity = Orderable_Helpers::get_product_quantity_in_the_cart( $product->get_id() );
/**
* Filter the Add to Cart button args.
*
* @since 1.0.0
* @hook orderable_add_to_cart_button_args
* @param array $args The button args.
* @param WC_Product $product The product.
* @param array $layout_settings The product layout settings.
* @return array New value
*/
$args = apply_filters( 'orderable_add_to_cart_button_args', $args, $product, $layout_settings );
$counter_element_classes = 'orderable-product__actions-counter';
return sprintf(
'<button
class="orderable-button %1$s"
data-orderable-trigger="%2$s"
data-orderable-product-id="%3$d"
data-orderable-product-type="%4$s"
data-orderable-variation-id="%5$d"
data-orderable-variation-attributes=""
data-quantity="1"
data-product_id="%3$d"
data-product_sku="%6$s"
data-product_name="%7$s"
data-price="%8$s"
>
%9$s
<span class="%10$s" data-orderable-product-quantity="%11$d">%11$d</span>
</button>',
esc_attr( $args['classes'] ),
esc_attr( $args['trigger'] ),
esc_attr( $args['product_id'] ),
esc_attr( $args['product_type'] ),
esc_attr( $args['variation_id'] ),
esc_attr( $product->get_sku() ),
esc_attr( $product->get_name() ),
esc_attr( $product->get_price() ),
wp_kses_post( $args['text'] ),
$counter_element_classes,
$product_quantity
);
}
/**
* Get update cart item button.
*
* @param string $cart_item_key The cart item key.
* @param WC_Product $product The product to be edited.
* @param string $classes Button classes.
*
* @return string
*/
public static function get_update_cart_item_button( $cart_item_key, $product, $classes = '' ) {
$cart_item = WC()->cart->get_cart_item( $cart_item_key );
$args = array(
'trigger' => 'update-cart-item',
'product_id' => $cart_item['product_id'],
'cart_item_key' => $cart_item_key,
'variation_id' => $cart_item['variation_id'],
'variation_attributes' => empty( array_filter( $cart_item['variation'] ) ) ? false : wp_json_encode( $cart_item['variation'] ),
'product_type' => $product->get_type(),
'text' => __( 'Update', 'orderable' ),
'classes' => $classes,
);
/**
* Filter arguments used to the update cart item button.
*
* @param array $args The arguments.
* @param string $cart_item_key The cart item key.
*
* @return array New arguments
* @since 1.4.0
* @hook orderable_update_cart_item_button_args
*/
$args = apply_filters( 'orderable_update_cart_item_button_args', $args, $cart_item_key );
ob_start();
?>
<button
class="orderable-button orderable-product__cancel-update"
data-orderable-trigger="show-cart"
>
<?php echo esc_html__( 'Cancel', 'orderable' ); ?>
</button>
<button
class="orderable-button <?php echo esc_attr( $args['classes'] ); ?>"
data-orderable-trigger="<?php echo esc_attr( $args['trigger'] ); ?>"
data-orderable-cart-item-key="<?php echo esc_attr( $args['cart_item_key'] ); ?>"
data-orderable-product-id="<?php echo esc_attr( $args['product_id'] ); ?>"
data-orderable-variation-id="<?php echo esc_attr( $args['variation_id'] ); ?>"
data-orderable-variation-attributes="<?php echo esc_attr( $args['variation_attributes'] ); ?>"
data-orderable-product-type="<?php echo esc_attr( $args['product_type'] ); ?>"
>
<?php echo esc_html( $args['text'] ); ?>
</button>
<?php
/**
* Filter the Update Cart Item button HTML.
*
* @param string|false $update_cart_item_button_html The Update Cart Item button HTML.
*
* @return string|false New HTML
* @since 1.4.0
* @hook orderable_update_cart_item_button_html
*/
$html = apply_filters( 'orderable_update_cart_item_button_html', ob_get_clean() );
return $html;
}
/**
* Get add to cart trigger value.
*
* @param WC_Product $product
*
* @return string
*/
public static function get_add_to_cart_trigger( $product ) {
$trigger = $product->is_type( 'variable' ) ? 'product-options' : 'add-to-cart';
return apply_filters( 'orderable_get_add_to_cart_trigger', $trigger, $product );
}
/**
* Get a list of attributes for available variations.
*
* @param WC_Product_Variable $product
*
* @return array
*/
public static function get_available_variation_attributes( $product ) {
$available_variation_attributes = array();
$available_variations = $product->get_available_variations();
$available_variations = wc_list_pluck( $available_variations, 'attributes' );
if ( empty( $available_variations ) ) {
return $available_variation_attributes;
}
foreach ( $available_variations as $available_variation ) {
foreach ( $available_variation as $attribute_slug => $attribute_value ) {
if ( ! isset( $available_variation_attributes[ $attribute_slug ] ) ) {
$available_variation_attributes[ $attribute_slug ] = array();
}
$available_variation_attributes[ $attribute_slug ][] = $attribute_value;
}
}
return $available_variation_attributes;
}
/**
* Get available attributes.
*
* This method remove an attributes which don't belong to
* an active variation.
*
* @param WC_Product_Variable $product
*
* @return array
*/
public static function get_available_attributes( $product ) {
$available_attributes = array();
$attributes = $product->get_variation_attributes();
$available_variation_attributes = self::get_available_variation_attributes( $product );
if ( empty( $attributes ) ) {
return $available_attributes;
}
foreach ( $attributes as $attribute_name => $attribute_terms ) {
$attribute_name_sanitized = wc_variation_attribute_name( $attribute_name );
if ( empty( $available_variation_attributes[ $attribute_name_sanitized ] ) ) {
continue;
}
if ( ! isset( $available_attributes[ $attribute_name ] ) ) {
$available_attributes[ $attribute_name ] = array();
}
foreach ( $attribute_terms as $attribute_term ) {
if ( ! in_array( $attribute_term, $available_variation_attributes[ $attribute_name_sanitized ], true ) && ! in_array( '', $available_variation_attributes[ $attribute_name_sanitized ], true ) ) {
continue;
}
$available_attributes[ $attribute_name ][] = $attribute_term;
}
}
return $available_attributes;
}
/**
* Is product single page hidden?
*
* @param int|WC_Product $product
*
* @return bool
*/
public static function is_product_hidden( $product ) {
if ( is_numeric( $product ) ) {
$product = wc_get_product( $product );
}
if ( empty( $product ) ) {
return false;
}
$categories = $product->get_category_ids();
if ( empty( $categories ) ) {
return false;
}
foreach ( $categories as $category_id ) {
if ( self::is_category_hidden( $category_id ) ) {
return true;
}
}
return false;
}
/**
* Is this category hidden?
*
* @param $category_id
*
* @return bool
*/
public static function is_category_hidden( $category_id ) {
$hidden_categories = Orderable_Settings::get_hidden_categories();
return in_array( $category_id, $hidden_categories, true );
}
/**
* Set if product is visible, based on category settings.
*
* @param bool $visible
* @param int $product_id
*
* @return bool
*/
public static function set_product_visibility( $visible, $product_id ) {
$hidden = self::is_product_hidden( $product_id );
return $hidden ? false : $visible;
}
/**
* Disable cart permalink.
*
* @param string $permalink
*
* @return bool
*/
public static function disable_cart_link( $permalink, $cart_item, $cart_item_key ) {
if ( ! isset( $cart_item['data'] ) ) {
return $permalink;
}
return self::is_product_hidden( $cart_item['data'] ) ? false : $permalink;
}
/**
* Set product page to 404 if required.
*/
public static function products_404() {
if ( is_admin() || ! ( is_product() && is_single() ) ) {
return;
}
global $post;
if ( empty( $post ) ) {
return;
}
$product = wc_get_product( $post->ID );
if ( empty( $product ) || ! self::is_product_hidden( $product ) ) {
return;
}
global $wp_query;
$wp_query->set_404();
status_header( 404 );
nocache_headers();
}
/**
* Exclude hidden categories from queries.
*
* @param $tax_query
* @param $wc_query
*
* @return array
*/
public static function remove_hidden_categories_from_products_query( $tax_query, $wc_query ) {
$hidden_categories = Orderable_Settings::get_hidden_categories();
if ( empty( $hidden_categories ) ) {
return $tax_query;
}
$tax_query[] = array(
'taxonomy' => 'product_cat',
'field' => 'term_id',
'terms' => $hidden_categories,
'operator' => 'NOT IN',
);
return $tax_query;
}
/**
* Remove hidden categories from terms query.
*
* As well as hiding from terms lists (sidebar widgets, etc),
* this also disables the archive page.
*
* @param array $args Args.
* @param array $taxonomies Taxonomies.
*
* @return mixed
*/
public static function remove_hidden_categories_from_terms_query( $args, $taxonomies ) {
if ( is_admin() ) {
return $args;
}
$taxonomy = ! empty( $args['taxonomy'] ) && isset( $args['taxonomy'][0] ) ? $args['taxonomy'][0] : false;
if ( 'product_cat' !== $taxonomy || is_admin() ) {
return $args;
}
// Exclude hidden categories.
$hidden_categories = Orderable_Settings::get_hidden_categories();
$args['exclude'] = ! is_array( $args['exclude'] ) ? array() : $args['exclude'];
$args['exclude'] = array_merge( $args['exclude'], $hidden_categories );
return $args;
}
/**
* Remove hidden products from sitemap.
*
* @param array $query_args Query args.
* @param string $post_type Post type.
*
* @return mixed
*/
public static function remove_hidden_products_from_sitemap( $query_args, $post_type ) {
if ( 'product' !== $post_type ) {
return $query_args;
}
$hidden_categories = Orderable_Settings::get_hidden_categories();
if ( empty( $hidden_categories ) ) {
return $query_args;
}
$tax_query = array(
'taxonomy' => 'product_cat',
'terms' => $hidden_categories,
'field' => 'term_id',
'include_children' => true,
'operator' => 'NOT IN',
);
if ( ! isset( $query_args['tax_query'] ) ) {
$query_args['tax_query'] = array();
}
$query_args['tax_query'][] = $tax_query;
return $query_args;
}
/**
* Exclude hidden categories from sitemap.
*
* @param array $query_args Query args.
* @param string $taxonomy Taxonomy.
*
* @return mixed
*/
public static function remove_hidden_categories_from_sitemap( $query_args, $taxonomy ) {
if ( 'product_cat' !== $taxonomy ) {
return $query_args;
}
$hidden_categories = Orderable_Settings::get_hidden_categories();
if ( empty( $hidden_categories ) ) {
return $query_args;
}
if ( ! isset( $query_args['exclude'] ) ) {
$query_args['exclude'] = $hidden_categories;
} else {
if ( is_array( $hidden_categories ) ) {
$query_args['exclude'] = array_merge( $query_args['exclude'], $hidden_categories );
} else {
$query_args['exclude'] = $query_args['exclude'] . ',' . implode( ',', $hidden_categories );
}
}
return $query_args;
}
/**
* Get product accordion data.
*
* @param WC_Product $product Product.
*
* @return array
*/
public static function get_accordion_data( $product ) {
$data = [];
$description = Orderable_Settings::get_setting( 'drawer_quickview_description' );
if ( 'none' === $description ) {
// phpcs:ignore WooCommerce.Commenting.CommentHooks
return apply_filters( 'orderable_get_accordion_data', $data, $product );
}
$description = 'short' === $description ? $product->get_short_description() : $product->get_description();
// phpcs:ignore WooCommerce.Commenting.CommentHooks
$content = apply_filters( 'the_content', $description );
if ( empty( $content ) ) {
// phpcs:ignore WooCommerce.Commenting.CommentHooks
return apply_filters( 'orderable_get_accordion_data', $data, $product );
}
$data[] = array(
'title' => __( 'Description', 'orderable' ),
'content' => $content,
'id' => 'accordion-description',
);
/**
* Filter product accordion data.
*
* @var array $data
* @var WC_Product $product
* @since 1.0.0
*/
return apply_filters( 'orderable_get_accordion_data', $data, $product );
}
/**
* Update the button args to allow adding to the cart without opening side drawer.
*
* @param array $args The button args.
* @param WC_Product $product The product.
* @param array $layout_settings The product layout settings.
* @return array
*/
public static function update_button_args_to_allow_add_to_cart_without_side_drawer( $args, $product, $layout_settings ) {
if ( empty( $layout_settings['quantity_roller'] ) ) {
return $args;
}
if ( 'add-to-cart' !== $args['trigger'] ) {
return $args;
}
$args['trigger'] = 'add-to-cart-without-side-drawer';
return $args;
}
/**
* Update the quantity roller fragments.
*
* @param array $fragments The WooCommerce cart fragments.
* @return array
*/
public static function handle_adding_product_without_side_drawer( $fragments ) {
// phpcs:ignore WordPress.Security.NonceVerification
if ( empty( $_POST['action'] ) || empty( $_POST['product_id'] ) ) {
return $fragments;
}
$action = sanitize_text_field( wp_unslash( $_POST['action'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
$product_id = absint( sanitize_text_field( wp_unslash( $_POST['product_id'] ) ) ); // phpcs:ignore WordPress.Security.NonceVerification
switch ( $action ) {
case 'orderable_add_to_cart':
$cart_item = false;
foreach ( WC()->cart->get_cart() as $cart_item_data ) {
if ( $product_id !== $cart_item_data['product_id'] ) {
continue;
}
$cart_item = $cart_item_data;
}
if ( empty( $cart_item ) ) {
return $fragments;
}
ob_start();
self::get_quantity_roller( $cart_item );
$fragments[ ".orderable-product[data-orderable-product-id='{$product_id}'] .orderable-product__actions-button .orderable-quantity-roller" ] = ob_get_clean();
$fragments[ ".orderable-product[data-orderable-product-id='{$product_id}'] .orderable-product__actions-button .orderable-product__actions-counter" ] = self::get_product_counter( $product_id );
break;
case 'orderable_cart_quantity':
// phpcs:ignore WordPress.Security.NonceVerification
if ( empty( $_POST['cart_item_key'] ) || ! isset( $_POST['quantity'] ) ) {
return $fragments;
}
$cart_item_key = sanitize_text_field( wp_unslash( $_POST['cart_item_key'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
if ( empty( $cart_item_key ) ) {
return $fragments;
}
$cart_item = WC()->cart->get_cart_item( $cart_item_key );
ob_start();
self::get_quantity_roller( $cart_item );
$fragments[ ".orderable-product[data-orderable-product-id='{$product_id}'] .orderable-product__actions-button .orderable-quantity-roller" ] = ob_get_clean();
if ( empty( $cart_item ) ) {
$fragments[ ".orderable-product[data-orderable-product-id='{$product_id}'] .orderable-product__actions-button .orderable-product__actions-counter" ] = self::get_product_counter( $product_id );
return $fragments;
}
$fragments[ ".orderable-product[data-orderable-product-id='{$product_id}'] .orderable-product__actions-button .orderable-product__actions-counter" ] = self::get_product_counter( $product_id );
break;
default:
break;
}
return $fragments;
}
/**
* Get the HTML markup for the quantity roller element.
*
* @param array $cart_item The cart item.
* @param string $product_price The product price.
* @return void
*/
public static function get_quantity_roller( $cart_item, $product_price = '' ) {
if ( empty( $cart_item ) ) {
?>
<div class="orderable-quantity-roller"></div>
<?php
} else {
?>
<div class="orderable-quantity-roller orderable-quantity-roller--is-active">
<span class="orderable-quantity-roller__roller">
<button
class="orderable-quantity-roller__button orderable-quantity-roller__button--decrease"
data-orderable-trigger="decrease-quantity"
data-orderable-cart-item-key="<?php echo esc_attr( $cart_item['key'] ); ?>"
data-orderable-product-id="<?php echo esc_attr( $cart_item['product_id'] ); ?>"
data-orderable-quantity="<?php echo esc_attr( $cart_item['quantity'] ); ?>"
><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><rect x="0" fill="none" width="20" height="20"/><g><path d="M12 4h3c.6 0 1 .4 1 1v1H3V5c0-.6.5-1 1-1h3c.2-1.1 1.3-2 2.5-2s2.3.9 2.5 2zM8 4h3c-.2-.6-.9-1-1.5-1S8.2 3.4 8 4zM4 7h11l-.9 10.1c0 .5-.5.9-1 .9H5.9c-.5 0-.9-.4-1-.9L4 7z"/></g></svg></button>
<span
class="orderable-quantity-roller__quantity"
contenteditable="true"
inputmode="numeric"
data-orderable-cart-item-key="<?php echo esc_attr( $cart_item['key'] ); ?>"
data-orderable-product-id="<?php echo esc_attr( $cart_item['product_id'] ); ?>"
>
<?php echo esc_attr( $cart_item['quantity'] ); ?>
</span>
<button
class="orderable-quantity-roller__button orderable-quantity-roller__button--increase"
data-orderable-trigger="increase-quantity"
data-orderable-cart-item-key="<?php echo esc_attr( $cart_item['key'] ); ?>"
data-orderable-product-id="<?php echo esc_attr( $cart_item['product_id'] ); ?>"
data-orderable-quantity="<?php echo esc_attr( $cart_item['quantity'] ); ?>"
>+</button>
</span>
<?php if ( ! empty( $product_price ) ) : ?>
<span class="orderable-quantity-roller__price"><?php echo wp_kses_post( $product_price ); ?></span>
<?php endif; ?>
</div>
<?php
}
}
/**
* Get the HTML markup for the product counter element.
*
* @param int $product_id The product ID.
* @return string The HTML markup.
*/
public static function get_product_counter( $product_id ) {
$quantity = Orderable_Helpers::get_product_quantity_in_the_cart( absint( $product_id ) );
?>
<span
class="orderable-product__actions-counter"
data-orderable-product-quantity="<?php echo esc_attr( $quantity ); ?>"
style="animation: wobble-hor-bottom .8s both;"
>
<?php echo esc_html( $quantity ); ?>
</span>
<?php
$html_markup = ob_get_clean();
/**
* Filter the product counter HTML markup.
*
* @param string $html_markup The HTML markup.
*
* @return string New value.
* @since 1.7.0
* @hook orderable_product_counter_html
*/
return apply_filters( 'orderable_product_counter_html', $html_markup );
}
/**
* Update product counter fragments for removed item.
*
* @param string $cart_item_key The removed cart item key.
* @param WC_Cart $wc_cart The WC Cart.
* @return void
*/
public static function update_product_counter_fragments_for_removed_item( $cart_item_key, $wc_cart ) {
$product_id = empty( $wc_cart->removed_cart_contents[ $cart_item_key ]['product_id'] ) ? false : $wc_cart->removed_cart_contents[ $cart_item_key ]['product_id'];
if ( ! $product_id ) {
return;
}
add_filter(
'woocommerce_add_to_cart_fragments',
function( $fragments ) use ( $product_id ) {
$fragments[ ".orderable-product[data-orderable-product-id='{$product_id}'] .orderable-product__actions-button .orderable-product__actions-counter" ] = self::get_product_counter( $product_id );
return $fragments;
}
);
}
/**
* Add `.orderable-main--quantity-roller` class to the `.orderable-main` element.
*
* @param string $class The class attribute value.
* @param array $args The layout settings.
* @return string
*/
public static function add_quantity_roller_class( $class, $args ) {
if ( empty( $args['quantity_roller'] ) ) {
return $class;
}
$class .= ' orderable-main--quantity-roller';
return $class;
}
}