5

At the moment we have a lot of product attribute terms, one attribute probably has around 20,000 terms inside it.

When editing a product and clicking into the field for the attribute we get a freeze for 10 seconds before the list of suggested terms drops down.

enter image description here

I have installed and setup Redis on the server and on WP however it doesn't look to have made any noticeable difference in this particular respect.

Is there something I can do to make this quicker? Or turn off the suggestions so we can just type the attribute value we need and save without a hang?

Thanks!

7
  • @RiddleMeThis yeah, I've searched far and wide! I Can only seem to find topics on products having too many variations! :( Mar 6, 2020 at 11:05
  • What version are you using?
    – questioner
    Mar 7, 2020 at 13:39
  • @grai WooCommerce 3.9.3 - Latest WP Mar 9, 2020 at 8:59
  • When editing a product, do you need to select several of the existing attributes, or just one? If selecting several, how many (approx)?
    – questioner
    Mar 9, 2020 at 12:43
  • @grai we may select 10 different attributes, one term for each attribute. But when I click into the box as in the image, it suggests ones. The issue is there are 20,000 terms so its very slow to load. Mar 9, 2020 at 16:32

1 Answer 1

3
+50

Having a look around in the woocommerce code, there is no ajax request made for this select, so there is no use in caching. The slowliness comes from javascript/select2 having so many options to display.

Woocommerce, however, left enough actions, filters and hooks so that the behavior of this select2 can be changed

I made a small plugin that will fix your issue by doing an ajax search limited to a 100 terms rather than displaying all of the terms in the select2

functions.php

<?php
/**
 * Plugin name: WC Fix Attributes
 * Version: 1.0
 * Author: Tofandel
 * Description: Fixes the slowliness of a select2 in woocommerce admin when having huge numbers of product variation terms
 */

/**
 * Filter to prevent displaying all of the attribute terms and only display the ones selected in the product
 */
add_filter( 'woocommerce_product_attribute_terms', function ( $args ) {
    global $post;

    if ( $post ) {
        $product = new WC_Product($post);

        $includes = [];
        $size = 0;

        foreach ($product->get_attributes() as $attribute) {
            /**
             * @var WC_Product_Attribute $attribute
             */
            $opts = $attribute->get_options();
            $includes = array_merge($includes, $opts);
            $size = max($size, sizeof($includes));

        }
        $args['include'] = $includes;

        $args['number'] = $size; //Will output only the selected terms
    }
    return $args;
} );

/**
 * Hack so we can get the term taxonomy (because WC forgot to print it somewhere)
 */
add_action( 'woocommerce_product_option_terms', function ( $attribute_taxonomy, $i, $attribute ) {
    echo '<span class="attribute_taxonomy_getter" data-taxonomy="' . esc_attr( $attribute->get_taxonomy() ) . '"></span>';
}, 10, 3 );

/**
 * Enqueue script
 */
add_action( 'admin_enqueue_scripts', function () {
    wp_enqueue_script( 'wc-fix-attributes', plugins_url( 'script.js', __FILE__ ) );

    wp_localize_script( 'wc-fix-attributes', 'WCFixAttributes', [
        'ajaxurl' => admin_url( 'admin-ajax.php' ),
        'nonce' => wp_create_nonce( 'wc_fix_search_terms' ),
    ] );
} );

/**
 * Ajax search
 */
add_action( 'wp_ajax_wc_fix_search_terms', function () {
    // Permissions check.
    check_ajax_referer( 'wc_fix_search_terms' );

    if ( ! current_user_can( 'manage_product_terms' ) ) {
        wp_send_json_error( __( 'You do not have permission to read product attribute terms', 'woocommerce' ) );
    }


    if ( ! empty( $_REQUEST['taxonomy'] ) ) {
        $terms = get_terms( [ 'taxonomy' => $_REQUEST['taxonomy'], 'number' => 100, 'name__like' => $_REQUEST['term'] ] );

        $terms = array_map( function ( $term ) {
            return [ 'text' => $term->name, 'slug' => $term->slug, 'id' => $term->term_id ];
        }, $terms );

        wp_send_json( [ 'results' => $terms, 'success' => true ] );
    } else {
        wp_send_json_error();
    }
} );

script.js

jQuery(function ($) {
    // The woocommerce select2 is initializing
    $(document.body).on('wc-enhanced-select-init', function () {
        //We need to wait a bit for it to be fully inited
        setTimeout(function() {
            $('select.attribute_values').each(function () {
                var $that = $(this);
                $that.select2({ //Add an ajax option to it, to search the terms dynamically
                    ajax: {
                        url: WCFixAttributes.ajaxurl,
                        dataType: 'json',
                        type: "GET",
                        quietMillis: 400, //Typing delay before sending the request
                        data: function (term) {
                            return {
                                action: 'wc_fix_search_terms',
                                _wpnonce: WCFixAttributes.nonce,
                                // Get the taxonomy printed from our action
                                taxonomy: $that.parent().children('.attribute_taxonomy_getter').data('taxonomy'),
                                term: term.term
                            };
                        },
                    }
                });
            });
        }, 100);
    })
});

Just create a directory in your plugins directory (name it however you like) and add those two files or download the zip and upload it in wordpress as you would any plugin

1
  • 1
    That was exactly the solution I was looking for. Thanks so much it worked flawlessly! Mar 12, 2020 at 16:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.