Thanks for all the code, but I am stuck with a couple of questions.
I am currently developing a theme with the Sage 9.0.0-beta.4 library and Woocommerce integration.
What version of Sage did you use for the code you posted? I more or less get a result when the original files in the Woocommerce plugin directory (archive-product.php & single-product.php) are completely quoted out and I add echo App\Template('woocommerce');
at the end of these files.
Then everything loads fine, but when you would update Woocommerce it will override these changes. This is, offcourse, a unwanted situation. It needs to keep working no matter what I would update.
Did you do any of these things, or just left them as is when you install Woocommerce for the first time?
Also, which Controller are you using? Is it under resources/controllers
or app/Controllers
?
I tried both but didn’t get any result.
To get this straight, these are the steps you took:
-
Created a file named woocommerce.blade.php
in resources/views
containing the @php(App\woocommerce_content(get_defined_vars()))
-
You are showing the original wc_get_template_part
function from wc-core-functions.php
in the Woocommerce plugin directory. But didn’t do anything with it right?
-
The code you applied to override the original wc_get_template_part
function and did you put it in filters.php
under themes/your_theme_name/app
or setup.php
, or just changed the original?
In case of php files you use the first piece of code and incase of blade files you use the second? Or you just put both in them and let the site figure it out?
-
Here you update the woocommerce_content()
function with your own, did you let the original(Woocommerce plugin directory) be as is and put this code in the setup.php
under themes/your_theme_name/app
or just edited the original?
-
You apply some code to the archive.blade.php
& single-product.blade.php
pretty straight forward.
Thanks in advance!
Edit December 22nd
Together with a colleague found out that we had to change the following to get the correct templates:
1. Edit helpers.php
Edit the function filter_templates
in helpers.php
under themes/your_theme_name/app
to look in the resources/views/woocommerce
directory like so:
function filter_templates($templates)
{
return collect($templates)
->map(function ($template) {
return preg_replace('#\.(blade\.)?php$#', '', ltrim($template));
})
->flatMap(function ($template) {
$paths = apply_filters('sage/filter_templates/paths', ['views', 'resources/views', 'resources/views/woocommerce']);
return collect($paths)
->flatMap(function ($path) use ($template) {
return [
"{$path}/{$template}.blade.php",
"{$path}/{$template}.php",
"{$template}.blade.php",
"{$template}.php",
];
});
})
->filter()
->unique()
->all();
}
This lets the function locate_template
also look in the resources/views/woocommerce
folder, where we declare our blade templates
2. Change the wc_get_template_part
because of #1.
Wherever locate_template
is used look for resources/views . WC()->template_path() .
and remove the resources/views
part of it.
This change needs to be done because the filter_templates
function, which we changed in #1 already looks in the resources/views
directory but not the resources/views/woocommerce
directory.
- In the
resources
root we created a directory named woocommerce
with the archive-product.php
(for example) which contained this:
<?php
$template = 'woocommerce.archive-product';
$data = collect(get_body_class())->reduce(function ($data, $class) use ($template) {
return apply_filters("sage/template/{$class}/data", $data, $template);
}, []);
echo App\Template($template, $data);
Notice that $template
is filled with the woocommerce.archive-product
, this is done so the template that we look for in resources/views/woocommerce
is archive-product.blade.php
4. create archive-product.blade.php
and more
As you could have guessed reading #3 we need to create a archive-product.blade.php
in the resources/views/woocommerce
folder.
This file contains the normal blade template stuff like @extends
and all that yada yada. But also this:
@while(have_posts()) @php(the_post())
{{ App\wc_get_template_part('content', 'product', null, get_defined_vars()) }}
@endwhile
With this we load a new blade template for the products named content-product.blade.php
(more on #5) and we really get control over our Woocommerce content, you can style it the way you would like, fetch the needed data etc.
5. Create the last blade view and see the awesomeness rise
As mentioned in #4 we also created a new content-product.blade.php
because Woocommerce loads this file by default, and we wanted control over this. So we looked it up in the Woocommerce plugin templates
folder and found it there, so we created our own file named content-product.blade.php
in the resources/views/woocommerce
folder which contains:
@php
global $product;
@endphp
<li @php(post_class())>
{!! do_action( 'woocommerce_before_shop_loop_item' ) !!}
{!! do_action( 'woocommerce_before_shop_loop_item_title' ) !!}
{!! do_action( 'woocommerce_shop_loop_item_title' ) !!}
{!! do_action( 'woocommerce_after_shop_loop_item_title' ) !!}
{!! do_action( 'woocommerce_after_shop_loop_item' ) !!}
</li>
The do_action's
are just tests. With a simple var_dump
you can check the contents of $product
and use as needed.
The same goes for all the other files that Woocommerce loads when viewing a product, ordering etc.
Hope this helps someone who crashed at the same point I did.
Edit 8th of January
I further changed the setup.php
so I can call wc_get_template
function within blade files.
Here is what I added to the setup.php
:
function wc_locate_template( $template_name, $template_path = '', $default_path = '' ) {
if ( ! $template_path ) {
$template_path = WC()->template_path();
}
// Look within passed path within the theme - this is priority.
$template = locate_template(
array(
trailingslashit( $template_path ) . $template_name,
$template_name,
)
);
// Get default template/
if ( ! $template || WC_TEMPLATE_DEBUG_MODE ) {
$template = $default_path . $template_name;
}
// Return what we found.
return apply_filters( 'woocommerce_locate_template', $template, $template_name, $template_path );
}
function wc_get_template( $template_name, $args = array(), $template_path = '', $default_path = '' ) {
if ( ! empty( $args ) && is_array( $args ) ) {
extract( $args );
}
$located = wc_locate_template( $template_name, $template_path, $default_path );
if ( ! file_exists( $located ) ) {
wc_doing_it_wrong( __FUNCTION__, sprintf( __( '%s does not exist.', 'woocommerce' ), '<code>' . $located . '</code>' ), '2.1' );
return;
}
// Allow 3rd party plugin filter template file from their plugin.
$located = apply_filters( 'wc_get_template', $located, $template_name, $args, $template_path, $default_path );
do_action( 'woocommerce_before_template_part', $template_name, $template_path, $located, $args );
include( $located );
do_action( 'woocommerce_after_template_part', $template_name, $template_path, $located, $args );
}
The filters.php
file already had this, like mentioned in @mtxz 's example:
add_filter('wc_get_template', function ($located, $template_name, $args, $template_path, $default_path) {
$bladeTemplateName = str_replace('.php', '.blade.php', $template_name);
$bladeTemplate = locate_template([$bladeTemplateName, 'resources/views/' . WC()->template_path() . $bladeTemplateName]);
if ($bladeTemplate) {
return template_path($bladeTemplate, $args);
}
return $located;
}, PHP_INT_MAX, 5);
In the wc_locate_template
function I made a minor change, basically just deleted one if statement:
if ( ! $default_path ) {
$default_path = WC()->plugin_path() . '/templates/';
}
I copied it’s contents from woocommerce/includes/wp-core-functions.php
, therefore this delete. It looks for the templates
directory in the plugin folder.
With this code added to the setup.php
I can make use of custom templates instead of parts.
Example:
Woocommerce makes use of the wc_get_template
function to call the title of a single product.
I wanted some extra flexibility with this, so I can customize the title.php
file without it being overwritten whenever Woocommerce updated.
Now I have this folder structure under views (sage 9):
views
| - woocommerce (here live all the basic Woocommerce related blade files)
| | - single-product (here live my custom templates related to single product)
| | | title.php etc.
| | archive.product.blade.php etc.
| 404.blade.php etc.
Like the folder single-product
I am now able to add directories for each individual directory(that I want to override) that exists in Woocommerce’s templates
directory and write my own code based on the original files.
So I created the directory single-product
under the woocommerce
directory in the views
directory.
The templates are being used in the following order:
single-product.blade.php
-
single-product.blade.php
looks for content-single-product.blade.php
-
content-single-product.blade.php
looks for single-product/title.php
If found confusing, look in the templates
directory in the Woocommerce plugin, it will make more sense.
single-product.blade.php
@extends('layouts.app')
@include('partials.headers.woocommerce-header')
@section('content')
<div class="container">
<div class="row">
@while(have_posts()) @php(the_post())
{{ App\wc_get_template_part('content', 'single-product', null, get_defined_vars()) }}
@endwhile
</div>
</div>
@endsection
Here we call for the wc_get_template_part
function located under the App
namespace.
It will look for a template named content-single-product
within the same directory.
content-single-product.blade.php
@php
global $product;
@endphp
<div class="col-6">
<div class="img-fluid">
{{ App\wc_get_template('single-product/image.php') }}
</div>
</div>
<div class="col-6">
{{ App\wc_get_template('single-product/title.php') }}
</div>
In this file, we go hunting for the image.php
and title.php
in the single-product
directory, also under the App
namespace.
single-product/title.php
the_title( '<h1 class="product_title entry-title">', '</h1>' );
Here we will load the title with it’s size & classes.
Hope this makes sense & helps