version ); wp_style_add_data( 'flatsome-swatches-frontend', 'rtl', 'replace' ); wp_enqueue_script( 'flatsome-swatches-frontend', get_template_directory_uri() . '/assets/js/extensions/flatsome-swatches-frontend.js', array( 'jquery', 'flatsome-js', ), flatsome_swatches()->version, true ); } /** * Add extension CSS. */ public function add_css() { ob_start(); ?> .variations th, .variations td { display: block; } .variations .label { display: flex; align-items: center; } .variations .label label { margin: .5em 0; } .ux-swatch-selected-value { font-weight: normal; font-size: .9em; } .variations_form .ux-swatch.selected { box-shadow: 0 0 0 0.1rem ; } .ux-swatches-in-loop .ux-swatch.selected { box-shadow: 0 0 0 0.1rem ; } '; $css .= $output; $css .= ''; echo flatsome_minify_css( $css ); // phpcs:ignore WordPress.Security.EscapeOutput } /** * The swatches HTML for an attribute. * * @param string $html The dropdown variation attribute options html. * @param array $args Args. * * @return string * @uses swatch_html() */ public function get_swatch_html( $html, $args ) { $swatch_types = flatsome_swatches()->get_attribute_types(); $attr = flatsome_swatches()->get_attribute( $args['attribute'] ); // Abort if this is normal attribute. if ( empty( $attr ) || ! array_key_exists( $attr->attribute_type, $swatch_types ) ) { return $html; } $swatches = ''; $options = $args['options']; $product = $args['product']; $attribute = $args['attribute']; $classes = array( 'ux-swatches', "ux-swatches-attribute-{$attr->attribute_type}" ); $selector_classes = array( 'variation-selector', "variation-select-{$attr->attribute_type}" ); $args['tooltip'] = get_theme_mod( 'swatches_tooltip', 1 ); $attr_options = flatsome_swatches()->get_attribute_option_by_name( $args['attribute'] ); $available_variations = $product->get_available_variations(); $args['swatches'] = $this->get_swatches( $attribute, $options, $available_variations, $this->use_variation_images( $attr_options ) ); $args['swatches']['use_variation_image'] = $this->use_variation_images( $attr_options ); if ( isset( $attr_options['swatch_size'] ) && ! empty( $attr_options['swatch_size'] ) ) { $classes[] = 'ux-swatches--' . $attr_options['swatch_size']; } if ( isset( $attr_options['swatch_shape'] ) && ! empty( $attr_options['swatch_shape'] ) ) { $classes[] = 'ux-swatches--' . $attr_options['swatch_shape']; } if ( empty( $options ) && ! empty( $product ) && ! empty( $attribute ) ) { $attributes = $product->get_variation_attributes(); $options = $attributes[ $attribute ]; } if ( array_key_exists( $attr->attribute_type, $swatch_types ) ) { if ( ! empty( $options ) && $product && taxonomy_exists( $attribute ) ) { $terms = wc_get_product_terms( $product->get_id(), $attribute, array( 'fields' => 'all' ) ); foreach ( $terms as $term ) { if ( ! in_array( $term->slug, $options, true ) ) { continue; } $swatches .= apply_filters( 'flatsome_swatch_html', '', $term, $attr->attribute_type, $args ); } } if ( ! empty( $swatches ) ) { $selector_classes[] = 'hidden'; $swatches = '
' . $swatches . '
'; $html = '
' . $html . '
' . $swatches; } } return $html; } /** * Single swatch HTML. * * @param string $html HTML. * @param \WP_Term $term WP Term object. * @param string $type Attribute type. * @param array $args Args. * * @return string */ public function swatch_html( $html, $term, $type, $args ) { $selected = sanitize_title( $args['selected'] ) == $term->slug ? 'selected' : ''; $name = esc_html( apply_filters( 'woocommerce_variation_option_name', $term->name ) ); $img_size = apply_filters( 'flatsome_swatch_image_size', 'woocommerce_gallery_thumbnail', $term ); $classes = array( 'ux-swatch' ); $thumb = ''; $tooltip = ''; if ( ! empty( $args['tooltip'] ) ) { $classes[] = 'tooltip'; $tooltip = $term->description ? $term->description : $name; } // Gather variation image if one is available. if ( $args['swatches']['use_variation_image'] ) { $options_flipped = array_flip( $args['options'] ); $key = $options_flipped[ $term->slug ]; if ( isset( $args['swatches'][ $key ]['variation_id'] ) && $args['swatches'][ $key ]['variation_id'] ) { $thumb_id = get_post_thumbnail_id( $args['swatches'][ $key ]['variation_id'] ); if ( $thumb_id ) { $thumb = wp_get_attachment_image( $thumb_id, $img_size, false, array( 'class' => "ux-swatch__img attachment-$img_size size-$img_size", 'alt' => $name, ) ); $type = 'variation-image'; } } } switch ( $type ) { case 'ux_color': $color_classes = array( 'ux-swatch__color' ); $value = get_term_meta( $term->term_id, 'ux_color', true ); $color = flatsome_swatches()->parse_ux_color_term_meta( $value ); if ( $color['class'] ) $color_classes[] = $color['class']; $html = sprintf( '
%s
', implode( ' ', $classes ), esc_attr( $term->slug ), $selected, esc_attr( $term->slug ), $name, esc_attr( $tooltip ), implode( ' ', $color_classes ), $color['style'], $name ); break; case 'ux_image': $image_id = get_term_meta( $term->term_id, 'ux_image', true ); $image = ''; if ( $image_id ) { $image = wp_get_attachment_image( $image_id, $img_size, false, array( 'class' => "ux-swatch__img attachment-$img_size size-$img_size", 'alt' => $name, ) ); } $html = sprintf( '
%s%s
', implode( ' ', $classes ), $selected, esc_attr( $term->slug ), $name, esc_attr( $tooltip ), $image ? $image : wc_placeholder_img( $img_size ), $name ); break; case 'variation-image': $html = sprintf( '
%s%s
', implode( ' ', $classes ), $selected, esc_attr( $term->slug ), $name, esc_attr( $tooltip ), $thumb ? $thumb : wc_placeholder_img( $img_size ), $name ); break; case 'ux_label': $label = get_term_meta( $term->term_id, 'ux_label', true ); $label = $label ? $label : $name; $html = sprintf( '
%s
', implode( ' ', $classes ), $selected, esc_attr( $term->slug ), $name, esc_attr( $tooltip ), esc_html( $label ) ); break; } return $html; } /** * Get an array of types and values for each attribute. * * @param array $attributes Attributes. * * @return array */ public function get_variation_attributes_types( $attributes ) { global $wc_product_attributes; $types = array(); $defined_attr = flatsome_swatches()->get_attribute_types(); if ( ! empty( $attributes ) ) { foreach ( $attributes as $name => $options ) { $current = isset( $wc_product_attributes[ $name ] ) ? $wc_product_attributes[ $name ] : false; if ( $current && array_key_exists( $current->attribute_type, $defined_attr ) ) { $types[ $name ] = $current->attribute_type; } } } return $types; } /** * Create a list of swatches on product boxes. * * @return string */ public function box_swatch_list() { global $product; $attribute = apply_filters( 'flatsome_swatches_box_attribute', $this->get_swatches_box_attribute(), $product ); if ( ! $attribute ) { return; } $attribute_name = $attribute->slug; if ( ! $attribute_name || empty( $attribute_name ) ) { return; } $id = $product->get_id(); if ( empty( $id ) || ! $product->is_type( 'variable' ) ) { return; } $attr_options = flatsome_swatches()->get_attribute_option_by_name( $attribute_name ); $cache_enabled = apply_filters( 'flatsome_swatches_cache_enabled', true ); $transient = 'flatsome_swatches_cache_' . $id; $classes = array( 'ux-swatches', 'ux-swatches-in-loop' ); if ( $cache_enabled ) { $available_variations = get_transient( $transient ); } else { $available_variations = array(); } if ( ! $available_variations ) { /** @var $product \WC_Product_Variable */ // phpcs:ignore Generic.Commenting.DocComment.MissingShort $available_variations = $product->get_available_variations(); if ( $cache_enabled ) { set_transient( $transient, $available_variations, apply_filters( 'flatsome_swatches_cache_time', WEEK_IN_SECONDS ) ); } } if ( empty( $available_variations ) ) { return; } $swatches_to_show = $this->get_option_variations( $attribute_name, $available_variations ); if ( empty( $swatches_to_show ) ) { return; } $html = ''; if ( get_theme_mod( 'swatches_box_shape' ) ) { $classes[] = 'ux-swatches--' . get_theme_mod( 'swatches_box_shape' ); } if ( get_theme_mod( 'swatches_box_size' ) ) $classes[] = 'ux-swatches--' . get_theme_mod( 'swatches_box_size' ); // Start ux-swatches. $html .= '
'; // Order. $terms = wc_get_product_terms( $product->get_id(), $attribute_name, array( 'fields' => 'slugs' ) ); $swatches_to_show_tmp = $swatches_to_show; $swatches_to_show = array(); foreach ( $terms as $id => $slug ) { if ( ! isset( $swatches_to_show_tmp[ $slug ] ) ) { continue; } $swatches_to_show[ $slug ] = $swatches_to_show_tmp[ $slug ]; } $index = 0; $swatch_count = count( $swatches_to_show ); $swatch_limit = (int) get_theme_mod( 'swatches_box_limit', 5 ); $swatch_layout = get_theme_mod( 'swatches_box_layout' ); foreach ( $swatches_to_show as $key => $swatch ) { $swatch_classes = array( 'ux-swatch' ); $color_classes = array( 'ux-swatch__color' ); $term = get_term_by( 'slug', $key, $attribute_name ); $name = esc_html( apply_filters( 'woocommerce_variation_option_name', $term->name ) ); $img_size = apply_filters( 'flatsome_swatch_image_size', 'woocommerce_gallery_thumbnail', $term ); $data = array(); $type_tmp = $attribute->type; $swatch_inner_html = ''; if ( $this->use_variation_images( $attr_options ) && isset( $swatch['image_src'] ) ) { $thumb_id = get_post_thumbnail_id( $swatch['variation_id'] ); if ( $thumb_id ) { $type_tmp = 'variation-image'; $swatch_classes[] = 'ux-swatch--image'; $swatch_inner_html = wp_get_attachment_image( $thumb_id, $img_size, false, array( 'class' => "ux-swatch__img attachment-$img_size size-$img_size", 'alt' => $name, ) ); } } switch ( $type_tmp ) { case 'ux_color': $color = flatsome_swatches()->parse_ux_color_term_meta( $swatch['ux_color'] ); if ( $color['class'] ) $color_classes[] = $color['class']; $swatch_classes[] = 'ux-swatch--color'; $swatch_inner_html = ''; break; case 'ux_image': $swatch_classes[] = 'ux-swatch--image'; $swatch_inner_html = wp_get_attachment_image( $swatch['ux_image'], $img_size, false, array( 'class' => "ux-swatch__img attachment-$img_size size-$img_size", 'alt' => $name, ) ); break; case 'ux_label': $swatch_classes[] = 'ux-swatch--label'; break; } if ( isset( $swatch['image_src'] ) ) { $data['data-image-src'] = $swatch['image_src']; $data['data-image-srcset'] = $swatch['image_srcset']; $data['data-image-sizes'] = $swatch['image_sizes']; if ( ! $swatch['is_in_stock'] ) { $swatch_classes[] = 'out-of-stock'; } } $data['data-attribute_name'] = 'attribute_' . $attribute_name; $data['data-value'] = $term->slug; if ( $swatch_layout === 'limit' && $swatch_count > $swatch_limit ) { if ( $index >= $swatch_limit ) { $swatch_classes[] = 'hidden'; } if ( $index === $swatch_limit ) { $html .= '+' . ( $swatch_count - $swatch_limit ) . ''; } } $html .= '
' . $swatch_inner_html . '' . $name . '
'; $index ++; } $html .= '
'; echo $html; // phpcs:ignore WordPress.Security.EscapeOutput } /** * Get the attribute to show in loops by user preference. * * @return \stdClass|null The attribute object. */ private function get_swatches_box_attribute() { if ( ! get_theme_mod( 'swatches_box_attribute' ) ) { return null; } $attr = wc_get_attribute( get_theme_mod( 'swatches_box_attribute' ) ); if ( $attr ) { return $attr; } return null; } /** * Get custom variation option data. * * @param string $attribute_name Attribute name. * @param array $available_variations The available variation. * @param mixed $option Whether or not to get only one variation by attribute option value. * * @return array|null */ private function get_option_variations( $attribute_name, $available_variations, $option = false ) { $swatches_to_show = array(); foreach ( $available_variations as $key => $variation ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable $option_variation = array(); $attr_key = 'attribute_' . $attribute_name; if ( ! isset( $variation['attributes'][ $attr_key ] ) ) { return null; } $val = $variation['attributes'][ $attr_key ]; if ( ! empty( $variation['image']['src'] ) ) { $option_variation = array( 'variation_id' => $variation['variation_id'], 'is_in_stock' => $variation['is_in_stock'], 'image_src' => $variation['image']['thumb_src'], 'image_srcset' => wp_get_attachment_image_srcset( $variation['image_id'], 'woocommerce_thumbnail' ), 'image_sizes' => wp_get_attachment_image_sizes( $variation['image_id'], 'woocommerce_thumbnail' ), ); } // Get only one variation by attribute option value. if ( $option ) { if ( $val != $option ) { continue; } else { return $option_variation; } } else { // Or get all variations with swatches to show by attribute name. $swatch = $this->get_swatch( $attribute_name, $val ); // If key already exist don't replace existing with sequential match. if ( ! array_key_exists( $val, $swatches_to_show ) ) { $swatches_to_show[ $val ] = array_merge( $swatch, $option_variation ); } } } return $swatches_to_show; } /** * Get single swatch values. * * @param string $attr_name Attribute name. * @param string|int $value Search for this term value. * * @return array */ private function get_swatch( $attr_name, $value ) { $swatches = array(); $color = ''; $image = ''; $label = ''; $term = get_term_by( 'slug', $value, $attr_name ); if ( is_object( $term ) ) { $color = get_term_meta( $term->term_id, 'ux_color', true ); $image = get_term_meta( $term->term_id, 'ux_image', true ); $label = get_term_meta( $term->term_id, 'ux_label', true ); } if ( $color != '' ) { $swatches['ux_color'] = $color; } if ( $image != '' ) { $swatches['ux_image'] = $image; } if ( $label != '' ) { $swatches['ux_label'] = $label; } return $swatches; } /** * Get swatches. * * @param string $attr_name Attribute name. * @param array $options Attribute options. * @param array $available_variations Available variations. * @param bool $use_variation_images Whether or not to search and collect the variation image. Default false. * * @return array */ private function get_swatches( $attr_name, $options, $available_variations, $use_variation_images = false ) { $swatches = array(); foreach ( $options as $key => $value ) { $swatch = $this->get_swatch( $attr_name, $value ); if ( ! empty( $swatch ) ) { if ( $available_variations && $use_variation_images ) { $variation = $this->get_option_variations( $attr_name, $available_variations, $value ); if ( $variation ) { $swatch = array_merge( $swatch, $variation ); } } $swatches[ $key ] = $swatch; } if ( empty( $swatch ) && $available_variations && $use_variation_images ) { $variation = $this->get_option_variations( $attr_name, $available_variations, $value ); if ( $variation ) { $swatch = array_merge( $swatch, $variation ); $swatches[ $key ] = $swatch; } } } return $swatches; } /** * Check if given attribute options wants to display variation images. * * @param array $options The attribute options array. * * @return bool Whether or not to us variation images. */ private function use_variation_images( $options ) { if ( ! $options ) { return false; } if ( isset( $options['swatch_variation_images'] ) && $options['swatch_variation_images'] ) { return true; } return false; } /** * Render swatch value in layered nav. * * @param string $term_html Term HTML. * @param object $term Term. * @param string $link Link. * @param string|int $count Count. * * @return string */ public function layered_nav_term_html( $term_html, $term, $link, $count ) { $swatch_types = flatsome_swatches()->get_attribute_types(); $attr = flatsome_swatches()->get_attribute( $term->taxonomy ); // Abort if this is normal attribute. if ( empty( $attr ) || ! array_key_exists( $attr->attribute_type, $swatch_types ) ) { return $term_html; } $classes = array( 'ux-swatch-widget-layered-nav-list__graphic' ); $img_size = apply_filters( 'flatsome_swatch_image_size', 'woocommerce_gallery_thumbnail', $term ); if ( get_theme_mod( 'swatches_box_shape' ) ) { $classes[] = 'ux-swatches--' . get_theme_mod( 'swatches_box_shape' ); } switch ( $attr->attribute_type ) { case 'ux_image': $image_id = get_term_meta( $term->term_id, 'ux_image', true ); $image = ''; $classes[] = 'ux-swatch--image'; if ( $image_id ) { $image = wp_get_attachment_image( $image_id, $img_size, false, array( 'class' => "ux-swatch__img attachment-$img_size size-$img_size", 'alt' => $term->name, ) ); } $swatch = sprintf( '
%s
', $image ? $image : wc_placeholder_img( 'woocommerce_gallery_thumbnail' ) ); break; case 'ux_color': $color_classes = array( 'ux-swatch__color' ); $value = get_term_meta( $term->term_id, 'ux_color', true ); $color = flatsome_swatches()->parse_ux_color_term_meta( $value ); $classes[] = 'ux-swatch--color'; if ( $color['class'] ) $color_classes[] = $color['class']; $swatch = sprintf( '
', implode( ' ', $color_classes ), $color['style'] ); break; default: return $term_html; } return $swatch . $term_html; } /** * Clear cache on save post by ID. * * @param int $post_id Post ID. */ public function cache_clear_save_post( $post_id ) { if ( ! apply_filters( 'flatsome_swatches_cache_enabled', true ) ) { return; } $transient = 'flatsome_swatches_cache_' . $post_id; delete_transient( $transient ); } /** * Clear cache on product object save by ID. * * @param \WC_Product $product Product object. */ public function cache_clear_product_object_save( $product ) { if ( ! apply_filters( 'flatsome_swatches_cache_enabled', true ) ) { return; } $post_id = $product->get_id(); $transient = 'flatsome_swatches_cache_' . $post_id; delete_transient( $transient ); } /** * Clear all cache. * * @param string $new_value The new value of the theme modification. * @param string $old_value The current value of the theme modification. * * @return mixed */ public function cache_clear_all( $new_value, $old_value ) { if ( $new_value !== $old_value ) { flatsome_swatches()->cache_clear(); } return $new_value; } }