2
\$\begingroup\$

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->get_category_ids() as $id ) {
      if( in_array($id, $categories) ) {

        // Add prefix
        $prefixedPrice   = "<span class='woocommerce-Price-amount amount'>Starting at </span>";
        $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;
}
\$\endgroup\$
4
  • \$\begingroup\$ If categories becomes an array of two elements, your code will break due to the early return in your foreach loop. \$\endgroup\$ – mickmackusa Aug 8 '19 at 3:11
  • \$\begingroup\$ And is that purely because I'm returning something in the loop? Because a product can have multiple categories, but as soon as 1 of them matches, I want to add the prefix. They don't all have to match. \$\endgroup\$ – rpm192 Aug 8 '19 at 10:05
  • \$\begingroup\$ Okay, I didn't understand that logic in your script. If that early return on the first qualifying occurrence is desired then no problem. \$\endgroup\$ – mickmackusa Aug 8 '19 at 10:25
  • \$\begingroup\$ Yeah my bad for not adding it to the post, thanks! Any advice about the usage of global $product; ? \$\endgroup\$ – rpm192 Aug 8 '19 at 10:26
0
\$\begingroup\$

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 = ["17"];
    if (!is_shop() || !array_intersect_key(array_flip($product->get_category_ids()), array_flip($categories))) {
        return $price;
    }
    return "<span class=\"woocommerce-Price-amount amount\">Starting at </span>{$price}";
}
  • 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->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);
\$\endgroup\$
2
  • \$\begingroup\$ Thanks, looks clean! How do I pass $product into the function? I added it to the custom function as an argument (website doesn't load), but that doesn't work. I assume I have to declare it somewhere, but where? \$\endgroup\$ – rpm192 Aug 10 '19 at 17:50
  • \$\begingroup\$ Updated my answer. \$\endgroup\$ – mickmackusa Aug 10 '19 at 21:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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