Over write plugin templates -- Child plugin concept - wordpress

Is that possible for overwriting a plugin templates via making a folder in theme file and copy the file in that folder and altering the content [both folder and file name have the same name as arranged in plugin ].
Generally we altering the woocommerce page templates by following these system .Woothemes has implemented something similar for their woocommerce plugin. You copy files from /wp-content/plugins/woocommerce <-->to<--> /wp-content/themes/yourthemes/woocommerce and WP automatically uses the files in the theme folder rather than the plugin folder. This way users can make customizations to their plugins without losing them to a plugin update..Is that possible for all plugin ?
If no , what code that make woocommerce plugin to change the style based on the file inside our theme folders woocoomerce folder ?
or What about CHILD PLUGIN concept ?
is there any possible way ?

Woocommerce checks first does file /wp-content/themes/yourthemes/woocommerce exists and reqire it. If not it require general template from /wp-content/plugins/woocommerce
Simple possible solution in your plugin, you can use.
function loadTemplate( $template_name ){
$plugin_path = plugin_dir_path(__FILE__);
$original_template = $plugin_path . "templates/" . $template_name . ".php";
$theme_path = get_template_directory();
$override_template = $theme_path . "/myplugin/" . $template_name . ".php";
if(file_exists($override_template)){
include( $override_template );
}
else{
include( $original_template );
}
}
And now you can use as you want your loadTemplate() function like so:
function load_teplate_after_content( $template_name ) {
loadTemplate( 'example' );
// Now it will check first for
// wp-content/themes/yourtheme/myplugin/example.php
// and load, if not exists it will load original template from
// /wp-content/plugins/myplugin/templates/example.php
}
add_filter( 'the_content', 'load_teplate_after_content' );
Of course remember to prefix your functions or put it in a Class. This is just simple example.
Not tested. May be some errors.
EDIT:
Just to answer all questions. Here is precisely how woocommerce is doing this
/**
* Get template part (for templates like the shop-loop).
*
* #access public
* #param mixed $slug
* #param string $name (default: '')
* #return void
*/
function wc_get_template_part( $slug, $name = '' ) {
$template = '';
// Look in yourtheme/slug-name.php and yourtheme/woocommerce/slug-name.php
if ( $name && ! WC_TEMPLATE_DEBUG_MODE ) {
$template = locate_template( array( "{$slug}-{$name}.php", WC()->template_path() . "{$slug}-{$name}.php" ) );
}
// Get default slug-name.php
if ( ! $template && $name && file_exists( WC()->plugin_path() . "/templates/{$slug}-{$name}.php" ) ) {
$template = WC()->plugin_path() . "/templates/{$slug}-{$name}.php";
}
// If template file doesn't exist, look in yourtheme/slug.php and yourtheme/woocommerce/slug.php
if ( ! $template && ! WC_TEMPLATE_DEBUG_MODE ) {
$template = locate_template( array( "{$slug}.php", WC()->template_path() . "{$slug}.php" ) );
}
// Allow 3rd party plugin filter template file from their plugin
if ( ( ! $template && WC_TEMPLATE_DEBUG_MODE ) || $template ) {
$template = apply_filters( 'wc_get_template_part', $template, $slug, $name );
}
if ( $template ) {
load_template( $template, false );
}
}
EDIT2:
Is that possible for all plugin
It's possible for all plugins which have this feature implemented.
or What about CHILD PLUGIN concept ?
There is no general answer. If plugin provide an API to its functionallities, you could create such child plugin. But depending directly on current plugin code is bad idea. When your parent plugin(1) is gonna change, your plugin will break if you are using function that has been removed or edited.
But as I said, if plugin provide consistent API, and it's enough to write such functionaliity, then yes. But not for all plugins. At least without editing plugins itself.
(1) There is no such thing like child plugin or parent plugin oficially.

Related

woocommerce - include customer-completed-order email template in plugin

I try to override the woocommerce customer-completed-order.php template via a custom plugin I build.
The most handy is to include the custom email template in the plugin, so various customers dont need to copy the template to a child theme.
So far i have (based upon internet research):
function intercept_wc_template( $template, $template_name, $template_path ) {
if ( strpos($template_name,'customer-completed-order.php' ) ) {
$template = trailingslashit( plugin_dir_path( __FILE__ ) ) . 'template/woocommerce/customer-completed-order.php';
}
return $template;
}
add_filter('woocommerce_locate_template', 'intercept_wc_template', 20, 3);
I tried to change the priority, by changing the priority to 9 instead of 20. However, that doesnt seem to help either.
Any help would be appriciated,
Kind regards, Kees
You should try this one:
add_filter('woocommerce_locate_template', 'woo_customer_completed_order_template', 10, 4);
function woo_customer_completed_order_template($template, $template_name, $template_path)
{
if ('customer-completed-order.php' === basename($template)){
$template = trailingslashit(plugin_dir_path( __FILE__ )) . 'templates/woocommerce/customer-completed-order.php';
}
return $template;
}
Note: You can change/update if ('customer-completed-order.php' === basename($template)) , cundition accordingly.
If now working above function, you can echo $template, $template_name, $template_path and update if() condition accordingly.
it's working 100% on my side.

How to disable specific plugin on Wordpress backend / edit product page

I try to find a solution to disable specific plugins on Wordpress admin area. The problem is that for building WooCommerce shops I use Divi Builder, which on product page can sometimes use 50mb of resources when you try to edit it... if I disable some plugins over there then the load time would be much faster. I've found the following code on other topic:
add_filter( 'option_active_plugins', 'lg_disable_cart66_plugin' );
function lg_disable_cart66_plugin($plugins){
if(strpos($_SERVER['REQUEST_URI'], '/store/') === FALSE AND strpos($_SERVER['REQUEST_URI'], '/wp-admin/') === FALSE) {
$key = array_search( 'cart66/cart66.php' , $plugins );
if ( false !== $key ) unset( $plugins[$key] );
}
return $plugins;
}
But don't know how to modify it, so it only disables the chosen plugin on backend. In other words: I don't want the plugin to load when I edit WooCommerce product page.
Some help will be really appreciated.
As ‘option_active_plugins’ is fired before any plugin is loaded we need to drop our code down into mu-plugins directory. Please also remember that those plugins are run before the main query is initialized – that is why we don’t have any access to many functionalities, especially conditional tags which will always return false.
Please paste below code or download gist in mu-plugins folder in your wp-content folder. It would disable the plugin in post & page areas only.
<?php
/*
Plugin Name: Disable Plugin for URl
Plugin URI: https://www.glowlogix.com
Description: Disable plugins for for specific backend pages.
Author: Muhammad Usama M.
Version: 1.0.0
*/
add_filter( 'option_active_plugins', 'disable_plugins_per_page' );
function disable_plugins_per_page( $plugin_list ) {
// Quit immediately if not post edit area.
global $pagenow;
if (( $pagenow == 'post.php' || $pagenow == 'edit.php' )) {
$disable_plugins = array (
// Plugin Name
'hello.php',
'developer/developer.php'
);
$plugins_to_disable = array();
foreach ( $plugin_list as $plugin ) {
if ( true == in_array( $plugin, $disable_plugins ) ) {
//error_log( "Found $plugin in list of active plugins." );
$plugins_to_disable[] = $plugin;
}
}
// If there are plugins to disable then remove them from the list,
// otherwise return the original list.
if ( count( $plugins_to_disable ) ) {
$new_list = array_diff( $plugin_list, $plugins_to_disable );
return $new_list;
}
}
return $plugin_list;
}
You can replace $disable_plugins with the required list of plugins to disable.

WordPress replace header.php from a plugin

I have searched and cant find any answer.
How can I replace the themes header.php template from a custom plugin?
Everywhere I look it seems like it cant be done, and you can only change template parts from a theme/child theme.
But how does plugins like Elementor page builder do it then in their theme builder?
Thanks,
Daniel
I also needed to include a custom header.php from my plugin. Because you can register templates like page.php, post.php or archive.php from a plugin via the ${type}_template hook, I thought it shouldn't be that difficult to do the same for the header.php, but you can't load a custom header.php from directories other than parent or child theme's one.
When traversing down the get_header function you'll see the locate_template function being invoked to load the header template. But there is no way to hook into that function and to replace the path for the loaded header template:
function locate_template( $template_names, $load = false, $require_once = true, $args = array() ) {
$located = '';
foreach ( (array) $template_names as $template_name ) {
if ( ! $template_name ) {
continue;
}
if ( file_exists( STYLESHEETPATH . '/' . $template_name ) ) {
$located = STYLESHEETPATH . '/' . $template_name;
break;
} elseif ( file_exists( TEMPLATEPATH . '/' . $template_name ) ) {
$located = TEMPLATEPATH . '/' . $template_name;
break;
} elseif ( file_exists( ABSPATH . WPINC . '/theme-compat/' . $template_name ) ) {
$located = ABSPATH . WPINC . '/theme-compat/' . $template_name;
break;
}
}
if ( $load && '' !== $located ) {
load_template( $located, $require_once, $args );
}
return $located;
}
One solution to bypass this limitation would be to get rid of the get_header function within your plugin's templates and to include the plugin's header.php via require or require_once statement from within the plugin's templates. But than you will have to implement your own get_header hook and locate_template functionality to enable replacement from the parent or child theme. See this answer for more information on limitations when omitting the get_header function:
https://wordpress.stackexchange.com/a/5195/80177
I have experience using a similar page-builder to elementor called site origin.
To the best of my knowledge wordpress page-builders don't manipulate or replace the themes template files. Instead, a lot of the page-builder content is displayed in the front end with the_content() found in your template file. In addition, it appends a bunch of css and js scripts to the web page in order to handle the styling of the elements and interactivity.
As for your original question... If I understand correctly, there's no need for this plugin because the header.php file can be freely edited/replaced in the theme editor!
In the admin section, go to 'appearance' > 'editor'. Then under "theme files", select the template for header.php.
I used this solution
add_action('get_header', 'wpbet_replace_theme_header');
function wpbet_replace_theme_header(){
require plugin_dir_path( __FILE__ ) . 'templates/headers/header-padrao.php';
$templates = [];
$templates[] = 'header.php';
remove_all_actions( 'wp_head' );
ob_start();
locate_template( $templates, true );
ob_get_clean();
}
Elementor does not replace the header.php. It adopts whatever header.php the active theme has. It simply takes over the_content() part.
header.php is essential part & asset of a theme.
You may build a page template with a different header (not different header.php)

Is there any way to override a WordPress template with a plugin?

I'd like to make a landing page. If plugin detects some GET or POST requests it should override wordpress theme and show its own.
It would work somehow like that:
if (isset($_GET['action']) && $_GET['action'] == 'myPluginAction'){
/* do something to maintain action */
/* forbid template to display and show plugin's landing page*/
}
I'm familiar with WP Codex, but I don't remember if there is any function to do that. Of course, I googled it with no results.
Thanks for any ideas in advance.
You need the hook template_include. It doesn't seem documented in the Codex, but you can find more examples here in SO or in WordPress StackExchange
Plugin file
<?php
/**
* Plugin Name: Landing Page Custom Template
*/
add_filter( 'template_include', 'so_13997743_custom_template' );
function so_13997743_custom_template( $template )
{
if( isset( $_GET['mod']) && 'yes' == $_GET['mod'] )
$template = plugin_dir_path( __FILE__ ) . 'my-custom-page.php';
return $template;
}
Custom Template in Plugin folder
<?php
/**
* Custom Plugin Template
* File: my-custom-page.php
*
*/
echo get_bloginfo('name');
Result
Visiting any url of the site with ?mod=yes will render the plugin template file, e.g.: http://example.com/hello-world/?mod=yes.
you need to create a folder '/woocommerce/' inside your plugin directory, inside woocommerce you need to add a folder say, for email 'emails' and put the required template inside '/emails/' to override. just copy paste this code in the main.php of your plugin.
<?php
/**
* Plugin Name: Custom Plugin
*/
function myplugin_plugin_path() {
// gets the absolute path to this plugin directory
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/';
// Look within passed path within the theme - this is priority
$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 what we found
return $template;
}
?>
for reference template override using plugin

WP - Use file in plugin directory as custom Page Template?

Is it possible for a file in the plugin directory to be used as a custom Page Template?
Also, how do you make a plugin create a page?
I'm developing a plugin for a client based on a theme, he wants this plugin to make sales pages while being able to use his theme on the homepage. This is a product that I'm making for him to market so it needs to be automated all through the plugin.
Is this possible?
EDIT
I have the activation/deactivation hooks in my plugins main file, and it's not working. Here's the code:
$filename = __FILE__;
register_activation_hook($filename, 'superActivation');
register_deactivation_hook($filename, 'superDeactivation');
global $myFile; global $fh; global $stringData; global $filename;
$myFile = "testFile.txt";
$stringData = "Testing\n";
$fh = fopen($myFile, 'w') or die("can't open file");
function superActivation() {
global $myFile; global $fh; global $stringData; global $filename;
fwrite($fh, $stringData);
fclose($fh);
}
function superDeactivation() {
$myFile = "testFile.txt";
unlink($myFile);
}
You can do this with the template_redirect hook. Here's my code to manually replace the template for a custom post type with one in the theme if there isn't one in the template folder. Put this in your plugin file and then put a folder underneath your plugin called themefiles with your default theme files.
//Template fallback
add_action("template_redirect", 'my_theme_redirect');
function my_theme_redirect() {
global $wp;
$plugindir = dirname( __FILE__ );
//A Specific Custom Post Type
if ($wp->query_vars["post_type"] == 'product') {
$templatefilename = 'single-product.php';
if (file_exists(TEMPLATEPATH . '/' . $templatefilename)) {
$return_template = TEMPLATEPATH . '/' . $templatefilename;
} else {
$return_template = $plugindir . '/themefiles/' . $templatefilename;
}
do_theme_redirect($return_template);
//A Custom Taxonomy Page
} elseif ($wp->query_vars["taxonomy"] == 'product_categories') {
$templatefilename = 'taxonomy-product_categories.php';
if (file_exists(TEMPLATEPATH . '/' . $templatefilename)) {
$return_template = TEMPLATEPATH . '/' . $templatefilename;
} else {
$return_template = $plugindir . '/themefiles/' . $templatefilename;
}
do_theme_redirect($return_template);
//A Simple Page
} elseif ($wp->query_vars["pagename"] == 'somepagename') {
$templatefilename = 'page-somepagename.php';
if (file_exists(TEMPLATEPATH . '/' . $templatefilename)) {
$return_template = TEMPLATEPATH . '/' . $templatefilename;
} else {
$return_template = $plugindir . '/themefiles/' . $templatefilename;
}
do_theme_redirect($return_template);
}
}
function do_theme_redirect($url) {
global $post, $wp_query;
if (have_posts()) {
include($url);
die();
} else {
$wp_query->is_404 = true;
}
}
You CAN add page templates from a plugin very easily by manipulating the page cache.
To customise, simply edit the following code block within the __construct method;
$this->templates = array(
'goodtobebad-template.php' => 'It\'s Good to Be Bad',
);
This is designed for a plugin (the template files are searched for in the root directory of the plugin). This can be changed if desired - check out my full tutorial http://www.wpexplorer.com/wordpress-page-templates-plugin/ for greater detail on this solution. These files are also in exactly the same format as if they were to be included directly in a theme.
Full code;
class PageTemplater {
/**
* A Unique Identifier
*/
protected $plugin_slug;
/**
* A reference to an instance of this class.
*/
private static $instance;
/**
* The array of templates that this plugin tracks.
*/
protected $templates;
/**
* Returns an instance of this class.
*/
public static function get_instance() {
if( null == self::$instance ) {
self::$instance = new PageTemplater();
}
return self::$instance;
}
/**
* Initializes the plugin by setting filters and administration functions.
*/
private function __construct() {
$this->templates = array();
// Add a filter to the attributes metabox to inject template into the cache.
add_filter(
'page_attributes_dropdown_pages_args',
array( $this, 'register_project_templates' )
);
// Add a filter to the save post to inject out template into the page cache
add_filter(
'wp_insert_post_data',
array( $this, 'register_project_templates' )
);
// Add a filter to the template include to determine if the page has our
// template assigned and return it's path
add_filter(
'template_include',
array( $this, 'view_project_template')
);
// Add your templates to this array.
$this->templates = array(
'goodtobebad-template.php' => 'It\'s Good to Be Bad',
);
}
/**
* Adds our template to the pages cache in order to trick WordPress
* into thinking the template file exists where it doens't really exist.
*
*/
public function register_project_templates( $atts ) {
// Create the key used for the themes cache
$cache_key = 'page_templates-' . md5( get_theme_root() . '/' . get_stylesheet() );
// Retrieve the cache list.
// If it doesn't exist, or it's empty prepare an array
$templates = wp_get_theme()->get_page_templates();
if ( empty( $templates ) ) {
$templates = array();
}
// New cache, therefore remove the old one
wp_cache_delete( $cache_key , 'themes');
// Now add our template to the list of templates by merging our templates
// with the existing templates array from the cache.
$templates = array_merge( $templates, $this->templates );
// Add the modified cache to allow WordPress to pick it up for listing
// available templates
wp_cache_add( $cache_key, $templates, 'themes', 1800 );
return $atts;
}
/**
* Checks if the template is assigned to the page
*/
public function view_project_template( $template ) {
global $post;
if (!isset($this->templates[get_post_meta(
$post->ID, '_wp_page_template', true
)] ) ) {
return $template;
}
$file = plugin_dir_path(__FILE__). get_post_meta(
$post->ID, '_wp_page_template', true
);
// Just to be safe, we check if the file exist first
if( file_exists( $file ) ) {
return $file;
}
else { echo $file; }
return $template;
}
}
add_action( 'plugins_loaded', array( 'PageTemplater', 'get_instance' ) );
Check out my tutorial on this for more info.
http://www.wpexplorer.com/wordpress-page-templates-plugin/
I hope this helps you in what you want to do :)
the code david posted above almost works for me. but it seems to blanket over all posts and pages for me. This code below works great for adding a template to a single post type that is created by my main plugin file
function get_book_post_type_template($single_template) {
global $post;
if ($post->post_type == 'books') {
$single_template = dirname( __FILE__ ) . '/themefiles/single-books.php';
}
return $single_template;
}
add_filter( "single_template", "get_book_post_type_template" ) ;
but I'm having trouble getting it to work with a custom page templates that don't have a post_type or has a post_type = page for instance lets say the custom page is an auxiliary member login page to see my custom posts. in my case this file is called myaccount.php and i've included it in a subfolder within my plugin folder named themefiles.
//Add Page and Post Template Files to Current Theme
add_action("template_redirect", 'my_account_redirect');
function my_account_redirect() {
global $wp;
//Set myAccount Custom Page Template
if (isset($wp->query_vars['pagename'] ) == "myaccount") {
$templatefilename = 'myAccount.php';
if (file_exists(dirname( __FILE__ ) . '/themefiles/' . $templatefilename)) {
$return_template = dirname( __FILE__ ) . '/themefiles/' . $templatefilename;
}
do_account_redirect($return_template);
}
}
//Finishing setting templates
function do_account_redirect($url) {
global $post, $wp_query;
if (have_posts()) {
include($url);
die();
} else {
$wp_query->is_404 = true;
}
}
when i do the above code the myaccount template shows up on all pages except for home which i believe is because it is set to a blogroll instead of a static page
I cannot reply to user1912899, but their recommendation seems to be the most elegant solution. To use a custom template to override single-post.php, I've implemented the following code. This will work for any custom single-****.php file you add to your plugin. If it doesn't exist, it just falls back to what WordPress normally uses.
add_action('template_include', 'my_template_include');
function my_template_include($template) {
$file = dirname( __FILE__ ).'/theme/single-'.get_post_type().'.php';
if(file_exists($file)) {
$template = $file;
}
return $template;
}

Resources