11

Why is it the preferred choice, to have WooCommerce function modifications placed inside the theme's 'function.php' file? Overtime, this would make the file rather large. I am of the understanding that it is generally better practice to have lots of well organised smaller files, rather than fewer much larger files.

With this in mind, what is wrong with copying the 'wc-template-functions.php' and 'wc-templates-hooks.php' files into your theme (whilst keeping its file hierarchy) and modifying these files accordingly?

As a side request, from a relative newbie to the WooCommerce platform, I would appreciate if I could get a 'Yes, that works' or a 'No, I have missed something out' response to my below understanding of how the WooCommerce; files, hooks, actions and templates all work with one and other

My Understanding:

  1. The WooCommerce functions are registered within the 'wc-template-functions.php' file. For the purpose of this explanation, I would like to refer to the woocommerce_breadcrumb entry.
  2. WooCommerce then uses the 'wc-templates-hooks.php' file to call the registered function by using a typical entry such as add_action('woocommerce_before_main_content','woocommerce_breadcrumb', 20, 0 ); This simply directs woocommerce_breadcrumb to be called within the woocommerce_before_main_content hook.
  3. WooCommerce is then able to output the above by placing do_action( 'woocommerce_before_main_content' ); where necessary. In this case, within all of the Template files.
Craig
  • 1,872
  • 5
  • 23
  • 56

2 Answers2

21

Your 1,2,3 understanding is correct.

However, the files wc-template-functions.php and wc-templates-hooks.php are not overridden by placing similar files in your theme, so having them in your theme would not do anything.

It's also, a bad idea (in my opinion) to wholesale copy/override files when you want to change something specific. I had to hunt through an entire folder of WooCommerce templates when a client's site crashed to find the actual changes that needed to be maintained.

There's not anything wrong with separating your functions.php file into smaller, more manageable files. And so, you could have a woocommerce-functions.php file named whatever you'd like to store your WooCommerce-specific code.

Edit to expand some thoughts

Anytime WooCommerce (or any WordPress function really) shows you this pattern:

if ( ! function_exists( 'some_function_name' ) ) {

    function some_function_name() {
        echo 'taco';
    }
}

you have a pluggable function and you can just define it in your theme's function.php and WooCommerce will use your version of some_function_name().

However, pluggable functions are hooked where they are hooked and you can't move them by redefining them in your theme/plugin. So a more powerful approach is to remove the function from it's hook and either add to back to a different hook, or add your own custom function, or both. Here's an example that moves a custom title to after the price:

function kia_switch_loop_title(){
    remove_action( 'woocommerce_shop_loop_item_title', 'woocommerce_template_loop_product_title', 10 );
    add_action( 'woocommerce_after_shop_loop_item_title', 'kia_template_loop_product_title', 15 );
}
add_action( 'woocommerce_before_shop_loop_item', 'kia_switch_loop_title' );

function kia_template_loop_product_title() {
    echo '<h4 class="we-do-what-we-want">' . get_the_title() . '</h4>';
}
helgatheviking
  • 25,596
  • 11
  • 95
  • 152
  • Thanks for the guidance and helping put my mind at rest, regarding my WooCommerce understanding. Your suggestion regarding 'splitting up' the functions.php file will be something I will consider in the coming weeks. – Craig Feb 20 '17 at 01:17
  • 1
    Also keep in mind that things that change the appearance of the site belong in your theme (and thus, `functions.php`). But code that changes the functionality of the site, is best suited to it's own plugin... or a site-specific plugin that can be a collection of all your "snippets". – helgatheviking Feb 20 '17 at 03:40
  • I have not got round to learning how to create Plugins as of yet. Whilst I am aware that it is considered best practice to place such codes within a Plugin, what is the main reason for doing so? Does it relate to compatibility? So should an update across WooCommerce etc conflict with a theme's functionality, you can simply deactivate it while you perform the relevant changes? – Craig Feb 20 '17 at 05:02
  • 1
    A plugin is basically some code in the `wp-content/plugins` folder with a specific bunch of comments as the "header". You can create one easily with this [generator](https://wppb.me/). The main reason is to keep presentation code separate from functionality code, so you don't get locked into a particular theme. And as you point out, it's easy to disable the plugin if any conflicts arise. – helgatheviking Feb 20 '17 at 16:10
  • Makes sense! Thanks for your help and insight. :-) – Craig Feb 20 '17 at 16:20
0

was struggling with how to make related products sorting in desc way, just found solution. In case anybody needs it

function custom_remove_hook(){
    remove_action( 'woocommerce_after_single_product_summary', 'woocommerce_output_related_products', 20 );
    add_action( 'woocommerce_after_single_product_summary', 'custom_function_to_sort_related', 22 );
}
add_action( 'woocommerce_after_single_product_summary', 'custom_remove_hook' );

function custom_function_to_sort_related( $args = array() ) {
        global $product;

        if ( ! $product ) {
            return;
        }

        $defaults = array(
            'posts_per_page' => 4,
            'columns'        => 4,
            'orderby'        => 'price', // @codingStandardsIgnoreLine.
            'order'          => 'desc'
        );

        $args = wp_parse_args( $args, $defaults );

        // Get visible related products then sort them at random.
        $args['related_products'] = array_filter( array_map( 'wc_get_product', wc_get_related_products( $product->get_id(), $args['posts_per_page'], $product->get_upsell_ids() ) ), 'wc_products_array_filter_visible' );

        // Handle orderby.
        $args['related_products'] = wc_products_array_orderby( $args['related_products'], $args['orderby'], $args['order'] );

        // Set global loop values.
        wc_set_loop_prop( 'name', 'related' );
        wc_set_loop_prop( 'columns', apply_filters( 'woocommerce_related_products_columns', $args['columns'] ) );

        wc_get_template( 'single-product/related.php', $args );
    }
Gudok
  • 23
  • 3