I want to use a file conditionally upon user input. I am using WooCommerce templates in my child theme. Of course, the file (content-single-product.php) is customized in the child theme. However, I also wish to give users an option to use the default WC file if they want to. In short, I want to use that file conditionally which user will choose.
I am using the PHP copy() and unlink() functions. I just want your expert opinion if this is the best solution or if you have any suggestions better than mine. Here are the functions in my child theme.
/*...for copying the file from a child theme folder to the woocommerce folder...*/
function ac_wc_files_to_theme()
{
$theme_dir = get_stylesheet_directory() . '/woocommerce/files/content-single-product.php';
$theme_dir_file = get_stylesheet_directory() . '/woocommerce/content-single-product.php';
if (!copy($theme_dir, $theme_dir_file)) {
echo "failed to copy $theme_dir to $theme_dir_file...\n";
}
}
/*...for removing the file from a the woocommerce folder...*/
function ac_wc_delete_wc_file(){
$fileArray = array(
get_stylesheet_directory() . '/woocommerce/content-single-product.php'
);
foreach ($fileArray as $value) {
if (file_exists($value)) {
unlink($value);
} else {
echo 'file not found';
}
}
}
/*...calling the options from the theme settings area....*/
if (get_option('ac_wc_default_single') == 1) {
add_action('init', 'ac_wc_delete_wc_file');
remove_action('init', 'ac_wc_files_to_theme');
}
else {
add_action('init', 'ac_wc_files_to_theme');
remove_action('init', 'ac_wc_delete_wc_file');
}
The codes are working fine. Just I need your view if this will do. Thanks
Here's my best guess at filtering the template without extensive testing.
// change the default template path to `woocommerce/files`
function ac_wc_override_template_path(){
return 'woocommerce/files/';
}
add_filter( 'woocommerce_template_path', 'ac_wc_override_template_path' );
// now filter the woocommerce template
function ac_wc_override_single_product($template, $template_name, $template_path) {
$alt_template = '';
if ($template_name == 'content-single-product.php') {
$alt_template = locate_template( trailingslashit( $template_path ) . 'content-single-product-1.php' );
}
if( $alt_template && get_option( 'use_my_themes_templates' ) ){
return $alt_template;
} else {
return $template;
}
}
add_filter('woocommerce_locate_template', 'ac_wc_override_single_product', 20, 3);
Related
I want to remove the information about an installed plugin from the WordPress dashboard plugins page. I have written the following code, but it doesn't work!
please guide me?
add_filter( 'all_plugin', 'remove_plugins');
function remove_plugins($plugins)
{
if(is_plugin_active('/woocommerce-checkout-manager/woocommerce-checkout-manager.php')) {
unset( $plugins['woocommerce-checkout-manager.php'] );
}
return $plugins;
}
I added this code to my template function file but it still doesn't work.
Use the filter below to delete the information of the plugin installed in WordPress and the WordPress plugins page.
Note that in the first value, put the folder and the main file of the plugin, and in the second value, only the main file of the plugin without adding the folder.
add_filter(
'all_plugins',
function ( $plugins ) {
$shouldHide = ! array_key_exists( 'show_all', $_GET );
if ( $shouldHide ) {
$hiddenPlugins = [
'woocommerce-checkout-manager/woocommerce-checkout-manager.php',
'woocommerce-checkout-manager.php',
];
foreach ( $hiddenPlugins as $hiddenPlugin ) {
unset( $plugins[ $hiddenPlugin ] );
}
}
return $plugins;
}
);
To begin with, my problem:
I have a WooCommerce error on the W3C Validator platform.
I overwrite the file by redirecting the template path of WooCommerce for that specific file.
Problem:
The Wordpress Theme that I am currently using is also overwritting the same file as my Custom plugin, as a result the Theme's overwriting cancels out my plugin's overwritting functionality.
CODE:
Here's some of my code:
This is the function I add using the built in wordpress function add_filter() with high priority value of "1" plus the path of the file I am overwritting is... woocommerce/templates/single-product/add-to-cart/variable.php
function wc_locate_template( $template, $template_name, $template_path ) {
// Check if WooCommerce is present on the website
if ( empty( $template ) || ! is_callable( 'WC' ) || ( defined( 'WC_TEMPLATE_DEBUG_MODE' ) && WC_TEMPLATE_DEBUG_MODE ) ) {
return $template;
}
// Variables
$default_path = WC()->plugin_path() . '/templates/';
$plugin_path = untrailingslashit( plugin_dir_path( __FILE__ ) ) . '/templates/';
$template_new = str_replace( $default_path, $plugin_path, $template );
// Processing
if (
false !== strpos( $template, $default_path )
&& file_exists( $template_new )
) {
$template = $template_new;
}
// Output
return $template;
}
add_filter( 'woocommerce_locate_template', 'wc_locate_template', 1, 3 );
Questions:
How can I make sure that my plugin will overwrite the file of in such way or prority so that the theme's overwritting won't overlap it?
Useful links:
Woocommerce Link
W3C Validator Link
Wordpress Link
Thank you in advance for your time.
priority 1 means your function will be applied first, so any other function attached to the filter with a number higher than 1 will simply overwrite your function.
You need to put highest possible number to make sure your function will be the last one applied.
use PHP_INT_MAX to make your function the last one applied.
add_filter( 'woocommerce_locate_template', 'wc_locate_template', PHP_INT_MAX, 3 );
That's an example on how to override a woocommerce template with a plugin:
add_filter( 'woocommerce_locate_template', 'woo_custom_template', 1, 3 );
function woo_custom_template( $template, $template_name, $template_path ) {
global $woocommerce;
$_template = $template;
if ( ! $template_path )
$template_path = $woocommerce->template_url;
$plugin_path = untrailingslashit( plugin_dir_path( __FILE__ ) ) . '/templates/';
// Within passed path within the theme - this is priority
$template = locate_template(
array(
$template_path . $template_name,
$template_name
)
);
// Processing
if( ! $template && file_exists( $plugin_path . $template_name ) )
$template = $plugin_path . $template_name;
if ( ! $template )
$template = $_template;
//Output
return $template;
}
Then you should be able to reach your goal by copying the template you want to override in your plugin folder.
Example:
your_plugin/template/WooCommerce/single-product/add-to-cart/variable.php
Hooks and filter are modification which runs based on priority,
the highest the priority before its being called will be the its final output
Here's an example
Assuming I have this function
function youFree() {
$imFree = apply_filters('free_filter', 'I am free' );
return $imFree;
}
then I have all these filters with different priorities
add_filter('free_filter', function() {
return 'You are not 1';
}, 1);
add_filter('free_filter', function() {
return 'You are not 10';
}, 10);
add_filter('free_filter', function() {
return 'You are not 999';
}, 999);
add_action('init', function() {
add_filter('free_filter', function() {
return 'You are not init 999';
}, 999);
});
add_action('wp_footer', function() {
add_filter('free_filter', function() {
return 'You are not wp_footer';
}, 999);
});
Here is the output
if you call youFree() on wp_head
add_action('wp_head', function() {
echo '<pre>', print_r(youFree(), 1), '</pre>';
});
//the output is "You are not init 999"
//because the add_filter that runs on wp_footer did not take effect
//as the function is already called way higher specifically in wp_head
//and the final value is last filter being called thats added on init hook with 999 priority
but if you call that youFree() function on wp_footer
add_action('wp_footer', function() {
echo '<pre>', print_r(youFree(), 1), '</pre>';
}, 20);
//the output is "You are not wp_footer"
//as this was the very last filter before that function is called on wp_footer
So in your situation,
You have to determine at which point the theme do the modification and at which point the value is being called.
Then you need to inject your filter after your theme modifies it and before it was called by woocommerce. Usually, this is as easy as looking at where the theme calls the filter and adding a priority on your filter which is higher than whats on the theme filter.
but if your having a hard at where to inject it your best option is to find it using query monitor
I am using the Woocommerce Admin Custom Order Fields plugin which is causing issues when searching orders in the backend. When I run a slow query on the admin order search function it searches through these custom fields and adds 10secs or so to the search.
I have found the function that does it with the plugin and I'm trying to work out the best way to disable the custom fields being included in the search.
When I comment out this code the search is quick, a couple of seconds. I want to add an override or disable it somehow in my functions.php
public function add_search_fields( $search_fields ) {
foreach ( wc_admin_custom_order_fields()->get_order_fields() as $order_field ) {
if ( 'date' === $order_field->type ) {
array_push( $search_fields, $order_field->get_meta_key() . '_formatted' );
} else {
array_push( $search_fields, $order_field->get_meta_key() );
}
}
return $search_fields;
}
Can anyone give me some pointers on how to stop this executing without editing the plugin files directly?
Cheers
Nik
Don't comment all the function code, but just the active code inside the function, like:
public function add_search_fields( $search_fields ) {
/*
foreach ( wc_admin_custom_order_fields()->get_order_fields() as $order_field ) {
/* if ( 'date' === $order_field->type ) {
array_push( $search_fields, $order_field->get_meta_key() . '_formatted' );
} else {
array_push( $search_fields, $order_field->get_meta_key() );
}
}
*/
return $search_fields;
}
Now this function will not have any effect, as it's active code is commented.
Now overwriting any core plugin code is really something to avoid… There are always different ways to change things, like using available hooks and other things may be more complicated…
How do you add a category template via a Wordpress plugin. It needs to be for a specific category. So if the category is 'category-awesome' load 'category-awesome.php'. I've come across using the single template hook e.g:
add_filter('single_template', 'my_custom_template');
But haven't found anything for categories or a single category.
Many Thanks
Think I solved it. Use the template include filter hook:
function category_awesome( $template ) {
if (is_category( 'awesome' )) {
$new_template = dirname(__FILE__) . '/custom-template-awesome.php';
if ( '' != $new_template ) {
return $new_template ;
}
}
return $template;
}
add_filter( 'template_include', 'category_awesome' );
I am developing a plugin based on woocommerce and as a part of the I had to override the default template file location of woocommerce. I mean I am looking to have a custom woocommerce template loaded from my plugin.
For doing this I read about woocommerce_locate_template in woocommerce based on this article, but I noticed that the same function has been deprecated as per this link. Now I am wondering what could be an alternative function for this.
My whole intention was to change the default woocommerce template loading location to my plugin folder. Any help in resolving this?
Thanks in advance.
woocommerce_locate_template function is deprecated in favor of wc_locate_template: you can read the code here.
However, if you are looking for the filter, it's still woocommerce_locate_template and takes three arguments:
$template that is the result of the wp core function locate_template
$template_name that is only the filename
$template_path that is the woocommerce path for templates
So you can check if the $template_name is what you want to intercept and change the path if true, like this
function intercept_wc_template($template, $template_name, $template_path) {
if ($template_name == 'that_template.php') {
$template = 'the/path/of/your/plugin/template.php';
}
return $template;
}
add_filter('woocommerce_locate_template', 'intercept_wc_template', 20, 3);
I've not tested it, so sorry for any possible syntax error :)
Hope it helps!
-- Update 1: I forgot a semicolon :P --
-- Update 2: I made a mistake! --
I had to modify the above code in order to get it to correctly match the template file I needed, which in my case was "variable.php".
$template_name needs to be the full woocommerce root path, see below:
See the amended code below:
function intercept_wc_template($template, $template_name, $template_path) {
if ($template_name == 'single-product/add-to-cart/variable.php') {
$template = 'wp-content/themes/theme-name/woocommerce/single-product/add-to-cart/variable.php';
}
return $template;
}
add_filter('woocommerce_locate_template', 'intercept_wc_template', 20, 3);
If someone struggle with this as of 2021, worth mention that the filter 'woocommerce_locate_template' does not filter all templates inside woocommerce folder. Instead, You need to filter 2 other functions:
add_filter('wc_get_template', 'entex_wc_get_template', 20, 5);
add_filter('wc_get_template_part', 'entex_wc_get_template_part', 20, 3);
For example, The root woocommerce template content-single-product.php must be filtered with wc_get_template_part.
This is working for our plugin:
function template_base(){
return untrailingslashit(plugin_dir_path( __FILE__ )) .'/templates/';
}
function entex_wc_get_template($template, $template_name, $args, $template_path, $default_path){
/* custom theme templates has priority */
if(strpos($template, '/themes/') !== FALSE) return $template;
static $cache = array();
if(isset($cache[$template_name])) return $cache[$template_name];
$plugin_template = wc_locate_template($template_name, WC()->template_path(), $this->template_base());
if($plugin_template && file_exists($plugin_template)){
$template = $plugin_template;
$cache[$template_name] = $template;
}
return $template;
}
function entex_wc_get_template_part($template, $slug, $name){
/* custom theme templates has priority */
if(strpos($template, '/themes/') !== FALSE) return $template;
$template_name = '';
if($name){
$template_name = "{$slug}-{$name}.php";
} else if($slug){
$template_name = "{$slug}.php";
}
if(!$template_name) return $template;
static $cache = array();
if(isset($cache[$template_name])) return $cache[$template_name];
$plugin_template = template_base().$template_name;
if($plugin_template && file_exists($plugin_template)){
$template = $plugin_template;
$cache[$template_name] = $template;
}
return $template;
}
This is ripped out of the PHP class and pasted here so hopefully the code is not broken.
We recommend to register the templates for cleaner performance, if you only use a few, and add something like this early in the functions:
if(!in_array($template_name, array(
'archive-product.php',
'content-product.php',
'content-product-cat.php',
'content-single-product.php',
'content-widget-product.php',
'checkout/form-checkout.php',
'checkout/thankyou.php',
'loop/loop-start.php',
'loop/loop-end.php'
))) return $template;