3

I have a function that outputs text after the main_content action hook in WordPress, but Woocommerce is telling me that I have an CRITICAL Uncaught Error: Call to a member function get_id() on null in .../function.php.

I've tried passing in the global $product, and checking if it is a product before running the function. The function seems to work fine, but I'm just trying to get rid of the fatal errors.

Is there something obvious I'm missing?

Here's my function:

add_action('woocommerce_after_main_content', 'display_prewired_notes');
    function display_prewired_notes() {
        global $product; //Tried global variable
        $product_id = $product->get_id(); //getting ID
        $product_name = $product->get_name(); //get name


        if (is_product() && has_term('prewired-pickguard', 'product_cat', $product_id)) { ?>

        //My HTML here
    
<?php
        }

        if (is_product() && $product_id == 6599) { ?>
    
        //More HTML for this specific product

<?php
        }
    };

Edit:

I've tried a few things based on @Martin 's suggestions, and I still can't get this to work.

I've tried:

1:

<?php

global $product


function display_prewired_notes($product) { // Pass it in

        $product_id = $product->get_id(); //getting ID
        $product_name = $product->get_name(); //get name

And I get atal error: Uncaught Error: Call to a member function get_id() on string

2:

Removing the global $product entirely, I get: Uncaught Error: Call to a member function get_id() on null

3:

Removing the global $product and keeping the $product as a parameter: Fatal error: Uncaught Error: Call to a member function get_id() on string

LoicTheAztec
  • 229,944
  • 23
  • 356
  • 399
Sackadelic
  • 945
  • 1
  • 11
  • 21
  • It is Bad Practise to globalise variables. You should instead pass the variable as a argument in the function call. – Martin Nov 11 '20 at 00:09
  • I would also question why you're calling the function before it's been defined, but that might be something taken care of by Woocommerce or elsewhere – Martin Nov 11 '20 at 00:10
  • @Martin so you suggest creating a `global $product` at top of `function.php`? How would you write the passed in argument? – Sackadelic Nov 11 '20 at 00:14
  • 1
    No, I would first prove that you can access $product from outside the function, and then passing it to the function as an argument. – Martin Nov 11 '20 at 00:15
  • Does this answer your question? [Access a global variable in a PHP function](https://stackoverflow.com/questions/15687363/access-a-global-variable-in-a-php-function) – Martin Nov 11 '20 at 00:15
  • Thanks! I'll rewrite the function as a passed in argument. – Sackadelic Nov 11 '20 at 00:21
  • @Martin, I've edited my question to add some more examples of what I'm trying, and I'm still getting errors. Any ideas? Thanks for your help! – Sackadelic Nov 11 '20 at 00:49
  • 1
    What is the global variable `$product` in your setup? You're using it as object, but php complains that it is a string. Can you add `var_dump($product);` after the `global $product` line to see what it really is? – Koala Yeung Nov 11 '20 at 01:23
  • @Sackadelic To avoid this problem, you need first to target Single product pages using `is_product()` conditional tag (see below)… – LoicTheAztec Nov 11 '20 at 02:48

1 Answers1

2

The hook woocommerce_after_main_content is mainly used in 2 WooCommerce templates:

  • templates/archive-product.php (WooCommerce archive pages)
  • templates/single-product.php (WooCommerce single product pages)

So you can only get the WC_Product Object from single product pages and you need to target first single product pages using the conditional tag is_product() where you will be able to get the WC_product Object this way:

add_action( 'woocommerce_after_main_content', 'display_prewired_notes' );
function display_prewired_notes() {
    // Targeting single product pages (before)
    if ( ! is_product() ) return; // exit

    global $product;
    
    // To be sure, If we don't get the product object
    if( ! is_a($product, 'WC_Product') ) {
        // Try to get an instance of the WC_Product object from Post id
        $product = wc_get_product( get_the_id() ); 
    }

    $product_name = $product->get_name(); //get product name

    if ( has_term(array('prewired-pickguard'), 'product_cat', $product->get_id() ) ) { 
        ?> 
        <!-- My HTML here -->
        <?php
    }

    if ( $product->get_id() == 6599 ) { 
        ?> 
        <!-- More HTML for this specific product -->
        <?php
    }
}

Code goes in functions.php file of the active child theme (or active theme). Tested and works.

On archive pages as it's a loop of products, it's not possible to get a product Id or/and the WC_Product Object…

LoicTheAztec
  • 229,944
  • 23
  • 356
  • 399
  • 1
    thank you so much for the help and detailed information - this makes a lot of sense, I appreciate you explaining why this wasn't working before. – Sackadelic Nov 11 '20 at 14:56