WordPress replace header.php from a plugin - wordpress

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)

Related

Over write plugin templates -- Child plugin concept

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.

How to detect the current template being displayed in WordPress?

I am developing a child theme of Twenty Eleven theme. There I need some customization in the blog page. I want to add a class in the place of id = "primary". How to discover which template is rendering the page?
Use the following code in your child theme's functions.php.
If you don't have it, create an empty one and use only the php opening tag (<?php).
This will print in the_content the current theme and template being displayed.
Seeing the main site page: child theme have an index.php
Seeing a single post: child theme don't have a single.php
Using a filter to add debugging to the content: check the comments
add_filter( 'the_content', 'so_13737534_print_template', 20 );
function so_13737534_print_template( $content )
{
// $template value equals to:
// /public_html/wp-content/themes/theme-name/template-name.php
global $template;
// Return normal content if seeing the backend
// or the user is not administrator
if( is_admin() || !current_user_can( 'delete_plugins' ) )
return $content;
// Split the value and build the output html
$split_path = explode( '/', $template );
$total = count( $split_path ) - 1;
$theme_and_template = $split_path[$total-1] . '/' . $split_path[$total];
$print = '<strong style="font-size:1em;background-color:#FFFDBC;padding:8px">Current = ' . $theme_and_template . '</strong>';
// Add our output before the_content
$content = $print . $content;
return $content;
}
The same can be printed as an Html comment in the <head>, using:
add_action( 'wp_head', 'so_13737534_print_template_in_head', 999 );
function so_13737534_print_template_in_head()
{
global $template;
echo '
<!--
TEMPLATE = ' . $template . '
-->
';
}

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

How do you make page templates load based on a page's entire url not just their slug?

How do you make page templates load based on a page's entire url not just their slug?
Page templates load either page-{slug}.php or page-{id}.php.
I really want it to load page-{parent-slug}_{slug}.php.
So the url /hello/world would look for the template page-hello_world.php.
This should be recursive so the longer the page url the longer template filename.
There is no template_redirect documentation in the API.
Any ideas?
This is what I came up with. It works great and added it to the functions.php file in the theme's folder:
function hierarchical_template() {
global $post;
$permalink_array =
array_filter(explode('/',str_replace(get_site_url(),'',get_permalink($post->ID))));
$template_redirect = false;
while ( count( $permalink_array ) ) {
$template = 'page-' . implode( '_', $permalink_array ) . '.php';
if(file_exists(TEMPLATEPATH . '/' . $template)){
include (TEMPLATEPATH . '/' . $template);
exit;
}
array_shift($permalink_array);
}
}
add_action('template_redirect', 'hierarchical_template');
In your page.php file, you can do something like this:
<?php
get_header();
$ancestors = get_ancestors(get_the_ID(), 'page');
$current_page = get_page(get_the_ID());
$top_page = $ancestors ? get_page(end($ancestors)) : false;
if($top_page && $file = locate_template('page-'.$top_page->post_name.'_'.$current_page->post_name.'.php'))
{
include $file;
}
else if($file = locate_template('page-'.$current_page->post_name.'.php'))
{
include $file;
}
else
{
//DEFAULT HTML TO DISPLAY
}
?>
This is untested, but the idea is for your page.php to search for and include a matching 'page-{parent-slug}_{slug}.php' file. If it can't find the matching file, then it will search for 'page-{slug}.php'. If that doesn't exist, then it will fall back on the default HTML in the else statement.
Hope this helps.

Change language only on theme

I want to keep the admin in english but the theme in another language. By adding language files to the theme directory nothing happens, the option to switch language wont come up. Is this possible without adding languages to wp-content?
I found a solution using the locale filter and load theme textdomain
The solution looks like this:
define('LOCALE', 'en');
add_action( 'after_theme_setup', 'site_setup' );
function site_setup() {
//Make the theme available for translation
load_theme_textdomain( 'mytheme', get_template_directory() . '/languages' );
$locale = get_locale(); //Will get what you defined earlier
$locale_file = get_template_directory() . "/languages/$locale.php";
if ( is_readable( $locale_file ) ) require_once( $locale_file );
}

Resources