initial commit
This commit is contained in:
80
includes/widgets/class-wc-widget-cart.php
Normal file
80
includes/widgets/class-wc-widget-cart.php
Normal file
@ -0,0 +1,80 @@
|
||||
<?php
|
||||
/**
|
||||
* Shopping Cart Widget.
|
||||
*
|
||||
* Displays shopping cart widget.
|
||||
*
|
||||
* @package WooCommerce\Widgets
|
||||
* @version 2.3.0
|
||||
*/
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Widget cart class.
|
||||
*/
|
||||
class WC_Widget_Cart extends WC_Widget {
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->widget_cssclass = 'woocommerce widget_shopping_cart';
|
||||
$this->widget_description = __( 'Display the customer shopping cart.', 'woocommerce' );
|
||||
$this->widget_id = 'woocommerce_widget_cart';
|
||||
$this->widget_name = __( 'Cart', 'woocommerce' );
|
||||
$this->settings = array(
|
||||
'title' => array(
|
||||
'type' => 'text',
|
||||
'std' => __( 'Cart', 'woocommerce' ),
|
||||
'label' => __( 'Title', 'woocommerce' ),
|
||||
),
|
||||
'hide_if_empty' => array(
|
||||
'type' => 'checkbox',
|
||||
'std' => 0,
|
||||
'label' => __( 'Hide if cart is empty', 'woocommerce' ),
|
||||
),
|
||||
);
|
||||
|
||||
if ( is_customize_preview() ) {
|
||||
wp_enqueue_script( 'wc-cart-fragments' );
|
||||
}
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Output widget.
|
||||
*
|
||||
* @see WP_Widget
|
||||
*
|
||||
* @param array $args Arguments.
|
||||
* @param array $instance Widget instance.
|
||||
*/
|
||||
public function widget( $args, $instance ) {
|
||||
if ( apply_filters( 'woocommerce_widget_cart_is_hidden', is_cart() || is_checkout() ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$hide_if_empty = empty( $instance['hide_if_empty'] ) ? 0 : 1;
|
||||
|
||||
if ( ! isset( $instance['title'] ) ) {
|
||||
$instance['title'] = __( 'Cart', 'woocommerce' );
|
||||
}
|
||||
|
||||
$this->widget_start( $args, $instance );
|
||||
|
||||
if ( $hide_if_empty ) {
|
||||
echo '<div class="hide_cart_widget_if_empty">';
|
||||
}
|
||||
|
||||
// Insert cart widget placeholder - code in woocommerce.js will update this on page load.
|
||||
echo '<div class="widget_shopping_cart_content"></div>';
|
||||
|
||||
if ( $hide_if_empty ) {
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
$this->widget_end( $args );
|
||||
}
|
||||
}
|
113
includes/widgets/class-wc-widget-layered-nav-filters.php
Normal file
113
includes/widgets/class-wc-widget-layered-nav-filters.php
Normal file
@ -0,0 +1,113 @@
|
||||
<?php
|
||||
/**
|
||||
* Layered Navigation Filters Widget.
|
||||
*
|
||||
* @package WooCommerce\Widgets
|
||||
* @version 2.3.0
|
||||
*/
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Widget layered nav filters.
|
||||
*/
|
||||
class WC_Widget_Layered_Nav_Filters extends WC_Widget {
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->widget_cssclass = 'woocommerce widget_layered_nav_filters';
|
||||
$this->widget_description = __( 'Display a list of active product filters.', 'woocommerce' );
|
||||
$this->widget_id = 'woocommerce_layered_nav_filters';
|
||||
$this->widget_name = __( 'Active Product Filters', 'woocommerce' );
|
||||
$this->settings = array(
|
||||
'title' => array(
|
||||
'type' => 'text',
|
||||
'std' => __( 'Active filters', 'woocommerce' ),
|
||||
'label' => __( 'Title', 'woocommerce' ),
|
||||
),
|
||||
);
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Output widget.
|
||||
*
|
||||
* @see WP_Widget
|
||||
* @param array $args Arguments.
|
||||
* @param array $instance Widget instance.
|
||||
*/
|
||||
public function widget( $args, $instance ) {
|
||||
if ( ! is_shop() && ! is_product_taxonomy() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$_chosen_attributes = WC_Query::get_layered_nav_chosen_attributes();
|
||||
$min_price = isset( $_GET['min_price'] ) ? wc_clean( wp_unslash( $_GET['min_price'] ) ) : 0; // WPCS: input var ok, CSRF ok.
|
||||
$max_price = isset( $_GET['max_price'] ) ? wc_clean( wp_unslash( $_GET['max_price'] ) ) : 0; // WPCS: input var ok, CSRF ok.
|
||||
$rating_filter = isset( $_GET['rating_filter'] ) ? array_filter( array_map( 'absint', explode( ',', wp_unslash( $_GET['rating_filter'] ) ) ) ) : array(); // WPCS: sanitization ok, input var ok, CSRF ok.
|
||||
$base_link = $this->get_current_page_url();
|
||||
|
||||
if ( 0 < count( $_chosen_attributes ) || 0 < $min_price || 0 < $max_price || ! empty( $rating_filter ) ) {
|
||||
|
||||
$this->widget_start( $args, $instance );
|
||||
|
||||
echo '<ul>';
|
||||
|
||||
// Attributes.
|
||||
if ( ! empty( $_chosen_attributes ) ) {
|
||||
foreach ( $_chosen_attributes as $taxonomy => $data ) {
|
||||
foreach ( $data['terms'] as $term_slug ) {
|
||||
$term = get_term_by( 'slug', $term_slug, $taxonomy );
|
||||
if ( ! $term ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$filter_name = 'filter_' . wc_attribute_taxonomy_slug( $taxonomy );
|
||||
$current_filter = isset( $_GET[ $filter_name ] ) ? explode( ',', wc_clean( wp_unslash( $_GET[ $filter_name ] ) ) ) : array(); // WPCS: input var ok, CSRF ok.
|
||||
$current_filter = array_map( 'sanitize_title', $current_filter );
|
||||
$new_filter = array_diff( $current_filter, array( $term_slug ) );
|
||||
|
||||
$link = remove_query_arg( array( 'add-to-cart', $filter_name ), $base_link );
|
||||
|
||||
if ( count( $new_filter ) > 0 ) {
|
||||
$link = add_query_arg( $filter_name, implode( ',', $new_filter ), $link );
|
||||
}
|
||||
|
||||
$filter_classes = array( 'chosen', 'chosen-' . sanitize_html_class( str_replace( 'pa_', '', $taxonomy ) ), 'chosen-' . sanitize_html_class( str_replace( 'pa_', '', $taxonomy ) . '-' . $term_slug ) );
|
||||
|
||||
echo '<li class="' . esc_attr( implode( ' ', $filter_classes ) ) . '"><a rel="nofollow" aria-label="' . esc_attr__( 'Remove filter', 'woocommerce' ) . '" href="' . esc_url( $link ) . '">' . esc_html( $term->name ) . '</a></li>';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( $min_price ) {
|
||||
$link = remove_query_arg( 'min_price', $base_link );
|
||||
/* translators: %s: minimum price */
|
||||
echo '<li class="chosen"><a rel="nofollow" aria-label="' . esc_attr__( 'Remove filter', 'woocommerce' ) . '" href="' . esc_url( $link ) . '">' . sprintf( __( 'Min %s', 'woocommerce' ), wc_price( $min_price ) ) . '</a></li>'; // WPCS: XSS ok.
|
||||
}
|
||||
|
||||
if ( $max_price ) {
|
||||
$link = remove_query_arg( 'max_price', $base_link );
|
||||
/* translators: %s: maximum price */
|
||||
echo '<li class="chosen"><a rel="nofollow" aria-label="' . esc_attr__( 'Remove filter', 'woocommerce' ) . '" href="' . esc_url( $link ) . '">' . sprintf( __( 'Max %s', 'woocommerce' ), wc_price( $max_price ) ) . '</a></li>'; // WPCS: XSS ok.
|
||||
}
|
||||
|
||||
if ( ! empty( $rating_filter ) ) {
|
||||
foreach ( $rating_filter as $rating ) {
|
||||
$link_ratings = implode( ',', array_diff( $rating_filter, array( $rating ) ) );
|
||||
$link = $link_ratings ? add_query_arg( 'rating_filter', $link_ratings ) : remove_query_arg( 'rating_filter', $base_link );
|
||||
|
||||
/* translators: %s: rating */
|
||||
echo '<li class="chosen"><a rel="nofollow" aria-label="' . esc_attr__( 'Remove filter', 'woocommerce' ) . '" href="' . esc_url( $link ) . '">' . sprintf( esc_html__( 'Rated %s out of 5', 'woocommerce' ), esc_html( $rating ) ) . '</a></li>';
|
||||
}
|
||||
}
|
||||
|
||||
echo '</ul>';
|
||||
|
||||
$this->widget_end( $args );
|
||||
}
|
||||
}
|
||||
}
|
469
includes/widgets/class-wc-widget-layered-nav.php
Normal file
469
includes/widgets/class-wc-widget-layered-nav.php
Normal file
@ -0,0 +1,469 @@
|
||||
<?php
|
||||
/**
|
||||
* Layered nav widget
|
||||
*
|
||||
* @package WooCommerce\Widgets
|
||||
* @version 2.6.0
|
||||
*/
|
||||
|
||||
use Automattic\WooCommerce\Internal\ProductAttributesLookup\Filterer;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Widget layered nav class.
|
||||
*/
|
||||
class WC_Widget_Layered_Nav extends WC_Widget {
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->widget_cssclass = 'woocommerce widget_layered_nav woocommerce-widget-layered-nav';
|
||||
$this->widget_description = __( 'Display a list of attributes to filter products in your store.', 'woocommerce' );
|
||||
$this->widget_id = 'woocommerce_layered_nav';
|
||||
$this->widget_name = __( 'Filter Products by Attribute', 'woocommerce' );
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a particular instance of a widget.
|
||||
*
|
||||
* @see WP_Widget->update
|
||||
*
|
||||
* @param array $new_instance New Instance.
|
||||
* @param array $old_instance Old Instance.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function update( $new_instance, $old_instance ) {
|
||||
$this->init_settings();
|
||||
return parent::update( $new_instance, $old_instance );
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs the settings update form.
|
||||
*
|
||||
* @see WP_Widget->form
|
||||
*
|
||||
* @param array $instance Instance.
|
||||
*/
|
||||
public function form( $instance ) {
|
||||
$this->init_settings();
|
||||
parent::form( $instance );
|
||||
}
|
||||
|
||||
/**
|
||||
* Init settings after post types are registered.
|
||||
*/
|
||||
public function init_settings() {
|
||||
$attribute_array = array();
|
||||
$std_attribute = '';
|
||||
$attribute_taxonomies = wc_get_attribute_taxonomies();
|
||||
|
||||
if ( ! empty( $attribute_taxonomies ) ) {
|
||||
foreach ( $attribute_taxonomies as $tax ) {
|
||||
if ( taxonomy_exists( wc_attribute_taxonomy_name( $tax->attribute_name ) ) ) {
|
||||
$attribute_array[ $tax->attribute_name ] = $tax->attribute_name;
|
||||
}
|
||||
}
|
||||
$std_attribute = current( $attribute_array );
|
||||
}
|
||||
|
||||
$this->settings = array(
|
||||
'title' => array(
|
||||
'type' => 'text',
|
||||
'std' => __( 'Filter by', 'woocommerce' ),
|
||||
'label' => __( 'Title', 'woocommerce' ),
|
||||
),
|
||||
'attribute' => array(
|
||||
'type' => 'select',
|
||||
'std' => $std_attribute,
|
||||
'label' => __( 'Attribute', 'woocommerce' ),
|
||||
'options' => $attribute_array,
|
||||
),
|
||||
'display_type' => array(
|
||||
'type' => 'select',
|
||||
'std' => 'list',
|
||||
'label' => __( 'Display type', 'woocommerce' ),
|
||||
'options' => array(
|
||||
'list' => __( 'List', 'woocommerce' ),
|
||||
'dropdown' => __( 'Dropdown', 'woocommerce' ),
|
||||
),
|
||||
),
|
||||
'query_type' => array(
|
||||
'type' => 'select',
|
||||
'std' => 'and',
|
||||
'label' => __( 'Query type', 'woocommerce' ),
|
||||
'options' => array(
|
||||
'and' => __( 'AND', 'woocommerce' ),
|
||||
'or' => __( 'OR', 'woocommerce' ),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this widgets taxonomy.
|
||||
*
|
||||
* @param array $instance Array of instance options.
|
||||
* @return string
|
||||
*/
|
||||
protected function get_instance_taxonomy( $instance ) {
|
||||
if ( isset( $instance['attribute'] ) ) {
|
||||
return wc_attribute_taxonomy_name( $instance['attribute'] );
|
||||
}
|
||||
|
||||
$attribute_taxonomies = wc_get_attribute_taxonomies();
|
||||
|
||||
if ( ! empty( $attribute_taxonomies ) ) {
|
||||
foreach ( $attribute_taxonomies as $tax ) {
|
||||
if ( taxonomy_exists( wc_attribute_taxonomy_name( $tax->attribute_name ) ) ) {
|
||||
return wc_attribute_taxonomy_name( $tax->attribute_name );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this widgets query type.
|
||||
*
|
||||
* @param array $instance Array of instance options.
|
||||
* @return string
|
||||
*/
|
||||
protected function get_instance_query_type( $instance ) {
|
||||
return isset( $instance['query_type'] ) ? $instance['query_type'] : 'and';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get this widgets display type.
|
||||
*
|
||||
* @param array $instance Array of instance options.
|
||||
* @return string
|
||||
*/
|
||||
protected function get_instance_display_type( $instance ) {
|
||||
return isset( $instance['display_type'] ) ? $instance['display_type'] : 'list';
|
||||
}
|
||||
|
||||
/**
|
||||
* Output widget.
|
||||
*
|
||||
* @see WP_Widget
|
||||
*
|
||||
* @param array $args Arguments.
|
||||
* @param array $instance Instance.
|
||||
*/
|
||||
public function widget( $args, $instance ) {
|
||||
if ( ! is_shop() && ! is_product_taxonomy() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$_chosen_attributes = WC_Query::get_layered_nav_chosen_attributes();
|
||||
$taxonomy = $this->get_instance_taxonomy( $instance );
|
||||
$query_type = $this->get_instance_query_type( $instance );
|
||||
$display_type = $this->get_instance_display_type( $instance );
|
||||
|
||||
if ( ! taxonomy_exists( $taxonomy ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$terms = get_terms( $taxonomy, array( 'hide_empty' => '1' ) );
|
||||
|
||||
if ( 0 === count( $terms ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
ob_start();
|
||||
|
||||
$this->widget_start( $args, $instance );
|
||||
|
||||
if ( 'dropdown' === $display_type ) {
|
||||
wp_enqueue_script( 'selectWoo' );
|
||||
wp_enqueue_style( 'select2' );
|
||||
$found = $this->layered_nav_dropdown( $terms, $taxonomy, $query_type );
|
||||
} else {
|
||||
$found = $this->layered_nav_list( $terms, $taxonomy, $query_type );
|
||||
}
|
||||
|
||||
$this->widget_end( $args );
|
||||
|
||||
// Force found when option is selected - do not force found on taxonomy attributes.
|
||||
if ( ! is_tax() && is_array( $_chosen_attributes ) && array_key_exists( $taxonomy, $_chosen_attributes ) ) {
|
||||
$found = true;
|
||||
}
|
||||
|
||||
if ( ! $found ) {
|
||||
ob_end_clean();
|
||||
} else {
|
||||
echo ob_get_clean(); // @codingStandardsIgnoreLine
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the currently viewed taxonomy name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function get_current_taxonomy() {
|
||||
return is_tax() ? get_queried_object()->taxonomy : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the currently viewed term ID.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function get_current_term_id() {
|
||||
return absint( is_tax() ? get_queried_object()->term_id : 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the currently viewed term slug.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function get_current_term_slug() {
|
||||
return absint( is_tax() ? get_queried_object()->slug : 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Show dropdown layered nav.
|
||||
*
|
||||
* @param array $terms Terms.
|
||||
* @param string $taxonomy Taxonomy.
|
||||
* @param string $query_type Query Type.
|
||||
* @return bool Will nav display?
|
||||
*/
|
||||
protected function layered_nav_dropdown( $terms, $taxonomy, $query_type ) {
|
||||
global $wp;
|
||||
$found = false;
|
||||
|
||||
if ( $taxonomy !== $this->get_current_taxonomy() ) {
|
||||
$term_counts = $this->get_filtered_term_product_counts( wp_list_pluck( $terms, 'term_id' ), $taxonomy, $query_type );
|
||||
$_chosen_attributes = WC_Query::get_layered_nav_chosen_attributes();
|
||||
$taxonomy_filter_name = wc_attribute_taxonomy_slug( $taxonomy );
|
||||
$taxonomy_label = wc_attribute_label( $taxonomy );
|
||||
|
||||
/* translators: %s: taxonomy name */
|
||||
$any_label = apply_filters( 'woocommerce_layered_nav_any_label', sprintf( __( 'Any %s', 'woocommerce' ), $taxonomy_label ), $taxonomy_label, $taxonomy );
|
||||
$multiple = 'or' === $query_type;
|
||||
$current_values = isset( $_chosen_attributes[ $taxonomy ]['terms'] ) ? $_chosen_attributes[ $taxonomy ]['terms'] : array();
|
||||
|
||||
if ( '' === get_option( 'permalink_structure' ) ) {
|
||||
$form_action = remove_query_arg( array( 'page', 'paged' ), add_query_arg( $wp->query_string, '', home_url( $wp->request ) ) );
|
||||
} else {
|
||||
$form_action = preg_replace( '%\/page/[0-9]+%', '', home_url( user_trailingslashit( $wp->request ) ) );
|
||||
}
|
||||
|
||||
echo '<form method="get" action="' . esc_url( $form_action ) . '" class="woocommerce-widget-layered-nav-dropdown">';
|
||||
echo '<select class="woocommerce-widget-layered-nav-dropdown dropdown_layered_nav_' . esc_attr( $taxonomy_filter_name ) . '"' . ( $multiple ? 'multiple="multiple"' : '' ) . '>';
|
||||
echo '<option value="">' . esc_html( $any_label ) . '</option>';
|
||||
|
||||
foreach ( $terms as $term ) {
|
||||
|
||||
// If on a term page, skip that term in widget list.
|
||||
if ( $term->term_id === $this->get_current_term_id() ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get count based on current view.
|
||||
$option_is_set = in_array( $term->slug, $current_values, true );
|
||||
$count = isset( $term_counts[ $term->term_id ] ) ? $term_counts[ $term->term_id ] : 0;
|
||||
|
||||
// Only show options with count > 0.
|
||||
if ( 0 < $count ) {
|
||||
$found = true;
|
||||
} elseif ( 0 === $count && ! $option_is_set ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
echo '<option value="' . esc_attr( urldecode( $term->slug ) ) . '" ' . selected( $option_is_set, true, false ) . '>' . esc_html( $term->name ) . '</option>';
|
||||
}
|
||||
|
||||
echo '</select>';
|
||||
|
||||
if ( $multiple ) {
|
||||
echo '<button class="woocommerce-widget-layered-nav-dropdown__submit" type="submit" value="' . esc_attr__( 'Apply', 'woocommerce' ) . '">' . esc_html__( 'Apply', 'woocommerce' ) . '</button>';
|
||||
}
|
||||
|
||||
if ( 'or' === $query_type ) {
|
||||
echo '<input type="hidden" name="query_type_' . esc_attr( $taxonomy_filter_name ) . '" value="or" />';
|
||||
}
|
||||
|
||||
echo '<input type="hidden" name="filter_' . esc_attr( $taxonomy_filter_name ) . '" value="' . esc_attr( implode( ',', $current_values ) ) . '" />';
|
||||
echo wc_query_string_form_fields( null, array( 'filter_' . $taxonomy_filter_name, 'query_type_' . $taxonomy_filter_name ), '', true ); // @codingStandardsIgnoreLine
|
||||
echo '</form>';
|
||||
|
||||
wc_enqueue_js(
|
||||
"
|
||||
// Update value on change.
|
||||
jQuery( '.dropdown_layered_nav_" . esc_js( $taxonomy_filter_name ) . "' ).on( 'change', function() {
|
||||
var slug = jQuery( this ).val();
|
||||
jQuery( ':input[name=\"filter_" . esc_js( $taxonomy_filter_name ) . "\"]' ).val( slug );
|
||||
|
||||
// Submit form on change if standard dropdown.
|
||||
if ( ! jQuery( this ).attr( 'multiple' ) ) {
|
||||
jQuery( this ).closest( 'form' ).trigger( 'submit' );
|
||||
}
|
||||
});
|
||||
|
||||
// Use Select2 enhancement if possible
|
||||
if ( jQuery().selectWoo ) {
|
||||
var wc_layered_nav_select = function() {
|
||||
jQuery( '.dropdown_layered_nav_" . esc_js( $taxonomy_filter_name ) . "' ).selectWoo( {
|
||||
placeholder: decodeURIComponent('" . rawurlencode( (string) wp_specialchars_decode( $any_label ) ) . "'),
|
||||
minimumResultsForSearch: 5,
|
||||
width: '100%',
|
||||
allowClear: " . ( $multiple ? 'false' : 'true' ) . ",
|
||||
language: {
|
||||
noResults: function() {
|
||||
return '" . esc_js( _x( 'No matches found', 'enhanced select', 'woocommerce' ) ) . "';
|
||||
}
|
||||
}
|
||||
} );
|
||||
};
|
||||
wc_layered_nav_select();
|
||||
}
|
||||
"
|
||||
);
|
||||
}
|
||||
|
||||
return $found;
|
||||
}
|
||||
|
||||
/**
|
||||
* Count products within certain terms, taking the main WP query into consideration.
|
||||
*
|
||||
* This query allows counts to be generated based on the viewed products, not all products.
|
||||
*
|
||||
* @param array $term_ids Term IDs.
|
||||
* @param string $taxonomy Taxonomy.
|
||||
* @param string $query_type Query Type.
|
||||
* @return array
|
||||
*/
|
||||
protected function get_filtered_term_product_counts( $term_ids, $taxonomy, $query_type ) {
|
||||
return wc_get_container()->get( Filterer::class )->get_filtered_term_product_counts( $term_ids, $taxonomy, $query_type );
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for WC_Query::get_main_tax_query() to ease unit testing.
|
||||
*
|
||||
* @since 4.4.0
|
||||
* @return array
|
||||
*/
|
||||
protected function get_main_tax_query() {
|
||||
return WC_Query::get_main_tax_query();
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for WC_Query::get_main_search_query_sql() to ease unit testing.
|
||||
*
|
||||
* @since 4.4.0
|
||||
* @return string
|
||||
*/
|
||||
protected function get_main_search_query_sql() {
|
||||
return WC_Query::get_main_search_query_sql();
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for WC_Query::get_main_search_queryget_main_meta_query to ease unit testing.
|
||||
*
|
||||
* @since 4.4.0
|
||||
* @return array
|
||||
*/
|
||||
protected function get_main_meta_query() {
|
||||
return WC_Query::get_main_meta_query();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show list based layered nav.
|
||||
*
|
||||
* @param array $terms Terms.
|
||||
* @param string $taxonomy Taxonomy.
|
||||
* @param string $query_type Query Type.
|
||||
* @return bool Will nav display?
|
||||
*/
|
||||
protected function layered_nav_list( $terms, $taxonomy, $query_type ) {
|
||||
// List display.
|
||||
echo '<ul class="woocommerce-widget-layered-nav-list">';
|
||||
|
||||
$term_counts = $this->get_filtered_term_product_counts( wp_list_pluck( $terms, 'term_id' ), $taxonomy, $query_type );
|
||||
$_chosen_attributes = WC_Query::get_layered_nav_chosen_attributes();
|
||||
$found = false;
|
||||
$base_link = $this->get_current_page_url();
|
||||
|
||||
foreach ( $terms as $term ) {
|
||||
$current_values = isset( $_chosen_attributes[ $taxonomy ]['terms'] ) ? $_chosen_attributes[ $taxonomy ]['terms'] : array();
|
||||
$option_is_set = in_array( $term->slug, $current_values, true );
|
||||
$count = isset( $term_counts[ $term->term_id ] ) ? $term_counts[ $term->term_id ] : 0;
|
||||
|
||||
// Skip the term for the current archive.
|
||||
if ( $this->get_current_term_id() === $term->term_id ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Only show options with count > 0.
|
||||
if ( 0 < $count ) {
|
||||
$found = true;
|
||||
} elseif ( 0 === $count && ! $option_is_set ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$filter_name = 'filter_' . wc_attribute_taxonomy_slug( $taxonomy );
|
||||
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
||||
$current_filter = isset( $_GET[ $filter_name ] ) ? explode( ',', wc_clean( wp_unslash( $_GET[ $filter_name ] ) ) ) : array();
|
||||
$current_filter = array_map( 'sanitize_title', $current_filter );
|
||||
|
||||
if ( ! in_array( $term->slug, $current_filter, true ) ) {
|
||||
$current_filter[] = $term->slug;
|
||||
}
|
||||
|
||||
$link = remove_query_arg( $filter_name, $base_link );
|
||||
|
||||
// Add current filters to URL.
|
||||
foreach ( $current_filter as $key => $value ) {
|
||||
// Exclude query arg for current term archive term.
|
||||
if ( $value === $this->get_current_term_slug() ) {
|
||||
unset( $current_filter[ $key ] );
|
||||
}
|
||||
|
||||
// Exclude self so filter can be unset on click.
|
||||
if ( $option_is_set && $value === $term->slug ) {
|
||||
unset( $current_filter[ $key ] );
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! empty( $current_filter ) ) {
|
||||
asort( $current_filter );
|
||||
$link = add_query_arg( $filter_name, implode( ',', $current_filter ), $link );
|
||||
|
||||
// Add Query type Arg to URL.
|
||||
if ( 'or' === $query_type && ! ( 1 === count( $current_filter ) && $option_is_set ) ) {
|
||||
$link = add_query_arg( 'query_type_' . wc_attribute_taxonomy_slug( $taxonomy ), 'or', $link );
|
||||
}
|
||||
$link = str_replace( '%2C', ',', $link );
|
||||
}
|
||||
|
||||
if ( $count > 0 || $option_is_set ) {
|
||||
$link = apply_filters( 'woocommerce_layered_nav_link', $link, $term, $taxonomy );
|
||||
$term_html = '<a rel="nofollow" href="' . esc_url( $link ) . '">' . esc_html( $term->name ) . '</a>';
|
||||
} else {
|
||||
$link = false;
|
||||
$term_html = '<span>' . esc_html( $term->name ) . '</span>';
|
||||
}
|
||||
|
||||
$term_html .= ' ' . apply_filters( 'woocommerce_layered_nav_count', '<span class="count">(' . absint( $count ) . ')</span>', $count, $term );
|
||||
|
||||
echo '<li class="woocommerce-widget-layered-nav-list__item wc-layered-nav-term ' . ( $option_is_set ? 'woocommerce-widget-layered-nav-list__item--chosen chosen' : '' ) . '">';
|
||||
// phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
echo apply_filters( 'woocommerce_layered_nav_term_html', $term_html, $term, $link, $count );
|
||||
echo '</li>';
|
||||
}
|
||||
|
||||
echo '</ul>';
|
||||
|
||||
return $found;
|
||||
}
|
||||
}
|
186
includes/widgets/class-wc-widget-price-filter.php
Normal file
186
includes/widgets/class-wc-widget-price-filter.php
Normal file
@ -0,0 +1,186 @@
|
||||
<?php
|
||||
/**
|
||||
* Price Filter Widget and related functions.
|
||||
*
|
||||
* Generates a range slider to filter products by price.
|
||||
*
|
||||
* @package WooCommerce\Widgets
|
||||
* @version 2.3.0
|
||||
*/
|
||||
|
||||
use Automattic\Jetpack\Constants;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Widget price filter class.
|
||||
*/
|
||||
class WC_Widget_Price_Filter extends WC_Widget {
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->widget_cssclass = 'woocommerce widget_price_filter';
|
||||
$this->widget_description = __( 'Display a slider to filter products in your store by price.', 'woocommerce' );
|
||||
$this->widget_id = 'woocommerce_price_filter';
|
||||
$this->widget_name = __( 'Filter Products by Price', 'woocommerce' );
|
||||
$this->settings = array(
|
||||
'title' => array(
|
||||
'type' => 'text',
|
||||
'std' => __( 'Filter by price', 'woocommerce' ),
|
||||
'label' => __( 'Title', 'woocommerce' ),
|
||||
),
|
||||
);
|
||||
$suffix = Constants::is_true( 'SCRIPT_DEBUG' ) ? '' : '.min';
|
||||
$version = Constants::get_constant( 'WC_VERSION' );
|
||||
wp_register_script( 'accounting', WC()->plugin_url() . '/assets/js/accounting/accounting' . $suffix . '.js', array( 'jquery' ), '0.4.2', true );
|
||||
wp_register_script( 'wc-jquery-ui-touchpunch', WC()->plugin_url() . '/assets/js/jquery-ui-touch-punch/jquery-ui-touch-punch' . $suffix . '.js', array( 'jquery-ui-slider' ), $version, true );
|
||||
wp_register_script( 'wc-price-slider', WC()->plugin_url() . '/assets/js/frontend/price-slider' . $suffix . '.js', array( 'jquery-ui-slider', 'wc-jquery-ui-touchpunch', 'accounting' ), $version, true );
|
||||
wp_localize_script(
|
||||
'wc-price-slider',
|
||||
'woocommerce_price_slider_params',
|
||||
array(
|
||||
'currency_format_num_decimals' => 0,
|
||||
'currency_format_symbol' => get_woocommerce_currency_symbol(),
|
||||
'currency_format_decimal_sep' => esc_attr( wc_get_price_decimal_separator() ),
|
||||
'currency_format_thousand_sep' => esc_attr( wc_get_price_thousand_separator() ),
|
||||
'currency_format' => esc_attr( str_replace( array( '%1$s', '%2$s' ), array( '%s', '%v' ), get_woocommerce_price_format() ) ),
|
||||
)
|
||||
);
|
||||
|
||||
if ( is_customize_preview() ) {
|
||||
wp_enqueue_script( 'wc-price-slider' );
|
||||
}
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Output widget.
|
||||
*
|
||||
* @see WP_Widget
|
||||
*
|
||||
* @param array $args Arguments.
|
||||
* @param array $instance Widget instance.
|
||||
*/
|
||||
public function widget( $args, $instance ) {
|
||||
global $wp;
|
||||
|
||||
// Requires lookup table added in 3.6.
|
||||
if ( version_compare( get_option( 'woocommerce_db_version', null ), '3.6', '<' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! is_shop() && ! is_product_taxonomy() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If there are not posts and we're not filtering, hide the widget.
|
||||
if ( ! WC()->query->get_main_query()->post_count && ! isset( $_GET['min_price'] ) && ! isset( $_GET['max_price'] ) ) { // WPCS: input var ok, CSRF ok.
|
||||
return;
|
||||
}
|
||||
|
||||
wp_enqueue_script( 'wc-price-slider' );
|
||||
|
||||
// Round values to nearest 10 by default.
|
||||
$step = max( apply_filters( 'woocommerce_price_filter_widget_step', 10 ), 1 );
|
||||
|
||||
// Find min and max price in current result set.
|
||||
$prices = $this->get_filtered_price();
|
||||
$min_price = $prices->min_price;
|
||||
$max_price = $prices->max_price;
|
||||
|
||||
// Check to see if we should add taxes to the prices if store are excl tax but display incl.
|
||||
$tax_display_mode = get_option( 'woocommerce_tax_display_shop' );
|
||||
|
||||
if ( wc_tax_enabled() && ! wc_prices_include_tax() && 'incl' === $tax_display_mode ) {
|
||||
$tax_class = apply_filters( 'woocommerce_price_filter_widget_tax_class', '' ); // Uses standard tax class.
|
||||
$tax_rates = WC_Tax::get_rates( $tax_class );
|
||||
|
||||
if ( $tax_rates ) {
|
||||
$min_price += WC_Tax::get_tax_total( WC_Tax::calc_exclusive_tax( $min_price, $tax_rates ) );
|
||||
$max_price += WC_Tax::get_tax_total( WC_Tax::calc_exclusive_tax( $max_price, $tax_rates ) );
|
||||
}
|
||||
}
|
||||
|
||||
$min_price = apply_filters( 'woocommerce_price_filter_widget_min_amount', floor( $min_price / $step ) * $step );
|
||||
$max_price = apply_filters( 'woocommerce_price_filter_widget_max_amount', ceil( $max_price / $step ) * $step );
|
||||
|
||||
// If both min and max are equal, we don't need a slider.
|
||||
if ( $min_price === $max_price ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$current_min_price = isset( $_GET['min_price'] ) ? floor( floatval( wp_unslash( $_GET['min_price'] ) ) / $step ) * $step : $min_price; // WPCS: input var ok, CSRF ok.
|
||||
$current_max_price = isset( $_GET['max_price'] ) ? ceil( floatval( wp_unslash( $_GET['max_price'] ) ) / $step ) * $step : $max_price; // WPCS: input var ok, CSRF ok.
|
||||
|
||||
$this->widget_start( $args, $instance );
|
||||
|
||||
if ( '' === get_option( 'permalink_structure' ) ) {
|
||||
$form_action = remove_query_arg( array( 'page', 'paged', 'product-page' ), add_query_arg( $wp->query_string, '', home_url( $wp->request ) ) );
|
||||
} else {
|
||||
$form_action = preg_replace( '%\/page/[0-9]+%', '', home_url( trailingslashit( $wp->request ) ) );
|
||||
}
|
||||
|
||||
wc_get_template(
|
||||
'content-widget-price-filter.php',
|
||||
array(
|
||||
'form_action' => $form_action,
|
||||
'step' => $step,
|
||||
'min_price' => $min_price,
|
||||
'max_price' => $max_price,
|
||||
'current_min_price' => $current_min_price,
|
||||
'current_max_price' => $current_max_price,
|
||||
)
|
||||
);
|
||||
|
||||
$this->widget_end( $args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get filtered min price for current products.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function get_filtered_price() {
|
||||
global $wpdb;
|
||||
|
||||
$args = WC()->query->get_main_query()->query_vars;
|
||||
$tax_query = isset( $args['tax_query'] ) ? $args['tax_query'] : array();
|
||||
$meta_query = isset( $args['meta_query'] ) ? $args['meta_query'] : array();
|
||||
|
||||
if ( ! is_post_type_archive( 'product' ) && ! empty( $args['taxonomy'] ) && ! empty( $args['term'] ) ) {
|
||||
$tax_query[] = WC()->query->get_main_tax_query();
|
||||
}
|
||||
|
||||
foreach ( $meta_query + $tax_query as $key => $query ) {
|
||||
if ( ! empty( $query['price_filter'] ) || ! empty( $query['rating_filter'] ) ) {
|
||||
unset( $meta_query[ $key ] );
|
||||
}
|
||||
}
|
||||
|
||||
$meta_query = new WP_Meta_Query( $meta_query );
|
||||
$tax_query = new WP_Tax_Query( $tax_query );
|
||||
$search = WC_Query::get_main_search_query_sql();
|
||||
|
||||
$meta_query_sql = $meta_query->get_sql( 'post', $wpdb->posts, 'ID' );
|
||||
$tax_query_sql = $tax_query->get_sql( $wpdb->posts, 'ID' );
|
||||
$search_query_sql = $search ? ' AND ' . $search : '';
|
||||
|
||||
$sql = "
|
||||
SELECT min( min_price ) as min_price, MAX( max_price ) as max_price
|
||||
FROM {$wpdb->wc_product_meta_lookup}
|
||||
WHERE product_id IN (
|
||||
SELECT ID FROM {$wpdb->posts}
|
||||
" . $tax_query_sql['join'] . $meta_query_sql['join'] . "
|
||||
WHERE {$wpdb->posts}.post_type IN ('" . implode( "','", array_map( 'esc_sql', apply_filters( 'woocommerce_price_filter_post_type', array( 'product' ) ) ) ) . "')
|
||||
AND {$wpdb->posts}.post_status = 'publish'
|
||||
" . $tax_query_sql['where'] . $meta_query_sql['where'] . $search_query_sql . '
|
||||
)';
|
||||
|
||||
$sql = apply_filters( 'woocommerce_price_filter_sql', $sql, $meta_query_sql, $tax_query_sql );
|
||||
|
||||
return $wpdb->get_row( $sql ); // WPCS: unprepared SQL ok.
|
||||
}
|
||||
}
|
301
includes/widgets/class-wc-widget-product-categories.php
Normal file
301
includes/widgets/class-wc-widget-product-categories.php
Normal file
@ -0,0 +1,301 @@
|
||||
<?php
|
||||
/**
|
||||
* Product Categories Widget
|
||||
*
|
||||
* @package WooCommerce\Widgets
|
||||
* @version 2.3.0
|
||||
*/
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Product categories widget class.
|
||||
*
|
||||
* @extends WC_Widget
|
||||
*/
|
||||
class WC_Widget_Product_Categories extends WC_Widget {
|
||||
|
||||
/**
|
||||
* Category ancestors.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $cat_ancestors;
|
||||
|
||||
/**
|
||||
* Current Category.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $current_cat;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->widget_cssclass = 'woocommerce widget_product_categories';
|
||||
$this->widget_description = __( 'A list or dropdown of product categories.', 'woocommerce' );
|
||||
$this->widget_id = 'woocommerce_product_categories';
|
||||
$this->widget_name = __( 'Product Categories', 'woocommerce' );
|
||||
$this->settings = array(
|
||||
'title' => array(
|
||||
'type' => 'text',
|
||||
'std' => __( 'Product categories', 'woocommerce' ),
|
||||
'label' => __( 'Title', 'woocommerce' ),
|
||||
),
|
||||
'orderby' => array(
|
||||
'type' => 'select',
|
||||
'std' => 'name',
|
||||
'label' => __( 'Order by', 'woocommerce' ),
|
||||
'options' => array(
|
||||
'order' => __( 'Category order', 'woocommerce' ),
|
||||
'name' => __( 'Name', 'woocommerce' ),
|
||||
),
|
||||
),
|
||||
'dropdown' => array(
|
||||
'type' => 'checkbox',
|
||||
'std' => 0,
|
||||
'label' => __( 'Show as dropdown', 'woocommerce' ),
|
||||
),
|
||||
'count' => array(
|
||||
'type' => 'checkbox',
|
||||
'std' => 0,
|
||||
'label' => __( 'Show product counts', 'woocommerce' ),
|
||||
),
|
||||
'hierarchical' => array(
|
||||
'type' => 'checkbox',
|
||||
'std' => 1,
|
||||
'label' => __( 'Show hierarchy', 'woocommerce' ),
|
||||
),
|
||||
'show_children_only' => array(
|
||||
'type' => 'checkbox',
|
||||
'std' => 0,
|
||||
'label' => __( 'Only show children of the current category', 'woocommerce' ),
|
||||
),
|
||||
'hide_empty' => array(
|
||||
'type' => 'checkbox',
|
||||
'std' => 0,
|
||||
'label' => __( 'Hide empty categories', 'woocommerce' ),
|
||||
),
|
||||
'max_depth' => array(
|
||||
'type' => 'text',
|
||||
'std' => '',
|
||||
'label' => __( 'Maximum depth', 'woocommerce' ),
|
||||
),
|
||||
);
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Output widget.
|
||||
*
|
||||
* @see WP_Widget
|
||||
* @param array $args Widget arguments.
|
||||
* @param array $instance Widget instance.
|
||||
*/
|
||||
public function widget( $args, $instance ) {
|
||||
global $wp_query, $post;
|
||||
|
||||
$count = isset( $instance['count'] ) ? $instance['count'] : $this->settings['count']['std'];
|
||||
$hierarchical = isset( $instance['hierarchical'] ) ? $instance['hierarchical'] : $this->settings['hierarchical']['std'];
|
||||
$show_children_only = isset( $instance['show_children_only'] ) ? $instance['show_children_only'] : $this->settings['show_children_only']['std'];
|
||||
$dropdown = isset( $instance['dropdown'] ) ? $instance['dropdown'] : $this->settings['dropdown']['std'];
|
||||
$orderby = isset( $instance['orderby'] ) ? $instance['orderby'] : $this->settings['orderby']['std'];
|
||||
$hide_empty = isset( $instance['hide_empty'] ) ? $instance['hide_empty'] : $this->settings['hide_empty']['std'];
|
||||
$dropdown_args = array(
|
||||
'hide_empty' => $hide_empty,
|
||||
);
|
||||
$list_args = array(
|
||||
'show_count' => $count,
|
||||
'hierarchical' => $hierarchical,
|
||||
'taxonomy' => 'product_cat',
|
||||
'hide_empty' => $hide_empty,
|
||||
);
|
||||
$max_depth = absint( isset( $instance['max_depth'] ) ? $instance['max_depth'] : $this->settings['max_depth']['std'] );
|
||||
|
||||
$list_args['menu_order'] = false;
|
||||
$dropdown_args['depth'] = $max_depth;
|
||||
$list_args['depth'] = $max_depth;
|
||||
|
||||
if ( 'order' === $orderby ) {
|
||||
$list_args['orderby'] = 'meta_value_num';
|
||||
$dropdown_args['orderby'] = 'meta_value_num';
|
||||
$list_args['meta_key'] = 'order';
|
||||
$dropdown_args['meta_key'] = 'order';
|
||||
}
|
||||
|
||||
$this->current_cat = false;
|
||||
$this->cat_ancestors = array();
|
||||
|
||||
if ( is_tax( 'product_cat' ) ) {
|
||||
$this->current_cat = $wp_query->queried_object;
|
||||
$this->cat_ancestors = get_ancestors( $this->current_cat->term_id, 'product_cat' );
|
||||
|
||||
} elseif ( is_singular( 'product' ) ) {
|
||||
$terms = wc_get_product_terms(
|
||||
$post->ID,
|
||||
'product_cat',
|
||||
apply_filters(
|
||||
'woocommerce_product_categories_widget_product_terms_args',
|
||||
array(
|
||||
'orderby' => 'parent',
|
||||
'order' => 'DESC',
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
if ( $terms ) {
|
||||
$main_term = apply_filters( 'woocommerce_product_categories_widget_main_term', $terms[0], $terms );
|
||||
$this->current_cat = $main_term;
|
||||
$this->cat_ancestors = get_ancestors( $main_term->term_id, 'product_cat' );
|
||||
}
|
||||
}
|
||||
|
||||
// Show Siblings and Children Only.
|
||||
if ( $show_children_only && $this->current_cat ) {
|
||||
if ( $hierarchical ) {
|
||||
$include = array_merge(
|
||||
$this->cat_ancestors,
|
||||
array( $this->current_cat->term_id ),
|
||||
get_terms(
|
||||
'product_cat',
|
||||
array(
|
||||
'fields' => 'ids',
|
||||
'parent' => 0,
|
||||
'hierarchical' => true,
|
||||
'hide_empty' => false,
|
||||
)
|
||||
),
|
||||
get_terms(
|
||||
'product_cat',
|
||||
array(
|
||||
'fields' => 'ids',
|
||||
'parent' => $this->current_cat->term_id,
|
||||
'hierarchical' => true,
|
||||
'hide_empty' => false,
|
||||
)
|
||||
)
|
||||
);
|
||||
// Gather siblings of ancestors.
|
||||
if ( $this->cat_ancestors ) {
|
||||
foreach ( $this->cat_ancestors as $ancestor ) {
|
||||
$include = array_merge(
|
||||
$include,
|
||||
get_terms(
|
||||
'product_cat',
|
||||
array(
|
||||
'fields' => 'ids',
|
||||
'parent' => $ancestor,
|
||||
'hierarchical' => false,
|
||||
'hide_empty' => false,
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Direct children.
|
||||
$include = get_terms(
|
||||
'product_cat',
|
||||
array(
|
||||
'fields' => 'ids',
|
||||
'parent' => $this->current_cat->term_id,
|
||||
'hierarchical' => true,
|
||||
'hide_empty' => false,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$list_args['include'] = implode( ',', $include );
|
||||
$dropdown_args['include'] = $list_args['include'];
|
||||
|
||||
if ( empty( $include ) ) {
|
||||
return;
|
||||
}
|
||||
} elseif ( $show_children_only ) {
|
||||
$dropdown_args['depth'] = 1;
|
||||
$dropdown_args['child_of'] = 0;
|
||||
$dropdown_args['hierarchical'] = 1;
|
||||
$list_args['depth'] = 1;
|
||||
$list_args['child_of'] = 0;
|
||||
$list_args['hierarchical'] = 1;
|
||||
}
|
||||
|
||||
$this->widget_start( $args, $instance );
|
||||
|
||||
if ( $dropdown ) {
|
||||
wc_product_dropdown_categories(
|
||||
apply_filters(
|
||||
'woocommerce_product_categories_widget_dropdown_args',
|
||||
wp_parse_args(
|
||||
$dropdown_args,
|
||||
array(
|
||||
'show_count' => $count,
|
||||
'hierarchical' => $hierarchical,
|
||||
'show_uncategorized' => 0,
|
||||
'selected' => $this->current_cat ? $this->current_cat->slug : '',
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
wp_enqueue_script( 'selectWoo' );
|
||||
wp_enqueue_style( 'select2' );
|
||||
|
||||
wc_enqueue_js(
|
||||
"
|
||||
jQuery( '.dropdown_product_cat' ).on( 'change', function() {
|
||||
if ( jQuery(this).val() != '' ) {
|
||||
var this_page = '';
|
||||
var home_url = '" . esc_js( home_url( '/' ) ) . "';
|
||||
if ( home_url.indexOf( '?' ) > 0 ) {
|
||||
this_page = home_url + '&product_cat=' + jQuery(this).val();
|
||||
} else {
|
||||
this_page = home_url + '?product_cat=' + jQuery(this).val();
|
||||
}
|
||||
location.href = this_page;
|
||||
} else {
|
||||
location.href = '" . esc_js( wc_get_page_permalink( 'shop' ) ) . "';
|
||||
}
|
||||
});
|
||||
|
||||
if ( jQuery().selectWoo ) {
|
||||
var wc_product_cat_select = function() {
|
||||
jQuery( '.dropdown_product_cat' ).selectWoo( {
|
||||
placeholder: '" . esc_js( __( 'Select a category', 'woocommerce' ) ) . "',
|
||||
minimumResultsForSearch: 5,
|
||||
width: '100%',
|
||||
allowClear: true,
|
||||
language: {
|
||||
noResults: function() {
|
||||
return '" . esc_js( _x( 'No matches found', 'enhanced select', 'woocommerce' ) ) . "';
|
||||
}
|
||||
}
|
||||
} );
|
||||
};
|
||||
wc_product_cat_select();
|
||||
}
|
||||
"
|
||||
);
|
||||
} else {
|
||||
include_once WC()->plugin_path() . '/includes/walkers/class-wc-product-cat-list-walker.php';
|
||||
|
||||
$list_args['walker'] = new WC_Product_Cat_List_Walker();
|
||||
$list_args['title_li'] = '';
|
||||
$list_args['pad_counts'] = 1;
|
||||
$list_args['show_option_none'] = __( 'No product categories exist.', 'woocommerce' );
|
||||
$list_args['current_category'] = ( $this->current_cat ) ? $this->current_cat->term_id : '';
|
||||
$list_args['current_category_ancestors'] = $this->cat_ancestors;
|
||||
$list_args['max_depth'] = $max_depth;
|
||||
|
||||
echo '<ul class="product-categories">';
|
||||
|
||||
wp_list_categories( apply_filters( 'woocommerce_product_categories_widget_args', $list_args ) );
|
||||
|
||||
echo '</ul>';
|
||||
}
|
||||
|
||||
$this->widget_end( $args );
|
||||
}
|
||||
}
|
50
includes/widgets/class-wc-widget-product-search.php
Normal file
50
includes/widgets/class-wc-widget-product-search.php
Normal file
@ -0,0 +1,50 @@
|
||||
<?php
|
||||
/**
|
||||
* Product Search Widget.
|
||||
*
|
||||
* @package WooCommerce\Widgets
|
||||
* @version 2.3.0
|
||||
*/
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Widget product search class.
|
||||
*/
|
||||
class WC_Widget_Product_Search extends WC_Widget {
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->widget_cssclass = 'woocommerce widget_product_search';
|
||||
$this->widget_description = __( 'A search form for your store.', 'woocommerce' );
|
||||
$this->widget_id = 'woocommerce_product_search';
|
||||
$this->widget_name = __( 'Product Search', 'woocommerce' );
|
||||
$this->settings = array(
|
||||
'title' => array(
|
||||
'type' => 'text',
|
||||
'std' => '',
|
||||
'label' => __( 'Title', 'woocommerce' ),
|
||||
),
|
||||
);
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Output widget.
|
||||
*
|
||||
* @see WP_Widget
|
||||
*
|
||||
* @param array $args Arguments.
|
||||
* @param array $instance Widget instance.
|
||||
*/
|
||||
public function widget( $args, $instance ) {
|
||||
$this->widget_start( $args, $instance );
|
||||
|
||||
get_product_search_form();
|
||||
|
||||
$this->widget_end( $args );
|
||||
}
|
||||
}
|
121
includes/widgets/class-wc-widget-product-tag-cloud.php
Normal file
121
includes/widgets/class-wc-widget-product-tag-cloud.php
Normal file
@ -0,0 +1,121 @@
|
||||
<?php
|
||||
/**
|
||||
* Tag Cloud Widget.
|
||||
*
|
||||
* @package WooCommerce\Widgets
|
||||
* @version 3.4.0
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Widget product tag cloud
|
||||
*/
|
||||
class WC_Widget_Product_Tag_Cloud extends WC_Widget {
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->widget_cssclass = 'woocommerce widget_product_tag_cloud';
|
||||
$this->widget_description = __( 'A cloud of your most used product tags.', 'woocommerce' );
|
||||
$this->widget_id = 'woocommerce_product_tag_cloud';
|
||||
$this->widget_name = __( 'Product Tag Cloud', 'woocommerce' );
|
||||
$this->settings = array(
|
||||
'title' => array(
|
||||
'type' => 'text',
|
||||
'std' => __( 'Product tags', 'woocommerce' ),
|
||||
'label' => __( 'Title', 'woocommerce' ),
|
||||
),
|
||||
);
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Output widget.
|
||||
*
|
||||
* @see WP_Widget
|
||||
*
|
||||
* @param array $args Arguments.
|
||||
* @param array $instance Widget instance.
|
||||
*/
|
||||
public function widget( $args, $instance ) {
|
||||
$current_taxonomy = $this->get_current_taxonomy( $instance );
|
||||
|
||||
if ( empty( $instance['title'] ) ) {
|
||||
$taxonomy = get_taxonomy( $current_taxonomy );
|
||||
$instance['title'] = $taxonomy->labels->name;
|
||||
}
|
||||
|
||||
$this->widget_start( $args, $instance );
|
||||
|
||||
echo '<div class="tagcloud">';
|
||||
|
||||
wp_tag_cloud(
|
||||
apply_filters(
|
||||
'woocommerce_product_tag_cloud_widget_args',
|
||||
array(
|
||||
'taxonomy' => $current_taxonomy,
|
||||
'topic_count_text_callback' => array( $this, 'topic_count_text' ),
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
echo '</div>';
|
||||
|
||||
$this->widget_end( $args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the taxonomy being displayed.
|
||||
*
|
||||
* @param object $instance Widget instance.
|
||||
* @return string
|
||||
*/
|
||||
public function get_current_taxonomy( $instance ) {
|
||||
return 'product_tag';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns topic count text.
|
||||
*
|
||||
* @since 3.4.0
|
||||
* @param int $count Count text.
|
||||
* @return string
|
||||
*/
|
||||
public function topic_count_text( $count ) {
|
||||
/* translators: %s: product count */
|
||||
return sprintf( _n( '%s product', '%s products', $count, 'woocommerce' ), number_format_i18n( $count ) );
|
||||
}
|
||||
|
||||
// Ignore whole block to avoid warnings about PSR2.Methods.MethodDeclaration.Underscore violation.
|
||||
// @codingStandardsIgnoreStart
|
||||
/**
|
||||
* Return the taxonomy being displayed.
|
||||
*
|
||||
* @deprecated 3.4.0
|
||||
* @param object $instance Widget instance.
|
||||
* @return string
|
||||
*/
|
||||
public function _get_current_taxonomy( $instance ) {
|
||||
wc_deprecated_function( '_get_current_taxonomy', '3.4.0', 'WC_Widget_Product_Tag_Cloud->get_current_taxonomy' );
|
||||
return $this->get_current_taxonomy( $instance );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns topic count text.
|
||||
*
|
||||
* @deprecated 3.4.0
|
||||
* @since 2.6.0
|
||||
* @param int $count Count text.
|
||||
* @return string
|
||||
*/
|
||||
public function _topic_count_text( $count ) {
|
||||
wc_deprecated_function( '_topic_count_text', '3.4.0', 'WC_Widget_Product_Tag_Cloud->topic_count_text' );
|
||||
return $this->topic_count_text( $count );
|
||||
}
|
||||
// @codingStandardsIgnoreEnd
|
||||
}
|
216
includes/widgets/class-wc-widget-products.php
Normal file
216
includes/widgets/class-wc-widget-products.php
Normal file
@ -0,0 +1,216 @@
|
||||
<?php
|
||||
/**
|
||||
* List products. One widget to rule them all.
|
||||
*
|
||||
* @package WooCommerce\Widgets
|
||||
* @version 3.3.0
|
||||
*/
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Widget products.
|
||||
*/
|
||||
class WC_Widget_Products extends WC_Widget {
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->widget_cssclass = 'woocommerce widget_products';
|
||||
$this->widget_description = __( "A list of your store's products.", 'woocommerce' );
|
||||
$this->widget_id = 'woocommerce_products';
|
||||
$this->widget_name = __( 'Products list', 'woocommerce' );
|
||||
$this->settings = array(
|
||||
'title' => array(
|
||||
'type' => 'text',
|
||||
'std' => __( 'Products', 'woocommerce' ),
|
||||
'label' => __( 'Title', 'woocommerce' ),
|
||||
),
|
||||
'number' => array(
|
||||
'type' => 'number',
|
||||
'step' => 1,
|
||||
'min' => 1,
|
||||
'max' => '',
|
||||
'std' => 5,
|
||||
'label' => __( 'Number of products to show', 'woocommerce' ),
|
||||
),
|
||||
'show' => array(
|
||||
'type' => 'select',
|
||||
'std' => '',
|
||||
'label' => __( 'Show', 'woocommerce' ),
|
||||
'options' => array(
|
||||
'' => __( 'All products', 'woocommerce' ),
|
||||
'featured' => __( 'Featured products', 'woocommerce' ),
|
||||
'onsale' => __( 'On-sale products', 'woocommerce' ),
|
||||
),
|
||||
),
|
||||
'orderby' => array(
|
||||
'type' => 'select',
|
||||
'std' => 'date',
|
||||
'label' => __( 'Order by', 'woocommerce' ),
|
||||
'options' => array(
|
||||
'date' => __( 'Date', 'woocommerce' ),
|
||||
'price' => __( 'Price', 'woocommerce' ),
|
||||
'rand' => __( 'Random', 'woocommerce' ),
|
||||
'sales' => __( 'Sales', 'woocommerce' ),
|
||||
),
|
||||
),
|
||||
'order' => array(
|
||||
'type' => 'select',
|
||||
'std' => 'desc',
|
||||
'label' => _x( 'Order', 'Sorting order', 'woocommerce' ),
|
||||
'options' => array(
|
||||
'asc' => __( 'ASC', 'woocommerce' ),
|
||||
'desc' => __( 'DESC', 'woocommerce' ),
|
||||
),
|
||||
),
|
||||
'hide_free' => array(
|
||||
'type' => 'checkbox',
|
||||
'std' => 0,
|
||||
'label' => __( 'Hide free products', 'woocommerce' ),
|
||||
),
|
||||
'show_hidden' => array(
|
||||
'type' => 'checkbox',
|
||||
'std' => 0,
|
||||
'label' => __( 'Show hidden products', 'woocommerce' ),
|
||||
),
|
||||
);
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Query the products and return them.
|
||||
*
|
||||
* @param array $args Arguments.
|
||||
* @param array $instance Widget instance.
|
||||
*
|
||||
* @return WP_Query
|
||||
*/
|
||||
public function get_products( $args, $instance ) {
|
||||
$number = ! empty( $instance['number'] ) ? absint( $instance['number'] ) : $this->settings['number']['std'];
|
||||
$show = ! empty( $instance['show'] ) ? sanitize_title( $instance['show'] ) : $this->settings['show']['std'];
|
||||
$orderby = ! empty( $instance['orderby'] ) ? sanitize_title( $instance['orderby'] ) : $this->settings['orderby']['std'];
|
||||
$order = ! empty( $instance['order'] ) ? sanitize_title( $instance['order'] ) : $this->settings['order']['std'];
|
||||
$product_visibility_term_ids = wc_get_product_visibility_term_ids();
|
||||
|
||||
$query_args = array(
|
||||
'posts_per_page' => $number,
|
||||
'post_status' => 'publish',
|
||||
'post_type' => 'product',
|
||||
'no_found_rows' => 1,
|
||||
'order' => $order,
|
||||
'meta_query' => array(),
|
||||
'tax_query' => array(
|
||||
'relation' => 'AND',
|
||||
),
|
||||
); // WPCS: slow query ok.
|
||||
|
||||
if ( empty( $instance['show_hidden'] ) ) {
|
||||
$query_args['tax_query'][] = array(
|
||||
'taxonomy' => 'product_visibility',
|
||||
'field' => 'term_taxonomy_id',
|
||||
'terms' => is_search() ? $product_visibility_term_ids['exclude-from-search'] : $product_visibility_term_ids['exclude-from-catalog'],
|
||||
'operator' => 'NOT IN',
|
||||
);
|
||||
$query_args['post_parent'] = 0;
|
||||
}
|
||||
|
||||
if ( ! empty( $instance['hide_free'] ) ) {
|
||||
$query_args['meta_query'][] = array(
|
||||
'key' => '_price',
|
||||
'value' => 0,
|
||||
'compare' => '>',
|
||||
'type' => 'DECIMAL',
|
||||
);
|
||||
}
|
||||
|
||||
if ( 'yes' === get_option( 'woocommerce_hide_out_of_stock_items' ) ) {
|
||||
$query_args['tax_query'][] = array(
|
||||
array(
|
||||
'taxonomy' => 'product_visibility',
|
||||
'field' => 'term_taxonomy_id',
|
||||
'terms' => $product_visibility_term_ids['outofstock'],
|
||||
'operator' => 'NOT IN',
|
||||
),
|
||||
); // WPCS: slow query ok.
|
||||
}
|
||||
|
||||
switch ( $show ) {
|
||||
case 'featured':
|
||||
$query_args['tax_query'][] = array(
|
||||
'taxonomy' => 'product_visibility',
|
||||
'field' => 'term_taxonomy_id',
|
||||
'terms' => $product_visibility_term_ids['featured'],
|
||||
);
|
||||
break;
|
||||
case 'onsale':
|
||||
$product_ids_on_sale = wc_get_product_ids_on_sale();
|
||||
$product_ids_on_sale[] = 0;
|
||||
$query_args['post__in'] = $product_ids_on_sale;
|
||||
break;
|
||||
}
|
||||
|
||||
switch ( $orderby ) {
|
||||
case 'price':
|
||||
$query_args['meta_key'] = '_price'; // WPCS: slow query ok.
|
||||
$query_args['orderby'] = 'meta_value_num';
|
||||
break;
|
||||
case 'rand':
|
||||
$query_args['orderby'] = 'rand';
|
||||
break;
|
||||
case 'sales':
|
||||
$query_args['meta_key'] = 'total_sales'; // WPCS: slow query ok.
|
||||
$query_args['orderby'] = 'meta_value_num';
|
||||
break;
|
||||
default:
|
||||
$query_args['orderby'] = 'date';
|
||||
}
|
||||
|
||||
return new WP_Query( apply_filters( 'woocommerce_products_widget_query_args', $query_args ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Output widget.
|
||||
*
|
||||
* @param array $args Arguments.
|
||||
* @param array $instance Widget instance.
|
||||
*
|
||||
* @see WP_Widget
|
||||
*/
|
||||
public function widget( $args, $instance ) {
|
||||
if ( $this->get_cached_widget( $args ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
ob_start();
|
||||
|
||||
wc_set_loop_prop( 'name', 'widget' );
|
||||
|
||||
$products = $this->get_products( $args, $instance );
|
||||
if ( $products && $products->have_posts() ) {
|
||||
$this->widget_start( $args, $instance );
|
||||
|
||||
echo wp_kses_post( apply_filters( 'woocommerce_before_widget_product_list', '<ul class="product_list_widget">' ) );
|
||||
|
||||
$template_args = array(
|
||||
'widget_id' => isset( $args['widget_id'] ) ? $args['widget_id'] : $this->widget_id,
|
||||
'show_rating' => true,
|
||||
);
|
||||
|
||||
while ( $products->have_posts() ) {
|
||||
$products->the_post();
|
||||
wc_get_template( 'content-widget-product.php', $template_args );
|
||||
}
|
||||
|
||||
echo wp_kses_post( apply_filters( 'woocommerce_after_widget_product_list', '</ul>' ) );
|
||||
|
||||
$this->widget_end( $args );
|
||||
}
|
||||
|
||||
wp_reset_postdata();
|
||||
|
||||
echo $this->cache_widget( $args, ob_get_clean() ); // WPCS: XSS ok.
|
||||
}
|
||||
}
|
147
includes/widgets/class-wc-widget-rating-filter.php
Normal file
147
includes/widgets/class-wc-widget-rating-filter.php
Normal file
@ -0,0 +1,147 @@
|
||||
<?php
|
||||
/**
|
||||
* Rating Filter Widget and related functions.
|
||||
*
|
||||
* @package WooCommerce\Widgets
|
||||
* @version 2.6.0
|
||||
*/
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Widget rating filter class.
|
||||
*/
|
||||
class WC_Widget_Rating_Filter extends WC_Widget {
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->widget_cssclass = 'woocommerce widget_rating_filter';
|
||||
$this->widget_description = __( 'Display a list of star ratings to filter products in your store.', 'woocommerce' );
|
||||
$this->widget_id = 'woocommerce_rating_filter';
|
||||
$this->widget_name = __( 'Filter Products by Rating', 'woocommerce' );
|
||||
$this->settings = array(
|
||||
'title' => array(
|
||||
'type' => 'text',
|
||||
'std' => __( 'Average rating', 'woocommerce' ),
|
||||
'label' => __( 'Title', 'woocommerce' ),
|
||||
),
|
||||
);
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Count products after other filters have occurred by adjusting the main query.
|
||||
*
|
||||
* @param int $rating Rating.
|
||||
* @return int
|
||||
*/
|
||||
protected function get_filtered_product_count( $rating ) {
|
||||
global $wpdb;
|
||||
|
||||
$tax_query = WC_Query::get_main_tax_query();
|
||||
$meta_query = WC_Query::get_main_meta_query();
|
||||
|
||||
// Unset current rating filter.
|
||||
foreach ( $tax_query as $key => $query ) {
|
||||
if ( ! empty( $query['rating_filter'] ) ) {
|
||||
unset( $tax_query[ $key ] );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Set new rating filter.
|
||||
$product_visibility_terms = wc_get_product_visibility_term_ids();
|
||||
$tax_query[] = array(
|
||||
'taxonomy' => 'product_visibility',
|
||||
'field' => 'term_taxonomy_id',
|
||||
'terms' => $product_visibility_terms[ 'rated-' . $rating ],
|
||||
'operator' => 'IN',
|
||||
'rating_filter' => true,
|
||||
);
|
||||
|
||||
$meta_query = new WP_Meta_Query( $meta_query );
|
||||
$tax_query = new WP_Tax_Query( $tax_query );
|
||||
$meta_query_sql = $meta_query->get_sql( 'post', $wpdb->posts, 'ID' );
|
||||
$tax_query_sql = $tax_query->get_sql( $wpdb->posts, 'ID' );
|
||||
|
||||
$sql = "SELECT COUNT( DISTINCT {$wpdb->posts}.ID ) FROM {$wpdb->posts} ";
|
||||
$sql .= $tax_query_sql['join'] . $meta_query_sql['join'];
|
||||
$sql .= " WHERE {$wpdb->posts}.post_type = 'product' AND {$wpdb->posts}.post_status = 'publish' ";
|
||||
$sql .= $tax_query_sql['where'] . $meta_query_sql['where'];
|
||||
|
||||
$search = WC_Query::get_main_search_query_sql();
|
||||
if ( $search ) {
|
||||
$sql .= ' AND ' . $search;
|
||||
}
|
||||
|
||||
return absint( $wpdb->get_var( $sql ) ); // WPCS: unprepared SQL ok.
|
||||
}
|
||||
|
||||
/**
|
||||
* Widget function.
|
||||
*
|
||||
* @see WP_Widget
|
||||
* @param array $args Arguments.
|
||||
* @param array $instance Widget instance.
|
||||
*/
|
||||
public function widget( $args, $instance ) {
|
||||
if ( ! is_shop() && ! is_product_taxonomy() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! WC()->query->get_main_query()->post_count ) {
|
||||
return;
|
||||
}
|
||||
|
||||
ob_start();
|
||||
|
||||
$found = false;
|
||||
$rating_filter = isset( $_GET['rating_filter'] ) ? array_filter( array_map( 'absint', explode( ',', wp_unslash( $_GET['rating_filter'] ) ) ) ) : array(); // WPCS: input var ok, CSRF ok, sanitization ok.
|
||||
$base_link = remove_query_arg( 'paged', $this->get_current_page_url() );
|
||||
|
||||
$this->widget_start( $args, $instance );
|
||||
|
||||
echo '<ul>';
|
||||
|
||||
for ( $rating = 5; $rating >= 1; $rating-- ) {
|
||||
$count = $this->get_filtered_product_count( $rating );
|
||||
if ( empty( $count ) ) {
|
||||
continue;
|
||||
}
|
||||
$found = true;
|
||||
$link = $base_link;
|
||||
|
||||
if ( in_array( $rating, $rating_filter, true ) ) {
|
||||
$link_ratings = implode( ',', array_diff( $rating_filter, array( $rating ) ) );
|
||||
} else {
|
||||
$link_ratings = implode( ',', array_merge( $rating_filter, array( $rating ) ) );
|
||||
}
|
||||
|
||||
$class = in_array( $rating, $rating_filter, true ) ? 'wc-layered-nav-rating chosen' : 'wc-layered-nav-rating';
|
||||
$link = apply_filters( 'woocommerce_rating_filter_link', $link_ratings ? add_query_arg( 'rating_filter', $link_ratings, $link ) : remove_query_arg( 'rating_filter' ) );
|
||||
$rating_html = wc_get_star_rating_html( $rating );
|
||||
$count_html = wp_kses(
|
||||
apply_filters( 'woocommerce_rating_filter_count', "({$count})", $count, $rating ),
|
||||
array(
|
||||
'em' => array(),
|
||||
'span' => array(),
|
||||
'strong' => array(),
|
||||
)
|
||||
);
|
||||
|
||||
printf( '<li class="%s"><a href="%s"><span class="star-rating">%s</span> %s</a></li>', esc_attr( $class ), esc_url( $link ), $rating_html, $count_html ); // WPCS: XSS ok.
|
||||
}
|
||||
|
||||
echo '</ul>';
|
||||
|
||||
$this->widget_end( $args );
|
||||
|
||||
if ( ! $found ) {
|
||||
ob_end_clean();
|
||||
} else {
|
||||
echo ob_get_clean(); // WPCS: XSS ok.
|
||||
}
|
||||
}
|
||||
}
|
97
includes/widgets/class-wc-widget-recent-reviews.php
Normal file
97
includes/widgets/class-wc-widget-recent-reviews.php
Normal file
@ -0,0 +1,97 @@
|
||||
<?php
|
||||
/**
|
||||
* Recent Reviews Widget.
|
||||
*
|
||||
* @package WooCommerce\Widgets
|
||||
* @version 2.3.0
|
||||
*/
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Widget recent reviews class.
|
||||
*/
|
||||
class WC_Widget_Recent_Reviews extends WC_Widget {
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->widget_cssclass = 'woocommerce widget_recent_reviews';
|
||||
$this->widget_description = __( 'Display a list of recent reviews from your store.', 'woocommerce' );
|
||||
$this->widget_id = 'woocommerce_recent_reviews';
|
||||
$this->widget_name = __( 'Recent Product Reviews', 'woocommerce' );
|
||||
$this->settings = array(
|
||||
'title' => array(
|
||||
'type' => 'text',
|
||||
'std' => __( 'Recent reviews', 'woocommerce' ),
|
||||
'label' => __( 'Title', 'woocommerce' ),
|
||||
),
|
||||
'number' => array(
|
||||
'type' => 'number',
|
||||
'step' => 1,
|
||||
'min' => 1,
|
||||
'max' => '',
|
||||
'std' => 10,
|
||||
'label' => __( 'Number of reviews to show', 'woocommerce' ),
|
||||
),
|
||||
);
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Output widget.
|
||||
*
|
||||
* @see WP_Widget
|
||||
* @param array $args Arguments.
|
||||
* @param array $instance Widget instance.
|
||||
*/
|
||||
public function widget( $args, $instance ) {
|
||||
global $comments, $comment;
|
||||
|
||||
if ( $this->get_cached_widget( $args ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
ob_start();
|
||||
|
||||
$number = ! empty( $instance['number'] ) ? absint( $instance['number'] ) : $this->settings['number']['std'];
|
||||
$comments = get_comments(
|
||||
array(
|
||||
'number' => $number,
|
||||
'status' => 'approve',
|
||||
'post_status' => 'publish',
|
||||
'post_type' => 'product',
|
||||
'parent' => 0,
|
||||
)
|
||||
); // WPCS: override ok.
|
||||
|
||||
if ( $comments ) {
|
||||
$this->widget_start( $args, $instance );
|
||||
|
||||
echo wp_kses_post( apply_filters( 'woocommerce_before_widget_product_review_list', '<ul class="product_list_widget">' ) );
|
||||
|
||||
foreach ( (array) $comments as $comment ) {
|
||||
wc_get_template(
|
||||
'content-widget-reviews.php',
|
||||
array(
|
||||
'comment' => $comment,
|
||||
'product' => wc_get_product( $comment->comment_post_ID ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
echo wp_kses_post( apply_filters( 'woocommerce_after_widget_product_review_list', '</ul>' ) );
|
||||
|
||||
$this->widget_end( $args );
|
||||
|
||||
}
|
||||
|
||||
$content = ob_get_clean();
|
||||
|
||||
echo $content; // WPCS: XSS ok.
|
||||
|
||||
$this->cache_widget( $args, $content );
|
||||
}
|
||||
}
|
110
includes/widgets/class-wc-widget-recently-viewed.php
Normal file
110
includes/widgets/class-wc-widget-recently-viewed.php
Normal file
@ -0,0 +1,110 @@
|
||||
<?php
|
||||
/**
|
||||
* Recent Products Widget.
|
||||
*
|
||||
* @package WooCommerce\Widgets
|
||||
* @version 3.3.0
|
||||
*/
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Widget recently viewed.
|
||||
*/
|
||||
class WC_Widget_Recently_Viewed extends WC_Widget {
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->widget_cssclass = 'woocommerce widget_recently_viewed_products';
|
||||
$this->widget_description = __( "Display a list of a customer's recently viewed products.", 'woocommerce' );
|
||||
$this->widget_id = 'woocommerce_recently_viewed_products';
|
||||
$this->widget_name = __( 'Recently Viewed Products list', 'woocommerce' );
|
||||
$this->settings = array(
|
||||
'title' => array(
|
||||
'type' => 'text',
|
||||
'std' => __( 'Recently Viewed Products', 'woocommerce' ),
|
||||
'label' => __( 'Title', 'woocommerce' ),
|
||||
),
|
||||
'number' => array(
|
||||
'type' => 'number',
|
||||
'step' => 1,
|
||||
'min' => 1,
|
||||
'max' => 15,
|
||||
'std' => 10,
|
||||
'label' => __( 'Number of products to show', 'woocommerce' ),
|
||||
),
|
||||
);
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Output widget.
|
||||
*
|
||||
* @see WP_Widget
|
||||
* @param array $args Arguments.
|
||||
* @param array $instance Widget instance.
|
||||
*/
|
||||
public function widget( $args, $instance ) {
|
||||
$viewed_products = ! empty( $_COOKIE['woocommerce_recently_viewed'] ) ? (array) explode( '|', wp_unslash( $_COOKIE['woocommerce_recently_viewed'] ) ) : array(); // @codingStandardsIgnoreLine
|
||||
$viewed_products = array_reverse( array_filter( array_map( 'absint', $viewed_products ) ) );
|
||||
|
||||
if ( empty( $viewed_products ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
ob_start();
|
||||
|
||||
$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',
|
||||
);
|
||||
|
||||
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',
|
||||
),
|
||||
); // WPCS: slow query ok.
|
||||
}
|
||||
|
||||
$r = new WP_Query( apply_filters( 'woocommerce_recently_viewed_products_widget_query_args', $query_args ) );
|
||||
|
||||
if ( $r->have_posts() ) {
|
||||
|
||||
$this->widget_start( $args, $instance );
|
||||
|
||||
echo wp_kses_post( apply_filters( 'woocommerce_before_widget_product_list', '<ul class="product_list_widget">' ) );
|
||||
|
||||
$template_args = array(
|
||||
'widget_id' => isset( $args['widget_id'] ) ? $args['widget_id'] : $this->widget_id,
|
||||
);
|
||||
|
||||
while ( $r->have_posts() ) {
|
||||
$r->the_post();
|
||||
wc_get_template( 'content-widget-product.php', $template_args );
|
||||
}
|
||||
|
||||
echo wp_kses_post( apply_filters( 'woocommerce_after_widget_product_list', '</ul>' ) );
|
||||
|
||||
$this->widget_end( $args );
|
||||
}
|
||||
|
||||
wp_reset_postdata();
|
||||
|
||||
$content = ob_get_clean();
|
||||
|
||||
echo $content; // WPCS: XSS ok.
|
||||
}
|
||||
}
|
107
includes/widgets/class-wc-widget-top-rated-products.php
Normal file
107
includes/widgets/class-wc-widget-top-rated-products.php
Normal file
@ -0,0 +1,107 @@
|
||||
<?php
|
||||
/**
|
||||
* Top Rated Products Widget.
|
||||
* Gets and displays top rated products in an unordered list.
|
||||
*
|
||||
* @package WooCommerce\Widgets
|
||||
* @version 3.3.0
|
||||
*/
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Widget top rated products class.
|
||||
*/
|
||||
class WC_Widget_Top_Rated_Products extends WC_Widget {
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->widget_cssclass = 'woocommerce widget_top_rated_products';
|
||||
$this->widget_description = __( "A list of your store's top-rated products.", 'woocommerce' );
|
||||
$this->widget_id = 'woocommerce_top_rated_products';
|
||||
$this->widget_name = __( 'Products by Rating list', 'woocommerce' );
|
||||
$this->settings = array(
|
||||
'title' => array(
|
||||
'type' => 'text',
|
||||
'std' => __( 'Top rated products', 'woocommerce' ),
|
||||
'label' => __( 'Title', 'woocommerce' ),
|
||||
),
|
||||
'number' => array(
|
||||
'type' => 'number',
|
||||
'step' => 1,
|
||||
'min' => 1,
|
||||
'max' => '',
|
||||
'std' => 5,
|
||||
'label' => __( 'Number of products to show', 'woocommerce' ),
|
||||
),
|
||||
);
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Output widget.
|
||||
*
|
||||
* @see WP_Widget
|
||||
* @param array $args Arguments.
|
||||
* @param array $instance Widget instance.
|
||||
*/
|
||||
public function widget( $args, $instance ) {
|
||||
|
||||
if ( $this->get_cached_widget( $args ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
ob_start();
|
||||
|
||||
$number = ! empty( $instance['number'] ) ? absint( $instance['number'] ) : $this->settings['number']['std'];
|
||||
|
||||
$query_args = apply_filters(
|
||||
'woocommerce_top_rated_products_widget_args',
|
||||
array(
|
||||
'posts_per_page' => $number,
|
||||
'no_found_rows' => 1,
|
||||
'post_status' => 'publish',
|
||||
'post_type' => 'product',
|
||||
'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(),
|
||||
)
|
||||
); // WPCS: slow query ok.
|
||||
|
||||
$r = new WP_Query( $query_args );
|
||||
|
||||
if ( $r->have_posts() ) {
|
||||
|
||||
$this->widget_start( $args, $instance );
|
||||
|
||||
echo wp_kses_post( apply_filters( 'woocommerce_before_widget_product_list', '<ul class="product_list_widget">' ) );
|
||||
|
||||
$template_args = array(
|
||||
'widget_id' => isset( $args['widget_id'] ) ? $args['widget_id'] : $this->widget_id,
|
||||
'show_rating' => true,
|
||||
);
|
||||
|
||||
while ( $r->have_posts() ) {
|
||||
$r->the_post();
|
||||
wc_get_template( 'content-widget-product.php', $template_args );
|
||||
}
|
||||
|
||||
echo wp_kses_post( apply_filters( 'woocommerce_after_widget_product_list', '</ul>' ) );
|
||||
|
||||
$this->widget_end( $args );
|
||||
}
|
||||
|
||||
wp_reset_postdata();
|
||||
|
||||
$content = ob_get_clean();
|
||||
|
||||
echo $content; // WPCS: XSS ok.
|
||||
|
||||
$this->cache_widget( $args, $content );
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user