phpwordpresswoocommercereplacehtml-entities

Woocommerce get_cart_subtotal() value contains HTML entities interfering with value sanitization process


I'm trying to strip the tags and remove extraneous characters from the value returned from Woocommerce's get_cart_subtotal() method, but I can't manage to get it in the correct format. Something is fishy.

I'm using WC()->cart->get_cart_subtotal(); to retrieve the value. In this example my value is 2,429kr and the raw returned value is <span class="amount">2,429kr</span>

$cart_total = WC()->cart->get_cart_subtotal();
$cart_total_format = strip_tags($cart_total);
$cart_value = preg_filter("/[^0-9,.]/", "", $cart_total_format);

echo $cart_value;

Result = 2,429107114
Expected = 2,429

I'm not a PHP wizard so I thought I was doing something wrong and did try several different approaches and methods without getting the correct result.

Then I did try to output the raw string value from WC()->cart->get_cart_subtotal();

$string_total = '<span class="amount">2,429kr</span>';
$string_total_format = strip_tags($string_total);
$string_value = preg_filter("/[^0-9,.]/", "", $string_total_format);

echo $string_value;

Result = 2,429
Expected = 2,429

Why? :(

Update

I found this while digging around in Woocommerce's source code:

case 'SEK' : $currency_symbol = '&#107;&#114;'; break;

So the real value is:

<span class="amount">2,429&#107;&#114;</span>

The question now is what is the best approach to filter this out? My quick fix approach is as follows; it's not beautiful but fixes the issue.

$cart_total = WC()->cart->get_cart_subtotal();
$cart_total_format = strip_tags($cart_total);
$cart_value = preg_filter("/[^0-9,.]/","", $cart_total_format);
$cart_value_new = preg_filter("/107114/",".", $cart_value);

echo $cart_value_new;

Result = 2,429
Expected = 2,429


Solution

  • Ok, so this is what is happening. get_cart_subtotal() returns an HTML-encoded string. Because you are not looking at the actual source, but rather var_dump-ing it and looking at the HTML you are seeing <span class="amount">2,429kr</span>, when in fact the "k" and "r" are encoded into their equivalent HTML entities (based on their ASCII codes), &#107; and &#114.

    That is also why var_dump shows string(45) "2,429kr" when it should in fact return string(7) "2,429kr" if the currency weren't encoded (and the <span> tags weren't interpreted by the browser).

    Then, when you apply the preg_filter, it also includes the numbers from the HTML entities, of course, because they match the regular expression.

    So the easiest solution is to decode all HTML entities before filtering:

    $cart_total = html_entity_decode($cart_total, ENT_QUOTES, 'UTF-8');
    

    so your code becomes:

    $cart_total = WC()->cart->get_cart_subtotal();
    $cart_total = html_entity_decode($cart_total, ENT_QUOTES, 'UTF-8');
    // rest of your code