WooCommerce – really slow wc_get_product_class

In my investigation and work to make WooCommerce perform a little bit better i found this little surprise! The little helper wc_get_product_class to print correct class names in the wrapper element in html for me took over 100ms per product. With over 100 products it’s really bad! I have quite complex products with many variations. But REALLY slowing down.

So this little code is now removed from my code.

wc_get_product_class('my-product', $product)

Yes, for me this was a good solution. I just added “product” as class instead. And saved 100ms per product! Good enough for my purpose, but it might not be sufficient for everyone.

If you don’t overwrite the product with a template, here is one way that might help you override this:

add_filter( 'woocommerce_attribute_taxonomies', 'remove_slowdowns_caused_by_taxonomies', 10, 1); function remove_slowdowns_caused_by_taxonomies($attribute_taxonomies){ return array('product'); }

Or read more here for more solutions:

https://github.com/woocommerce/woocommerce/issues/20262

WooCommerce – find default variation performance

My shop page was very slow when I had over 100 products, REALLY slow. So I had to investigate what happened. So here are some points.

Find default variation

One thing I did for every product was to find the default variation to show correct image, and the code I used was this. My products have 15 variations, and this was really bad for performance.

$default_attributes = $product->get_default_attributes();
$available_variations = $product->get_available_variations();

foreach($available_variations as $variation_values ) {
  $found_variations = 0;
  foreach($default_attributes as $key => $default_attribute_value ) {
                
    if ($variation_values['attributes']['attribute_'.$key] == $default_attribute_value) {
      $found_variations++;
    }
  }
  // return variation_id if found all of the default variations 
  if (count($default_attributes) == $found_variations) {
    return $variation_values['variation_id'];
  }
}

Instead i found the neat little function find_matching_product_variation, so instead of the nested foreach loops, I use the Data_Store_CPT to do the same.

$default_attributes = $product->get_default_attributes();
$attributes = [];
foreach ($default_attributes as $key => $value) {
  $attributes['attribute_'.$key] = $value;
}
return (new \WC_Product_Data_Store_CPT())->find_matching_product_variation(
        new \WC_Product($product->get_id()),
        $attributes
);

The same procedure that on my machine in the first foreach loops took 70-90 ms now take around 2 ms instead!

WooCommerce zero trimming decimal

I found this little neat thing when messing around with decimals in WooCommerce.

// Trim only when decimal is zero in price
add_filter( 'woocommerce_price_trim_zeros', '__return_true' );

Nice of them to provide this little filter! But even better if it was a setting in wp-admin, but until that is added, this is a quite simple solution. Just put the above code in your functions.php.

If you can’t access your functions.php or don’t know howto do it, there is of course a plugin for that. It’s made by Therichpost, and it only does exactly the above small filter snippet above. So really simple and not bloated with other crap 😉

CSV and HTML search filter for WordPress

This is one of my WordPress plugins, made to add a simple ajax-search in html or in uploaded CSV-file.

The plugin has two shortcodes.

[csvsearch src='/path/file.csv']
[filtersearch search_element='table']

[csvsearch]

[csvsearch] is performing a search in an uploaded (or otherwise accessible) CSV-file. Use the format to set the output. use {0}, {1} etc for different columns in the file and {b}{/b}, {i}{/i} etc for simple formatting. Here is a sample with all arguments to use.

[csvsearch 

// url to uploaded file
src='URL' 

// charset of file
charset='iso-8859-1' 

// format for the output
format='{b}{0}{/b}, {1}, {2}{br/}' 

// search label
searchtext='search' 

// format for output when instant search
instantformat='{0}' 

// instant search enabled or not
instantsearch='false' 

// data ID format, i.e. what to put in data-id of the listed element.
dataidformat="{0}" 

// change the item separator depending on type of csv file used
csv_separator=';'

// change the nothing found message
nothing_found_message='Nothing found when searching for: '

// I true, the shortcode will only find exact matches, case sensitive. Default false.
exact_match='false'
]

[filtersearch]

[filtersearch] does a filter inside current html page. Specify which element you want to search within. You cah use either element type, .class_name of #id. See sample below for more arguments that can be used.

[filtersearch 

// what DOM element to search in, use element type, .class_name or #id
search_element='' 

// show table header or not when filtering
show_header_in_table='false'

// filter heading 
text='Page filter'

// class to style clear icon
clear_icon_class='delete-icon'

// clear filter text
clear_text='Clear' 

// enable or disable to set focus in filter input element on page load
set_focus_on_load='true'
]

Live samples using the plugin

Use this [filtersearch] shortcode

[filtersearch search_element='#name_table' text='Filter name in table' show_header_in_table=true clear_text='Clear filter' set_focus_on_load=false]

which enables this filter

Filter name in tableclear filter

on this table (with id name_table)

First nameLast name
EmilySmith
EdithJohnson
JohnWilliams
SophiaBrown
RobertJones
PaulaGarcia
JamieMiller
RobertDavis
MartinaRodriguez
PabloMartinez

Use this [csvsearch] shortcode

[csvsearch src='/wp-content/uploads/2021/09/sample.csv' searchtext='Search in file' format='{b}{0} {1}{/b} {2} - {3}{br/}' nothing_found_message='No hits for: ']

to show this search

for a search in this csv-sample-file. Try searching for a name (I’m using the same sampel names as in the table above) or a favorite color (pink, blue, red, …) or lucky number (3, 6, 7, …) to see the results.

Download

Download the plugin from wordpress.org.

Donate

Feel free to donate if you find the plugin useful 🙂

Select2 on existing select-dropdown

I had some issues with using Selct2 on an already existing select where the select attribute was already set. The problem was Select2 didn’t unselect the previously set option. To by-pass that I did this workaround.

To use Select2 check their installation guide here. When that is setup I used this jquery snippet where I;

  1. temporary save the previously set option
  2. removing that attribute from option
  3. init Select2 to the select element
  4. set the saved option again with the Select2 .val() function
jQuery(document).ready( function($) {
  
  // temporary save the current selected option
  selected = $("#my_select option:selected").val(); 
  
  // remove selected attribute to make default selected work
  $("#my_select option:selected").removeAttr("selected");
    
  // init select2
  $("#my_select").select2({
    minimumResultsForSearch: -1,
    multiple: false
  });

  // set default value again
  $("#my_select").val(selected); 

})

This is an example of previous select snippet where the second option is pre-selected.

<select id="my_select">
  <option value="my-first">First option</option>
  <option value="my-second" selected="selected">Second option</option>
</select>

Elementor Custom Modules

Creating lots of modules in you theme for Elementor? Do you want to skip the step of loading the files and classes manually? I use this code which makes things very handy, just create the php-file with the same name as the class and it will be loaded automagic.

class My_Elementor_Widgets_Loader {
  protected static $_instance = null;

  /* change path to the local directory where you put the elementor modules */
  private $path = "/php/elementor_widgets/";
  public static function instance() {
    if ( ! isset( self::$_instance ) ) {
      self::$_instance = new self();
    }
    return self::$_instance;
  }

  protected function __construct() {
    add_action( 'elementor/widgets/widgets_registered', [ $this, 'register_widgets' ], 99 );
  }

  public function register_widgets() {
    $this->include_widgets_files();
    /* register all classes (must be named as the php files) */
    foreach(glob(get_stylesheet_directory() . "/php/elementor_widgets/*.php") as $file) {
      $path_parts = pathinfo($file);

      /* change if using other namespace, or remove '__NAMESPACE__ .' if no namespace */
      $class_name = __NAMESPACE__ . '\\Widgets\\' . $path_parts['filename'];
      \Elementor\Plugin::instance()->widgets_manager->register_widget_type( new $class_name() );
    }
  }

  public function include_widgets_files() {
    /* load all php files */
    foreach(glob(get_stylesheet_directory() . $this->path . "*.php") as $file) {
      require_once($file);
    }
  }
}

My_Elementor_Widgets_Loader::instance();

Hope this will help you!