How to overwrite a theme function within a custom plugin? - php

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

Related

Replace get_header template from plugin

Im creating a plugin what overrides templates which included in plugin folder. First of all Im trying to override header.php and footer.php files. Tried to create various solutions, but any of them doesnt work. (This is one of the plugin solutions)
Tried to remove get_header hook and add like new, but this doesnt help.
There is some of the latest solutions, what I tried
function header_override () {
// $template = locate_template('header.php');
// load_template(plugin_dir_path( __FILE__ ) . 'templates/header.php');
// print_r($template);
if ( $overridden_template = locate_template( 'header.php' ) ) {
load_template( $overridden_template );
}else{
load_template(plugin_dir_path( __FILE__ ) . 'templates/header.php');
}
}
add_action('template_include', 'header_override');
function new_header_output() {
remove_action( 'get_header', 'header_output', 20);
load_template(plugin_dir_path( __FILE__ ) . 'templates/header.php');
}
add_action('get_header', 'new_header_output');
function action_function_name_391( $name, $args ){
print_r("custom header");
}
add_action( 'get_header', 'action_function_name_391', 10, 2 );
Maybe someone has a similar problem to override theme templates
add_action('get_header', 'replace_header');
function replace_header(){
require PLUGIN_DIR.'includes/templates/header.php';
$templates = [];
$templates[] = 'header.php';
remove_all_actions( 'wp_head' );
ob_start();
locate_template( $templates, true );
ob_get_clean();
}

Disable Jetpack Carousel on specific pages in WordPress

I'm trying to disable Jetpack Carousel on a specific post ID using the following code in my functions.php
function djcoh_disable_carousel( $value ) {
wp_reset_query();
if ( is_page( 614 ) ) {
$value = true; // true to disable Carousel
}
// Return original or changed value
return $value;
}
add_filter( 'jp_carousel_maybe_disable', 'djcoh_disable_carousel' );
Here's the reference for jp_carousel_maybe_disable on GitHub
It seems that I'm unable to use is_page() within functions.php - though I thought I'd be able to by using wp_reset_query() as mentioned in the codex
What am I missing?!
The code you have is from a tutorial which is intended for running as a simple plugin. The reason your code doesn't currently work is because you are using it in the functions.php.
In it's current form your function is called as soon as it is read as part of the functions.php file. This is usually some time before the page is formed, and so you can't grab the page id with is_page{}.
Instead you should query the page and get it's id as follows:
function djcoh_disable_carousel( $value ) {
//get the global
global $post
echo "TEST PAGE ID: ".$post->ID;
//wp_reset_query();
if ( $post->ID == 614 ) {
$value = true; // true to disable Carousel
}
wp_reset_query();
// Return original or changed value
return $value;
}
add_filter( 'jp_carousel_maybe_disable', 'djcoh_disable_carousel' );
if that doesn't work try this:
function djcoh_disable_carousel( $value ) {
//get the global
global $wp_query;
$post_ID = $wp_query->post->ID;
echo "TEST PAGE ID: ". $post_ID;
//wp_reset_query();
if ( $post_ID == 614 ) {
$value = true; // true to disable Carousel
}
wp_reset_query();
// Return original or changed value
return $value;
}
add_filter( 'jp_carousel_maybe_disable', 'djcoh_disable_carousel' );
If none of the above work then your script is being called far too early in the process to grab the page id. So, the easiest option would be to simply place this script in it's own .php file and then upload that to the plugins root folder. Then activate it from the plugins menu.
The final option would be to create this as a filter or script and add the function call in the actual page template.
I managed this by using REQUEST_URI within a plugin file:
<?php
// No direct access
if ( ! defined( 'ABSPATH' ) ) exit;
if ( $_SERVER["REQUEST_URI"] === '/PAGE-SLUG/' ) {
add_filter( 'jp_carousel_maybe_disable', '__return_true' );
}
Change PAGE-SLUG for your slug and you are all set.
You can find info on REQUEST_URI in PHP's manuals:
'REQUEST_URI'
The URI which was given in order to access this page; for instance, '/index.html'.
It seems simplest to conditionally dequeue the Jetpack carousel script and stylesheet. The conditionals that you would typically use to control output would be available at the point in the request when the wp_footer action fires.
add_action( 'wp_footer', function() {
if ( is_page( $page ) ) {
wp_dequeue_script( 'jetpack-carousel' );
wp_dequeue_style( 'jetpack-carousel' );
}
}
Be certain to modify the is_page function to include the $page parameter or the condition will match all pages. Place the code in your theme's functions.php file and the Jetpack carousel should be disabled.

remove_action From PHP Class in WooCommerce Memberships

I have previously used a solution described here: remove_action From PHP Class for removing an action in the WooCommerce membership plugin.
However, the solution no longer works, as WooComemerce have changed the code behind the membership plugin.
So this is the new code.
Main woocommerce-memberships.php
public function includes() {
// load post types
require_once( $this->get_plugin_path() . '/includes/class-wc-memberships-post-types.php' );
// load user messages helper
require_once( $this->get_plugin_path() . '/includes/class-wc-memberships-user-messages.php' );
// load helper functions
require_once( $this->get_plugin_path() . '/includes/functions/wc-memberships-functions.php' );
// init general classes
$this->rules = $this->load_class( '/includes/class-wc-memberships-rules.php', 'WC_Memberships_Rules' );
$this->plans = $this->load_class( '/includes/class-wc-memberships-membership-plans.php', 'WC_Memberships_Membership_Plans' );
$this->emails = $this->load_class( '/includes/class-wc-memberships-emails.php', 'WC_Memberships_Emails' );
$this->user_memberships = $this->load_class( '/includes/class-wc-memberships-user-memberships.php', 'WC_Memberships_User_Memberships' );
$this->capabilities = $this->load_class( '/includes/class-wc-memberships-capabilities.php', 'WC_Memberships_Capabilities' );
$this->member_discounts = $this->load_class( '/includes/class-wc-memberships-member-discounts.php', 'WC_Memberships_Member_Discounts' );
$this->restrictions = $this->load_class( '/includes/class-wc-memberships-restrictions.php', 'WC_Memberships_Restrictions' );
Main instance
function wc_memberships() {
return WC_Memberships::instance();
}
From included class-wc-memberships-restrictions.php file
/**
* Returns the general content restrictions handler.
*
* #since 1.9.0
*
* #return null|\WC_Memberships_Posts_Restrictions
*/
public function get_posts_restrictions_instance() {
if ( ! $this->posts_restrictions instanceof WC_Memberships_Posts_Restrictions ) {
$this->posts_restrictions = wc_memberships()->load_class( '/includes/frontend/class-wc-memberships-posts-restrictions.php', 'WC_Memberships_Posts_Restrictions' );
}
return $this->posts_restrictions;
}
Then in class-wc-memberships-posts-restrictions.php
public function __construct() {
// decide whether attempting to access restricted content has to be redirected
add_action( 'wp', array( $this, 'handle_restriction_modes' ) );
// restrict the post by filtering the post object and replacing the content with a message and maybe excerpt
add_action( 'the_post', array( $this, 'restrict_post' ), 0 );
How do i remove the 'the_post' action?
So far i have the following in functions.php theme file:
function weteach_remove_actions(){
if(is_singular( 'post' )) {
if( function_exists( 'wc_memberships' ) ){
remove_action( 'the_post', array( wc_memberships()->restrictions, 'restrict_post' ));
}
}
return;
}
add_action( 'the_post', 'weteach_remove_actions', 1 );
Which gives me a "blank-page"-error.
Could you tell us what the error message was? My guess is that restrictions and post_restrictions aren't the same property and so you aren't finding the restrict_post method in the right class.
Edited now that I have looked at Memberships, this seems to work for me:
function so_41431558_remove_membership_post_restrictions(){
if( function_exists( 'wc_memberships' ) && version_compare( WC_Memberships::VERSION, '1.9.0', '>=' ) && is_singular( 'post' ) ){
remove_action( 'the_post', array( wc_memberships()->get_restrictions_instance()->get_posts_restrictions_instance(), 'restrict_post' ), 0 );
}
}
add_action( 'wp_head', 'so_41431558_remove_membership_post_restrictions', 1 );
Your add_action attempt is happening on priority 1, which is after the function has already run the Memberships method on priority 0, so even if the rest of your code was correct it would be too late.
So 1. I think we need to go to an earlier hook.
And 2. I think we need to use the new method for accessing the post restrictions class instance.
edited to add
and 3. I've switched to a direct version compare condition
and 4. I misread where the get_posts_restrictions_instance() method was... it is accessed via wc_memberships()->get_restrictions_instance()->get_posts_restrictions_instance()

WooCommerce - How can we change Shipping Address to N/A in order emails?

WooCommerce provides various hooks and action to change the predefined templates. But i need to hide the shipping address from order emails and display N/A. I have created a custom shipping method using plugin. Using that plugin i have to changed the address.
Any help will be appreciated.
Finally, i found a solution :
function myplugin_plugin_path() {
return untrailingslashit( plugin_dir_path( __FILE__ ) );
}
add_filter( 'woocommerce_locate_template', 'myplugin_woocommerce_locate_template', 10, 3 );
function myplugin_woocommerce_locate_template( $template, $template_name, $template_path ) {
global $woocommerce;
$_template = $template;
if ( ! $template_path ) $template_path = $woocommerce->template_url;
$plugin_path = myplugin_plugin_path() . '/woocommerce/';
$template = locate_template( array(
$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;
}
The normal WooCommerce template loader searches the following locations in order:
your theme / template path / template name
your theme / template name
your plugin / woo-commerce / template name
default path / template name
Reference Link : https://www.skyverge.com/blog/override-woocommerce-template-file-within-a-plugin/

WordPress - Ovveride plugin template in theme

I have plugin that create new post type. Also plugin set single template for it's single page.
add_filter( 'single_template', array( &$this, 'register_ipa_product_post_type_single_template' ) );
function register_ipa_product_post_type_single_template( $single_template ) {
global $post;
if ( $post->post_type == 'product' ) {
$single_template = IPA_PRODUCT_POST_TYPE_TEMPLATE_FOLDER . 'single-product.php';
}
return $single_template;
}
How i can override single-product.php in my theme.
I don't found any solutions for my question at this site.
just filter it a little later than the current function (ps if doing this within a class you need to reference it using array(&$this, 'function'). I left it out as i assume you are using the functions.php or function override....etc
add_filter( 'single_template', 'register_ipa_product_post_type_single_template', 100 );
function change_temp( $single_template ) {
global $post;
if ( $post->post_type == 'product' ) {
$single_template = 'path to your template file';
}
return $single_template;
};

Categories