1

I have seen various questions about this but I am unsure how to apply those methods in this particular case.

I am trying to add a filter to a plugin which returns output with the apply_filters hook:

public function get_shipment_tracking_column( $order_id ) {
        ob_start();

        $tracking_items = $this->get_tracking_items( $order_id );

        if ( count( $tracking_items ) > 0 ) {
            echo '<ul>';

            foreach ( $tracking_items as $tracking_item ) {
                $formatted = $this->get_formatted_tracking_item( $order_id, $tracking_item );
                printf(
                    '<li><a href="%s" target="_blank">%s</a></li>',
                    esc_url( $formatted['formatted_tracking_link'] ),
                    esc_html( $tracking_item['tracking_number'] )
                );
            }
            echo '</ul>';
        } else {
            echo '–';
        }

        return apply_filters( 'woocommerce_shipment_tracking_get_shipment_tracking_column', ob_get_clean(), $order_id, $tracking_items );
    }

In my particular case I need to change the contents within the <a> tag, so I tried the following:

add_filter('woocommerce_shipment_tracking_get_shipment_tracking_column', 'woocommerce_shipment_tracking_get_shipment_tracking_column_custom', 10, 2);
function woocommerce_shipment_tracking_get_shipment_tracking_column_custom($order_id, $tracking_items){
    $tracking_items = $this->get_tracking_items( $order_id );

    if ( count( $tracking_items ) > 0 ) {
        echo '<ul>';

        foreach ( $tracking_items as $tracking_item ) {
            $formatted = $this->get_formatted_tracking_item( $order_id, $tracking_item );
            printf(
                '<li><a href="%s" target="_blank">%s</a></li>',
                esc_url( $formatted['formatted_tracking_link'] ),
                'MY NEW TEXT'
            );
        }
        echo '</ul>';
    } else {
        echo '–';
    }
}

Note the "My new text". While I can get content to output if I just remove everything within the function and just do echo "something", I really need to output information specific to an order. I am just unsure how to do this if I can't use $this.

So my question - how can I correctly use add_filters in this case, and is it possible to use $this in my function to get the order data that is originally being sent to this filter

  • Normally questions about WooCommerce would be offtopic as 3rd party plugins are offtopic, but this just looks like a general filters question, that can be answered generically. – Tom J Nowell Oct 21 '19 at 13:56
  • @TomJNowell Indeed. There is nothing really specific about WooCommerce here. I am just trying to understand how filters would be used in this specific case. – wickywills Oct 21 '19 at 14:00
1

There are a lot of fundamental mistakes here that suggest a misunderstanding of what filters are, and how they work.

Filters are a way for you to intercept and modify a value. For example:

add_filter( 'my_number', function( $value ) {
 return $value + 1;
} );
$stuff = apply_filters( 'my_number' , 5 );
echo $stuff; // outputs 6

Here, we have the number 5, and we give other code the opportunity to modify it. Notice the filter that was added that adds 1 to every value. The value we wanted to modify was passed in as the first value, and is the only thing absolutely necessary. We then modified it and returned the new value.

A filter can pass additional parameters, but these are just extra information. They can't be modified and are entirely optional.

$final_result = apply_filters( 'filter name', $thing_to_be_filtered, $other_parameters_that_are_all_optional, etc.. );

Your code does none of that:

  • Your code returns no value to act as a replacement, so PHP will return null or an empty value, aka return '';
  • Your code calls echo with no output buffers, so the output would get sent straight to the browser without going through the proper process
  • for some reason you ignored the first value and renamed it to $object_id, the second value, so all your parameters are off by one. The value being filtered is the HTML, which is why it calls ob_get_clean() to grab the value of the HTML sent to output. That's what's being filtered, not the order ID.

As for the filter you're working with, you have 2 options for changing the anchor tag:

  • modify the string passed as the first value
  • Ignore the value to be filtered and generate a new one from scratch

It looks like you tried to do the second, but got the function arguments wrong, and didn't return anything. I'd suggest doing the latter option as modifying a HTML string is not easy or reliable.

Finally, there's a bug here:

            $formatted = $this->get_formatted_tracking_item( $order_id, $tracking_item );

$this can only be used inside objects, but this is a standard PHP function, not an object. This line will cause a PHP fatal error. You will need to find an alternative method of generating this link via WooCommerce support. This kind of bug implies that there are some gaps in the basic fundamentals of how functions and objects work in PHP/general programming, a refresher should make all of this a lot clearer/easier

The same mistake is also made here:

$tracking_items = $this->get_tracking_items( $order_id );

However, since $tracking_items is passed by the filter, this line is unnecessary, just reuse the tracking items it's already fetched.

  • A really great explanation, thanks very much! – wickywills Oct 22 '19 at 6:40

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.