admin管理员组

文章数量:1418112

I've read a bunch of articles about overriding the default /woocommerce/ templates and tried implementing the following (which were the best/most relevant that I could find all to no avail):

  • Load WooCommerce templates from my plugin folder first
  • Override WooCommerce Template File Within a Plugin

Essentially, what I would like to accomplish is: load all template files (for archives and posts not just template parts) from ~/wp-content/my-plugin/templates/woocommerce/* UNLESS the files are in my theme (and I don't have to override each file instance in my function) . For instance:

  • ~/wp-content/my-plugin/templates/woocommerce/single-product.php (this seems like it just doesn't want to load via plugin)
  • ~/wp-content/my-plugin/templates/woocommerce/archive-products.php (this seems like it just doesn't want to load via plugin)
  • ~/wp-content/my-plugin/templates/woocommerce-pdf-invoices-packing-slips/* (I also want to be able to override other plugin extension templates just like I would be able to in my child theme)

EDIT:

The friendly folks at SkyVerge sent me the following code, which I tested and confirm that it works for template parts.

// Locate the template in a plugin
function myplugin_woocommerce_locate_template( $template, $template_name, $template_path ) {

    $_template = $template;

    if ( ! $template_path ) {
        $template_path = WC()->template_path();
    }

    $plugin_path = myplugin_plugin_path() . '/templates/';

    // Look within passed path within the theme - this is priority
    $template = locate_template(
        array(
            trailingslashit( $template_path ) . $template_name,
            $template_name
        )
    );

    // Modification: Get the template from this plugin, if it exists
    if ( ! $template && file_exists( $plugin_path . $template_name ) ) {
        $template = $plugin_path . $template_name;
    }

    // Use default template
    if ( ! $template ) {
        $template = $_template;
    }

    return $template;
}
add_filter( 'woocommerce_locate_template', 'myplugin_woocommerce_locate_template', 10, 3 );

// Helper to get the plugin's path on the server
function myplugin_plugin_path() {
    // gets the absolute path to this plugin directory
    return untrailingslashit( plugin_dir_path( __FILE__ ) );
}

The above code works for something like:

  • ~/myplugin/templates/single-product/product-image.php

But does NOT work for:

  • ~/myplugin/templates/single-product.php

Where I'm getting stuck:

  • There are solutions to override bits and pieces of WC templates, but there I've not found / been able to create a solution that does comprehensive overrides (i.e. overriding ability just like a child theme would)
  • I can't seem to find the right combination of filter hooks; single-product.php and archive-product.php seem to be controlled by functions outside the standard WC template functions

Thanks in advance!

I've read a bunch of articles about overriding the default /woocommerce/ templates and tried implementing the following (which were the best/most relevant that I could find all to no avail):

  • Load WooCommerce templates from my plugin folder first
  • Override WooCommerce Template File Within a Plugin

Essentially, what I would like to accomplish is: load all template files (for archives and posts not just template parts) from ~/wp-content/my-plugin/templates/woocommerce/* UNLESS the files are in my theme (and I don't have to override each file instance in my function) . For instance:

  • ~/wp-content/my-plugin/templates/woocommerce/single-product.php (this seems like it just doesn't want to load via plugin)
  • ~/wp-content/my-plugin/templates/woocommerce/archive-products.php (this seems like it just doesn't want to load via plugin)
  • ~/wp-content/my-plugin/templates/woocommerce-pdf-invoices-packing-slips/* (I also want to be able to override other plugin extension templates just like I would be able to in my child theme)

EDIT:

The friendly folks at SkyVerge sent me the following code, which I tested and confirm that it works for template parts.

// Locate the template in a plugin
function myplugin_woocommerce_locate_template( $template, $template_name, $template_path ) {

    $_template = $template;

    if ( ! $template_path ) {
        $template_path = WC()->template_path();
    }

    $plugin_path = myplugin_plugin_path() . '/templates/';

    // Look within passed path within the theme - this is priority
    $template = locate_template(
        array(
            trailingslashit( $template_path ) . $template_name,
            $template_name
        )
    );

    // Modification: Get the template from this plugin, if it exists
    if ( ! $template && file_exists( $plugin_path . $template_name ) ) {
        $template = $plugin_path . $template_name;
    }

    // Use default template
    if ( ! $template ) {
        $template = $_template;
    }

    return $template;
}
add_filter( 'woocommerce_locate_template', 'myplugin_woocommerce_locate_template', 10, 3 );

// Helper to get the plugin's path on the server
function myplugin_plugin_path() {
    // gets the absolute path to this plugin directory
    return untrailingslashit( plugin_dir_path( __FILE__ ) );
}

The above code works for something like:

  • ~/myplugin/templates/single-product/product-image.php

But does NOT work for:

  • ~/myplugin/templates/single-product.php

Where I'm getting stuck:

  • There are solutions to override bits and pieces of WC templates, but there I've not found / been able to create a solution that does comprehensive overrides (i.e. overriding ability just like a child theme would)
  • I can't seem to find the right combination of filter hooks; single-product.php and archive-product.php seem to be controlled by functions outside the standard WC template functions

Thanks in advance!

Share Improve this question edited Jul 13, 2017 at 11:54 Ryan Dorn asked Jul 10, 2017 at 19:56 Ryan DornRyan Dorn 3699 silver badges23 bronze badges
Add a comment  | 

4 Answers 4

Reset to default 4 +50

WooCommerce uses the template_include filter/hook to load main templates like archive-product.php and single-product.php. And here's the class which handles main templates.

And there's a filter in that class which you can use to capture the default file (name) which WooCommerce loads based on the current request/page — e.g. single-product.php for single product pages.

You can't, however, simply hook to that filter, return a custom template path and expect it to be used (because the path has to be relative to the active theme folder). But you can do something like in the second snippet below (which is tried & tested working on WordPress 5.2.2 with WooCommerce 3.6.5, the latest version as of writing):

  1. First, a helper function:

    // Helper function to load a WooCommerce template or template part file from the
    // active theme or a plugin folder.
    function my_load_wc_template_file( $template_name ) {
        // Check theme folder first - e.g. wp-content/themes/my-theme/woocommerce.
        $file = get_stylesheet_directory() . '/woocommerce/' . $template_name;
        if ( @file_exists( $file ) ) {
            return $file;
        }
    
        // Now check plugin folder - e.g. wp-content/plugins/my-plugin/woocommerce.
        $file = 'full/path/to/your/plugin/' . 'woocommerce/' . $template_name;
        if ( @file_exists( $file ) ) {
            return $file;
        }
    }
    
  2. To override main WooCommerce templates (e.g. single-product.php):

    add_filter( 'woocommerce_template_loader_files', function( $templates, $template_name ){
        // Capture/cache the $template_name which is a file name like single-product.php
        wp_cache_set( 'my_wc_main_template', $template_name ); // cache the template name
        return $templates;
    }, 10, 2 );
    
    add_filter( 'template_include', function( $template ){
        if ( $template_name = wp_cache_get( 'my_wc_main_template' ) ) {
            wp_cache_delete( 'my_wc_main_template' ); // delete the cache
            if ( $file = my_load_wc_template_file( $template_name ) ) {
                return $file;
            }
        }
        return $template;
    }, 11 );
    
  3. To override WooCommerce template parts (retrieved using wc_get_template_part()):

    add_filter( 'wc_get_template_part', function( $template, $slug, $name ){
        $file = my_load_wc_template_file( "{$slug}-{$name}.php" );
        return $file ? $file : $template;
    }, 10, 3 );
    
  4. To override other WooCommerce templates (retrieved using wc_get_template() or wc_locate_template()):

    add_filter( 'woocommerce_locate_template', function( $template, $template_name ){
        $file = my_load_wc_template_file( $template_name );
        return $file ? $file : $template;
    }, 10, 2 );
    

Btw, there's also the woocommerce_template_path filter for those of you who're just looking to change the default WooCommerce templates folder (woocommerce) in the active theme folder.

function woo_template_replace( $located, $template_name, $args, $template_path, $default_path ) {

if( file_exists( plugin_dir_path(__FILE__) . 'templates/' . $template_name ) ) {
    $located = plugin_dir_path(__FILE__) . 'templates/' . $template_name;
}

return $located;
}


function woo_get_template_part( $template , $slug , $name ) {

if( empty( $name ) ) {
    if( file_exists( plugin_dir_path(__FILE__) . "/templates/{$slug}.php" ) ) {
        $template = plugin_dir_path(__FILE__) . "/templates/{$slug}.php";
    }
} else {
    if( file_exists( plugin_dir_path(__FILE__) . "/templates/{$slug}-{$name}.php" ) ) {
        $template = plugin_dir_path(__FILE__) . "/templates/{$slug}-{$name}.php";
    }
return $template;
}

add_filter( 'wc_get_template' , 'woo_template_replace' , 10 , 5 );

add_filter( 'wc_get_template_part' , 'woo_get_template_part' , 10 , 3 );

You can use this snippet in your plugin root file and place your all woocommerce templates file in templates directory.

Plugin structure for reference

plugins
  woo-template-replace (plugin root folder)
     woo-template-replace.php (plugin root file)
     templates (folder)
        single-content.php (woocommerce template file)
        searchform.php (woocommerce template file)

In this scenario you can use the following filter wc_get_template_part.

Hook reference link: wc_get_template_part

If you don't know how to use filters read this article wordpress hooks for non developers

If you want to overriding the templates for WooCommerce, then I have your answer. I just have created a complate WooCommerce Theme to my client and Support Everthing in WooCommerce so let's get started.

First of all before doing anything this page is very good if you read it slowly WooCommerce Overriding the plugins templates.

Step 1: In the functions.php add the WooCommerce Support

if (!function_exists( 'albadrbakelser_setup')) :
    function albadrbakelser_setup() {

        // Add Woocommerce Support
        add_theme_support(
            'woocommerce', array(
                //'thumbnail_image_width' => 150,
                // 'gallery_thumbnail_image_width' => 100,
                //'single_image_width'    => 300,

                'product_grid'          => array(
                    'default_rows'    => 5,
                    'min_rows'        => 1,
                    'max_rows'        => 10,
                    'default_columns' => 4,
                    'min_columns'     => 1,
                    'max_columns'     => 4,
                    ),
                )
        );
        add_theme_support( 'wc-product-gallery-zoom' );
        add_theme_support( 'wc-product-gallery-lightbox' );
        add_theme_support( 'wc-product-gallery-slider' );


    }
endif;
add_action( 'after_setup_theme', 'albadrbakelser_setup' );

OR you can use just this if you don't want everythings

function mytheme_add_woocommerce_support() {
    add_theme_support( 'woocommerce' );
}
add_action( 'after_setup_theme', 'mytheme_add_woocommerce_support' );

Step 2: Override something.

Example: To add "Hello" to the single product title copy: wp-content/plugins/woocommerce/single-product/title.php to wp-content/themes/yourtheme/woocommerce/single-product/title.php

Then Open the title.php that you have copied in this direction wp-content/themes/yourtheme/woocommerce/single-product/title.php and write Hello between the h1 html tag like this <h1>Hello</h1>. Then save the file

Last Step: Go to the single product in your site to check if the Hello is there. Make sure you have created a product to visit.

Results:

Note:

In case nothings work try to create woocommerce.php file in your root by following this page https://docs.woocommerce/document/third-party-custom-theme-compatibility/

This is the page to start with the add support https://github/woocommerce/woocommerce/wiki/Declaring-WooCommerce-support-in-themes

本文标签: WooCommerceLoad Templates From Plugin For All Template Files