id = 'sku'; $this->short_desc = __( 'SKU', 'woocommerce-jetpack' ); $this->desc = __( 'Generate SKUs automatically. Search by SKU on frontend.', 'woocommerce-jetpack' ); $this->link_slug = 'woocommerce-sku'; parent::__construct(); $this->add_tools( array( 'sku' => array( 'title' => __( 'Autogenerate SKUs', 'woocommerce-jetpack' ), 'desc' => __( 'The tool generates and sets product SKUs for existing products.', 'woocommerce-jetpack' ), ), ) ); if ( $this->is_enabled() ) { // New product if ( 'yes' === get_option( 'wcj_sku_new_products_generate_enabled', 'yes' ) ) { add_action( 'wp_insert_post', array( $this, 'set_sku_for_new_product' ), PHP_INT_MAX, 3 ); add_action( 'woocommerce_duplicate_product', array( $this, 'set_new_product_sku_on_duplicate' ), PHP_INT_MAX, 2 ); } // Allow duplicates if ( 'yes' === get_option( 'wcj_sku_allow_duplicates_enabled', 'no' ) ) { add_filter( 'wc_product_has_unique_sku', '__return_false', PHP_INT_MAX ); } // SKU in emails if ( 'yes' === get_option( 'wcj_sku_add_to_customer_emails', 'no' ) ) { add_filter( 'woocommerce_email_order_items_args', array( $this, 'add_sku_to_customer_emails' ), PHP_INT_MAX, 1 ); } if ( 'yes' === get_option( 'wcj_sku_remove_from_admin_emails', 'no' ) ) { add_filter( 'woocommerce_email_order_items_args', array( $this, 'remove_sku_from_admin_emails' ), PHP_INT_MAX, 1 ); } // Search by SKU if ( 'yes' === get_option( 'wcj_sku_search_enabled', 'no' ) ) { if ( 'pre_get_posts' === get_option( 'wcj_sku_search_hook', 'pre_get_posts' ) ) { add_filter( 'pre_get_posts', array( $this, 'add_search_by_sku_to_frontend' ), PHP_INT_MAX ); } else { // 'posts_search' add_filter( 'posts_search', array( $this, 'add_search_by_sku_to_frontend_posts_search' ), 9 ); } } // Disable SKU if ( 'yes' === get_option( 'wcj_sku_disabled', 'no' ) ) { add_filter( 'wc_product_sku_enabled', '__return_false', PHP_INT_MAX ); } } } /** * add_search_by_sku_to_frontend_posts_search. * * @version 3.4.0 * @since 3.4.0 * @see https://plugins.svn.wordpress.org/search-by-sku-for-woocommerce/ */ function add_search_by_sku_to_frontend_posts_search( $where ) { global $pagenow, $wpdb, $wp; if ( ( is_admin() && 'edit.php' != $pagenow ) || ! is_search() || ! isset( $wp->query_vars['s'] ) || ( isset( $wp->query_vars['post_type'] ) && 'product' != $wp->query_vars['post_type'] ) || ( isset( $wp->query_vars['post_type'] ) && is_array( $wp->query_vars['post_type'] ) && ! in_array( 'product', $wp->query_vars['post_type'] ) ) ) { return $where; } $search_ids = array(); $terms = explode( ',', $wp->query_vars['s'] ); foreach ( $terms as $term ) { if ( is_admin() && is_numeric( $term ) ) { $search_ids[] = $term; } $variations_query = "SELECT p.post_parent as post_id" . " FROM {$wpdb->posts} as p join {$wpdb->postmeta} pm on p.ID = pm.post_id and pm.meta_key='_sku' and pm.meta_value" . " LIKE '%%%s%%' where p.post_parent <> 0 group by p.post_parent"; $regular_products_query = "SELECT post_id FROM {$wpdb->postmeta} WHERE meta_key='_sku' AND meta_value LIKE '%%%s%%';"; $sku_to_parent_id = $wpdb->get_col( $wpdb->prepare( $variations_query, wc_clean( $term ) ) ); $sku_to_id = $wpdb->get_col( $wpdb->prepare( $regular_products_query, wc_clean( $term ) ) ); $search_ids = array_merge( $search_ids, $sku_to_id, $sku_to_parent_id ); } $search_ids = array_filter( array_map( 'absint', $search_ids ) ); if ( sizeof( $search_ids ) > 0 ) { $where = str_replace( ')))', ") OR ({$wpdb->posts}.ID IN (" . implode( ',', $search_ids ) . "))))", $where ); } return $where; } /** * remove_sku_from_admin_emails. * * @version 3.4.0 * @since 3.4.0 */ function remove_sku_from_admin_emails( $args ) { if ( $args['sent_to_admin'] ) { $args['show_sku'] = false; } return $args; } /** * add_sku_to_customer_emails. * * @version 3.4.0 * @since 2.5.5 */ function add_sku_to_customer_emails( $args ) { if ( ! $args['sent_to_admin'] ) { $args['show_sku'] = true; } return $args; } /** * get_all_variations. * * @version 2.9.0 * @since 2.4.8 */ function get_all_variations( $_product ) { $all_variations = array(); foreach ( $_product->get_children() as $child_id ) { if ( $variation = ( WCJ_IS_WC_VERSION_BELOW_3 ? $_product->get_child( $child_id ) : wc_get_product( $child_id ) ) ) { $all_variations[] = $_product->get_available_variation( $variation ); } } return $all_variations; } /** * get_sequential_counter. * * @version 2.9.0 * @since 2.9.0 */ function get_sequential_counter( $product_id ) { if ( 'yes' === get_option( 'wcj_sku_number_generation_sequential_by_cat', 'no' ) ) { $product_terms = get_the_terms( $product_id, 'product_cat' ); if ( is_array( $product_terms ) ) { foreach ( $product_terms as $term ) { $sku_number = $this->sequential_counter_cats[ $term->term_id ]; $this->sequential_counter_cats[ $term->term_id ]++; return $sku_number; } } } // Cats disabled or no category found $sku_number = $this->sequential_counter; $this->sequential_counter++; return $sku_number; } /** * set_sku_with_variable. * * @version 3.6.0 * @todo `as_variable_with_suffix` - handle cases with more than 26 variations */ function set_sku_with_variable( $product_id, $is_preview ) { switch ( apply_filters( 'booster_option', 'product_id', get_option( 'wcj_sku_number_generation', 'product_id' ) ) ) { case 'sequential': $sku_number = $this->get_sequential_counter( $product_id ); break; case 'hash_crc32': $sku_number = sprintf( "%u", crc32( $product_id ) ); break; default: // 'product_id' $sku_number = $product_id; break; } $product = wc_get_product( $product_id ); $this->set_sku( $product_id, $sku_number, '', $is_preview, $product_id, $product ); // Handling variable products $variation_handling = apply_filters( 'booster_option', 'as_variable', get_option( 'wcj_sku_variations_handling', 'as_variable' ) ); if ( $product->is_type( 'variable' ) ) { $variations = $this->get_all_variations( $product ); if ( 'as_variable' === $variation_handling ) { foreach ( $variations as $variation ) { $this->set_sku( $variation['variation_id'], $sku_number, '', $is_preview, $product_id, wc_get_product( $variation['variation_id'] ) ); } } elseif ( 'as_variation' === $variation_handling ) { foreach ( $variations as $variation ) { if ( 'sequential' === apply_filters( 'booster_option', 'product_id', get_option( 'wcj_sku_number_generation', 'product_id' ) ) ) { $sku_number = $this->get_sequential_counter( $product_id ); } elseif ( 'hash_crc32' === apply_filters( 'booster_option', 'product_id', get_option( 'wcj_sku_number_generation', 'product_id' ) ) ) { $sku_number = sprintf( "%u", crc32( $variation['variation_id'] ) ); } else { // if 'product_id' $sku_number = $variation['variation_id']; } $this->set_sku( $variation['variation_id'], $sku_number, '', $is_preview, $product_id, wc_get_product( $variation['variation_id'] ) ); } } else if ( 'as_variable_with_suffix' === $variation_handling ) { $variation_suffixes = 'abcdefghijklmnopqrstuvwxyz'; $abc = 0; foreach ( $variations as $variation ) { $this->set_sku( $variation['variation_id'], $sku_number, $variation_suffixes[ $abc++ ], $is_preview, $product_id, wc_get_product( $variation['variation_id'] ) ); if ( 26 == $abc ) { $abc = 0; } } } } } /** * get_acronym. * * @version 3.6.0 * @since 3.6.0 * @todo move to `wcj_get_acronym()` */ function get_acronym( $str, $sep ) { $acronym = ''; $words = explode( $sep, $str ); foreach ( $words as $word ) { if ( ! empty( $word ) ) { $acronym .= $word[0]; } } return $acronym; } /** * maybe_process_attributes. * * @version 3.6.0 * @since 3.6.0 */ function maybe_process_attributes( $_product, $format_template, $str, $is_variation = false ) { while ( false !== ( $pos = strpos( $format_template, '{' . $str . '=' ) ) ) { if ( false !== ( $pos_end = strpos( $format_template, '}', $pos ) ) ) { if ( ! isset( $atts ) ) { if ( $is_variation ) { $atts = ( 'WC_Product_Variation' === get_class( $_product ) ? $_product->get_variation_attributes() : array() ); } else { $atts = $_product->get_attributes(); } } $att_str = substr( $format_template, $pos, ( $pos_end - $pos + 1 ) ); $att = explode( '=', str_replace( array( '{', '}' ), '', $att_str ) ); $att_res = array(); if ( isset( $att[1] ) ) { $att_name = $att[1]; $limit = 0; if ( false !== ( $pos_slash = strpos( $att_name, '/' ) ) ) { $att_name = explode( '/', $att_name ); $limit = $att_name[1]; $att_name = $att_name[0]; } if ( $is_variation ) { $att_name = 'attribute_' . $att_name; } if ( isset( $atts[ $att_name ] ) ) { if ( $is_variation ) { $slug = $atts[ $att_name ]; if ( 0 != $limit ) { $slug = substr( $slug, 0, $limit ); } $att_res[] = $slug; // array is not necessary here (always one slug) } else { $att_object = $atts[ $att_name ]; if ( is_object( $att_object ) && 'WC_Product_Attribute' === get_class( $att_object ) ) { foreach ( $att_object->get_slugs() as $slug ) { if ( 0 != $limit ) { $slug = substr( $slug, 0, $limit ); } $att_res[] = $slug; } } } } } $format_template = str_replace( $att_str, implode( get_option( 'wcj_sku_variations_product_slug_sep', '-' ), $att_res ), $format_template ); } } return $format_template; } /** * set_sku. * * @version 3.7.0 * @todo deprecate `{prefix}` and `{suffix}` * @todo `{tag_prefix}`, `{tag_suffix}` * @todo (maybe) remove some "replaced values" that can be replaced by Booster products shortcodes, e.g.: `[wcj_product_slug]` (and update description in settings) * @todo (maybe) add option to disable shortcodes processing */ function set_sku( $product_id, $sku_number, $variation_suffix, $is_preview, $parent_product_id, $_product ) { $format_template = get_option( 'wcj_sku_template', '{category_prefix}{prefix}{sku_number}{suffix}{category_suffix}{variation_suffix}' ); global $post; $post = get_post( $product_id ); setup_postdata( $post ); $format_template = do_shortcode( $format_template ); wp_reset_postdata(); $parent_product = wc_get_product( $parent_product_id ); $old_sku = $_product->get_sku(); $do_generate_new_sku = ( 'no' === get_option( 'wcj_sku_generate_only_for_empty_sku', 'no' ) || '' === $old_sku ); // {category_prefix} & {category_suffix} $category_prefix = array(); $category_suffix = array(); $product_cat = array(); $product_terms = get_the_terms( $parent_product_id, 'product_cat' ); if ( is_array( $product_terms ) ) { foreach ( $product_terms as $term ) { $product_cat[] = esc_html( $term->name ); $category_prefix[] = get_option( 'wcj_sku_prefix_cat_' . $term->term_id, '' ); $category_suffix[] = get_option( 'wcj_sku_suffix_cat_' . $term->term_id, '' ); } } $category_prefix = array_filter( $category_prefix ); $category_suffix = array_filter( $category_suffix ); if ( 'first' === get_option( 'wcj_sku_categories_multiple', 'first' ) ) { $category_prefix = reset( $category_prefix ); $category_suffix = reset( $category_suffix ); } else { $category_prefix = implode( get_option( 'wcj_sku_categories_multiple_glue', '' ), $category_prefix ); $category_suffix = implode( get_option( 'wcj_sku_categories_multiple_glue', '' ), $category_suffix ); } $product_cat = implode( ', ', $product_cat ); // {variation_attributes} $variation_attributes = ''; if ( false !== strpos( $format_template, '{variation_attributes}' ) && 'WC_Product_Variation' === get_class( $_product ) ) { $variation_attributes = implode( get_option( 'wcj_sku_variations_product_slug_sep', '-' ), $_product->get_variation_attributes() ); } // {variation_attribute=X} $format_template = $this->maybe_process_attributes( $_product, $format_template, 'variation_attribute', true ); // {attribute=X} $format_template = $this->maybe_process_attributes( $_product, $format_template, 'attribute' ); // {parent_attribute=X} $format_template = $this->maybe_process_attributes( $parent_product, $format_template, 'parent_attribute' ); // {product_slug_acronym} $product_slug_acronym = ''; if ( false !== strpos( $format_template, '{product_slug_acronym}' ) ) { $product_slug_acronym = $this->get_acronym( $_product->get_slug(), '-' ); } // {parent_product_slug_acronym} $parent_product_slug_acronym = ''; if ( false !== strpos( $format_template, '{parent_product_slug_acronym}' ) ) { $parent_product_slug_acronym = $this->get_acronym( $parent_product->get_slug(), '-' ); } $replace_values = array( '{parent_sku}' => $parent_product->get_sku(), '{product_slug}' => $_product->get_slug(), '{product_slug_acronym}' => $product_slug_acronym, '{parent_product_slug}' => $parent_product->get_slug(), '{parent_product_slug_acronym}' => $parent_product_slug_acronym, '{variation_attributes}' => $variation_attributes, '{category_prefix}' => apply_filters( 'booster_option', '', $category_prefix ), '{prefix}' => get_option( 'wcj_sku_prefix', '' ), '{sku_number}' => sprintf( '%0' . get_option( 'wcj_sku_minimum_number_length', 0 ) . 's', $sku_number ), '{suffix}' => get_option( 'wcj_sku_suffix', '' ), '{category_suffix}' => $category_suffix, '{variation_suffix}' => $variation_suffix, ); if ( $do_generate_new_sku ) { $the_sku = str_replace( array_keys( $replace_values ), $replace_values, $format_template ); if ( 'original' != ( $characters_case = get_option( 'wcj_sku_characters_case', 'original' ) ) ) { $the_sku = ( 'lower' == $characters_case ? strtolower( $the_sku ) : strtoupper( $the_sku ) ); } } else { $the_sku = $old_sku; } if ( $is_preview ) { $this->preview_buffer .= '
| ' . ' | ' . __( 'ID', 'woocommerce-jetpack' ) . ' | ' . '' . __( 'Product', 'woocommerce-jetpack' ) . ' | ' . '' . __( 'Categories', 'woocommerce-jetpack' ) . ' | ' . '' . __( 'SKU', 'woocommerce-jetpack' ) . ' | ' . '' . __( 'Old SKU', 'woocommerce-jetpack' ) . ' | ' . '
|---|
' . __( 'SKUs generated and set successfully!', 'woocommerce-jetpack' ) . '