Prefixing prices of certain product categories with text in Woocommerce I had the need to prefix the price for certain product categories on only the shop page (because the price can be higher depending on extras that the customer might want).

These were my requirements for this code:


Add the prefix only on the shop page, not on the product page;
Only add the prefix to certain (hardcoded) product categories.


I'd like some advice on possible improvements and certainly about possible security risks, if there are any.

Along with that, I've heard that globals are considered bad practise, but I see them a lot in Wordpress. What are the alternatives, if there's any.

This is the code:

add_filter('woocommerce_get_price_html', 'change_product_price_html');
function change_product_price_html($price){

  // Check if we're on the shop page
  // Don't want the prefix on the product pages.
  if( is_shop() ) {
    global $product;

    // ID of categories to add the prefix to
    $categories = ["17"];

    // Loop through all the category ID's if they equal one of the values
    // in the array, add the prefix.
    foreach( $product-&gt;get_category_ids() as $id ) {
      if( in_array($id, $categories) ) {

        // Add prefix
        $prefixedPrice   = "&lt;span class='woocommerce-Price-amount amount'&gt;Starting at &lt;/span&gt;";
        $prefixedPrice  .= $price;

        return $prefixedPrice;
      }
    }
    // Nothing matched in the loop,
    // return the price without the prefix.
    return $price;
  }
  // We're not on the shop page so
  // return the price without the prefix.
  return $price;
}
You could reduce your script to this: (untested)
add_filter('woocommerce_get_price_html', 'change_product_price_html');
function change_product_price_html($product, $price) {
    $categories = [&quot;17&quot;];
    if (!is_shop() || !array_intersect_key(array_flip($product-&gt;get_category_ids()), array_flip($categories))) {
        return $price;
    }
    return &quot;&lt;span class=\&quot;woocommerce-Price-amount amount\&quot;&gt;Starting at &lt;/span&gt;{$price}&quot;;
}


pass the $product into the custom function's scope as an argument to avoid the global declaration.

merge the un-prefixed return conditions into a single expression.

while only a benchmark executed on your system will tell the real truth, I am employing a key-based comparison between two arrays.  The downside is that it may do more work than it needs to (by finding multiple matches). The good news is, it is not going to perform multiple full array scans like a looped in_array() technique might.  I'm not going to be too pushy about how to best compare the two category arrays -- I just wanted to show an alternative.


Alternatively, this will be an easier array-to-array comparison to read:
if (!is_shop() || !array_intersect($product-&gt;get_category_ids(), $categories)) {
    return $price;
}

I assume you were calling your posted function like change_product_price_html($price);.
To add the $product variable as the first expected argument, call my custom function like this:
change_product_price_html($product, $price);