1

I'm creating a function in functions.php with a custom hook, and from what I've read somewhere, it's good practice to return instead of use echo in a WordPress function? Correct me if I'm wrong.

Anyway, so with echo, my function works, but breaks everything else. With return, the function is no longer outputting anything, but nothing's broken. I tried to use this question as a reference to fix mine.

Here's what I have:

function display_collections_menu(){
/* Get WooCommerce's product categories which is custom taxonomy */
  $prod_cat_args = array(
      'taxonomy'     => 'product_cat', //woocommerce
      'orderby'      => 'name',
      'empty'        => 0
    );

    $woo_categories = get_categories( $prod_cat_args );

    $woo_menu = '';

    $woo_menu.= '<ul class="menu-collections">';

    /* For each first level category, get the image, name, and link */
    foreach ( $woo_categories as $woo_cat ) {

        if( $woo_cat->category_parent == 0 ) {
          $woo_cat_id = $woo_cat->term_id; //category ID
          $woo_img_id = get_woocommerce_term_meta( $woo_cat_id, 'thumbnail_id', true ); //category image ID
          $woo_parent_image = wp_get_attachment_url( $woo_img_id ); //category image url
          $woo_cat_slug = $woo_cat->slug; //category slug for classes
          $woo_cat_name = $woo_cat->name; //category name for link

          /* return the image/link/name */
          $orw_woo_menu.= '<li class="menu-product menu-item menu-item-object-' . $woo_cat_slug . ' ">
          <a href="' . get_term_link( $woo_cat_slug, 'product_cat' ) . '" class="menu-product-link">
          <img src="' . $woo_parent_image . '" alt=" ' . $woo_cat_name . ' " class="menu-product-thumb" />
          <p class="menu-product-name">' . $woo_cat_name . '</p></a></li>';
        } 

    }//end of $woo_categories foreach

    $woo_menu.= '</ul>';

    return $woo_menu;   
}
add_action('woo_collections_menu', 'display_collections_menu');

It'll work if instead of using return and a variable, I just echo out the values, but it breaks things. Am I using return wrong?


Updated with an attempt Privateer's solution - still doesn't work:

function display_collections_menu( $input = '' ){
/* Get WooCommerce's product categories which is custom taxonomy */
  $prod_cat_args = array(
      'taxonomy'     => 'product_cat', //woocommerce
      'orderby'      => 'name',
      'empty'        => 0
    );

    $woo_categories = get_categories( $prod_cat_args );

    $woo_menu = '';

    $woo_menu.= '<ul class="menu-collections">';

    /* For each first level category, get the image, name, and link */
    foreach ( $woo_categories as $woo_cat ) {

        if( $woo_cat->category_parent == 0 ) {
          $woo_cat_id = $woo_cat->term_id; //category ID
          $woo_img_id = get_woocommerce_term_meta( $woo_cat_id, 'thumbnail_id', true ); //category image ID
          $woo_parent_image = wp_get_attachment_url( $woo_img_id ); //category image url
          $woo_cat_slug = $woo_cat->slug; //category slug for classes
          $woo_cat_name = $woo_cat->name; //category name for link

          /* return the image/link/name */
          $orw_woo_menu.= '<li class="menu-product menu-item menu-item-object-' . $woo_cat_slug . ' ">
          <a href="' . get_term_link( $woo_cat_slug, 'product_cat' ) . '" class="menu-product-link">
          <img src="' . $woo_parent_image . '" alt=" ' . $woo_cat_name . ' " class="menu-product-thumb" />
          <p class="menu-product-name">' . $woo_cat_name . '</p></a></li>';
        } 

    }//end of $woo_categories foreach

    $woo_menu.= '</ul>';

    return $woo_menu;   
}
add_filter('collections_menu', 'display_collections_menu', 10, 1);
$html_block = apply_filters('collections_menu', $input_html);

And then this in a template:

<?php echo $html_block; ?>

Am I still doing this wrong?

3
  • Isn't an action for new functionality whereas a filter changes existing functionality? I feel like this should be an action or else what am I applying filters to using Privateer's solution?
    – RachieVee
    Jan 14, 2015 at 19:03
  • your goal here is not clear. are you trying to create a way for others to override your menu output with their own?
    – Milo
    Jan 14, 2015 at 19:54
  • @Milo I originally have it as an action so I can run do_action in a template file for cleaner templates. All I want at this point is for my function to spit out what it should in the template whether it's with return, echo, or some other method. I just became confused with Privateer's answer as I second-guessed why I used an action vs a filter but it should work with an action... It appears my return method is the issue, am I right?
    – RachieVee
    Jan 14, 2015 at 20:03

3 Answers 3

2

If you use do_action( 'woo_collections_menu' ); in the template, then your function must echo its value. Otherwise, you are returning the data into a black hole, nothing is outputting what you're returning.

If you use a filter, then you should return the value. The point of a filter is to take a value, filter that value through a function, then do something with the result. In the context of your template, using apply_filters would be a bit strange, because your menu has no value until you construct it. So in the template it would look like:

echo apply_filters( 'collections_menu', '' );

Which is just potentially confusing and unnecessary. That empty string could be a default menu or something, but putting that in the template is probably not the wisest choice.

However, a filter would make sense within the function itself, to allow someone to change the output.

function display_collections_menu(){
    $default_menu = 'my complete menu markup here';
    return apply_filters( 'collections_menu', $default_menu );
}

Then in the template, you could just output the function directly:

echo display_collections_menu();

and someone can add their own filter to modify output if they'd like. Another helpful inclusion could be a filter on the arguments that you fetch terms with, so someone can change menu output without having to reproduce the whole function.

But going back to your original code, adding do_action( 'woo_collections_menu' ); and then echoing menu output directly in the function should also work.

2
  • 1
    Thank you SO much for making sense of that. I figured out that echo worked in the answer I posted with an action, but didn't know why - marking this as correct because you explained it and also provided the handy tip for the filter inside the function. So then someone could just hook into the collections_menu filter and re-structure my menu if they needed to then?
    – RachieVee
    Jan 14, 2015 at 20:36
  • 1
    yes, correct. also if it wasn't clear, you can combine both the do_action to output the menu as well as the apply_filters within the menu function to let others modify output. in that case the filter and the action should have different names.
    – Milo
    Jan 14, 2015 at 20:46
1

From my understanding of actions (as opposed to filters), an action simply does something and stops processing. No return value is actually made use of.

You might change your code to be a filter by accepting an argument (say the html to append to) and then make a call like the following where you want to grab the code:

$html_block = apply_filters('woo_collections_menu', $input_html);

To do this, you might change your function definition:

function display_collections_menu( $input = '' ){
 #code here
}
add_filter('woo_collections_menu', 'display_collections_menu', 10, 1);

That would then put our output into the variable $html_block for use as you see fit.

3
  • Thanks for your answer. I'm a bit confused, is the $input_html in your first code block and the $input = '' within the function parenthesis as a parameter supposed to be the same? What do these two things do? And would I then just echo out $html_block in a template?
    – RachieVee
    Jan 14, 2015 at 18:34
  • I updated my question with your solution - it's still not working for me. Not sure where I went wrong.
    – RachieVee
    Jan 14, 2015 at 18:43
  • The input variable is simply something to pass in, say if you needed to modify some content or add the results to the end of it. You would just return your output as normal and it should go into the html_block variable so that you could then echo it. You could also do echo apply_filters('woo_collections_menu', ''); to output the results if wanted.
    – Privateer
    Jan 14, 2015 at 21:05
0

I still couldn't figure out how to return $woo_menu; with my first example code, but I realized things don't break if I keep the rest of the structure as far as the variable goes and just echo once at the very end. This seems to work for me. Whether this is good practice or not, leave me a comment, but for now, this is the solution I'm using.

Thanks.

function display_collections_menu(){
/* Get WooCommerce's product categories which is custom taxonomy */
  $prod_cat_args = array(
      'taxonomy'     => 'product_cat', //woocommerce
      'orderby'      => 'name',
      'empty'        => 0
    );

    $woo_categories = get_categories( $prod_cat_args );

    $woo_menu = '';

    $woo_menu.= '<ul class="menu-collections">';

    /* For each first level category, get the image, name, and link */
    foreach ( $woo_categories as $woo_cat ) {

        if( $woo_cat->category_parent == 0 ) {
          $woo_cat_id = $woo_cat->term_id; //category ID
          $woo_img_id = get_woocommerce_term_meta( $woo_cat_id, 'thumbnail_id', true ); //category image ID
          $woo_parent_image = wp_get_attachment_url( $woo_img_id ); //category image url
          $woo_cat_slug = $woo_cat->slug; //category slug for classes
          $woo_cat_name = $woo_cat->name; //category name for link

          /* return the image/link/name */
          $orw_woo_menu.= '<li class="menu-product menu-item menu-item-object-' . $woo_cat_slug . ' ">
          <a href="' . get_term_link( $woo_cat_slug, 'product_cat' ) . '" class="menu-product-link">
          <img src="' . $woo_parent_image . '" alt=" ' . $woo_cat_name . ' " class="menu-product-thumb" />
          <p class="menu-product-name">' . $woo_cat_name . '</p></a></li>';
        } 

    }//end of $woo_categories foreach

    $woo_menu.= '</ul>';

    echo $woo_menu; //ECHO at the very end instead of return works for me  
}
add_action('woo_collections_menu', 'display_collections_menu');
1
  • See @milo's answer for an explanation as to why echo works here.
    – RachieVee
    Jan 14, 2015 at 20:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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