Accessing post data before functions.php in Wordpress - php

I am updating my custom Wordpress theme, but as it is rather time consuming process I would like to launch one section at a time.
In other words there would be several versions of a theme for different parts of the website.
To keep things tidy I would like to keep them in separate folders, with all the assets such as js, images, css.
I managed to rewrite template hierarchy using conditional tags but got stuck on functions.php
I was trying to use custom filed (post meta) to switch between several functions.php files but unfortunately $post is not available there so I am unable to use get_post_meta().
I could only find a trace of a solution with custom db queries, $wpdb etc. but can't really figure it out.
Is there any fairly simple solution to hook-up into post data (wp_query) before functions.php is loaded? Or to somehow differently modify where the functions are loaded from?
To illustrate what I'm writing about I pasted my main index.php
<?
get_header();
/*
* Get theme version according to the custom field 'section'
*/
if( function_exists ( 'theme_version' ) ){
$theme = theme_version( #get_the_ID() );
} else {
$theme = 'v2';
}
include_once( 'theme/'. $theme .'/TEMPLATE_BUILDER.php' );
get_footer();
?>
Thanks!

Hopefully found a right answer (after couple of hours of research, trial and error)
I placed the below code in main (wp-native) functions.php
in attempt to keep the code and file structure tidy, works as a charm.
add_action('after_setup_theme', function(){
// parse_url tidies-up the uri
$section = get_post_meta( url_to_postid( parse_url( $_SERVER['REQUEST_URI'], PHP_URL_PATH ) ),'section', true);
if ( !empty( $section )){
// assign sections to the theme versions below
$theme_version = array(
'v3' => array(
'Sixth Form',
[ ... ]
),
'v3.1' => array(
'Contact',
[ ... ]
)
);
foreach($theme_version as $key => $value) { if(in_array( $section, $value )) $theme = $key; }
}
if( empty($theme) ) $theme = 'v2'; // default theme version
require_once( 'theme/' . $theme . '/functions.php' );
$GLOBALS['theme-ver'] = $theme; // set the global to use in index.php (and somewhere else perhaps)
});
The code is not complete yet – needs some conditional clauses as the functions.php is sometimes called multiple times within the loop (especially with custom wp_query)
Perhaps someone will find the above useful. By the way it's quite surprising that WP doesn't natively support some kind of 'theme version control' – I can see strong benefits of not having to upgrade the whole website at once for instance to e. g. resp.

Related

Loading Templates from a plugin in WordPress

I'm trying to make my first plugin and I got stuck. Here is the idea.
When my plugin is activated it will create one post type and two taxonomies for that post type (in my case the post type name is 'Ads').
Also, I created two template pages, one to display the listing of all ads post type articles and the other for a single page for the same post type.
Now my problem is how to tell WordPress to look for the templates from a plugin folder rather than the theme folder when the plugin is active.?
Is it something I can do in the plugin file or I have to create another file for this purpose?
This should do what you are looking for:
First, this hook to tell WordPress which is your single CPT template in your plugin
From this answer you get the single_template hook and how to load it.
Define a constant to replace "plugin_dir_path( FILE )" if you use it elsewhere in your plugin, like this:
define('YOUR_PLUGIN_DIR_PATH', trailingslashit(plugin_dir_path( __FILE__ )) );
https://wordpress.stackexchange.com/questions/17385/custom-post-type-templates-from-plugin-folder
function load_single_ad_template( $template ) {
global $post;
if ( 'ads' === $post->post_type && locate_template( ['single-ads.php'] ) !== $template ) {
/*
* This is an 'ads' post
* AND a 'single ad template' is not found on
* theme or child theme directories, so load it
* from our plugin directory from inside a /templates folder.
*/
return YOUR_PLUGIN_DIR_PATH . 'templates/single-ads.php';
}
return $template;
}
add_filter( 'single_template', 'load_single_ad_template', 10, 1 );
And then for the ads archive template, the 'archive_template' hook, like this:
function load_archive_ads_template( $archive_template ) {
global $post;
if ( is_post_type_archive ( 'ads' ) ) {
$archive_template = YOUR_PLUGIN_DIR_PATH . 'templates/archive-ads.php';
}
return $archive_template;
}
add_filter( 'archive_template', 'load_archive_ads_template', 10, 1 ) ;
Official documentation:
https://developer.wordpress.org/reference/hooks/type_template/
https://codex.wordpress.org/Plugin_API/Filter_Reference/archive_template
This is untested, but should work, however, let me know.

Woocommerce Multiple single product templates using single-product.php to redirect

I've been pulling my hair out with this all day, please forgive the short description, I just need to validate my sanity!!
As the title says, I'm trying to create two or three different single-product layouts within woocommerce. The minimum is trying to achieve would be to have multiple single-product folders each with their own name and configurations.
No matter which way I try to override the single-product.php and make this file use logic to check for the product_cat and give out templates accordingly, I either the page not loading or what I write is skipped over and the default is loaded.
So far I've been through the following methods multiple times, trying to piece together what may be outdated code or otherwise causing all the fuss:
WooCommerce - How to create multiple single product template based on category?
Woocommerce single product - template by categories
Creating a different template file for certain Product Categories - Wordpress/Woocommerce?
I was more hoping someone may know something about this that I'm obviously missing as there are many articles out there on what to try and most claim success but I'm unable to do so.
[Update] using template_include code from #helgatheviking
No success just yet but here's where I'm up to;
File structure
team-shops is the category I'm trying to get
/mytheme/woocommerce/single-product.php - no changes
/mytheme/woocommerce/content-single-product.php
/mytheme/woocommerce/single-product-team-shops.php - changed line 37 to<?php wc_get_template_part( 'content', 'single-product-team-shops' ); ?>
/mytheme/woocommerce/content-single-product-team-shops.php - added additional id to #product-id (line 39)
/mytheme/woocommerce/single-product-team-shops/ folder with all single product files to change.
As I said above this isn't working but hopefully with what I've provided the problem may be more obvious.
Thanks again for any help :)
[Think I've got it]
Ok so I think I've something that works, at least for now it seems to, still have some further testing to do but any thoughts more than welcome, this is what I've got so far along with a single-product-team-shops folder in my theme
add_filter( 'woocommerce_locate_template', 'so_25789472_locate_template', 10, 3 );
function so_25789472_locate_template( $template, $template_name, $template_path ){
$term_id = 2854;
$taxonomy_name = 'product_cat';
$term_children = get_term_children( $term_id, $taxonomy_name );
foreach ( $term_children as $child ) {
// on single posts with mock category and only for single-product/something.php templates
if( is_product() && has_term( $child, 'product_cat' ) && strpos( $template_name, 'single-product/') !== false ){
// replace single-product with single-product-mock in template name
$mock_template_name = str_replace("single-product/", "single-product-team-shops/", $template_name );
// look for templates in the single-product-mock/ folder
$mock_template = locate_template(
array(
trailingslashit( $template_path ) . $mock_template_name,
$mock_template_name
)
);
// if found, replace template with that in the single-product-mock/ folder
if ( $mock_template ) {
$template = $mock_template;
}
}}
return $template;
}
Use a single-product-custom.php template for any product in the "custom" category:
add_filter( 'template_include', 'so_43621049_template_include' );
function so_43621049_template_include( $template ) {
if ( is_singular('product') && (has_term( 'custom', 'product_cat')) ) {
$template = get_stylesheet_directory() . '/woocommerce/single-product-custom.php';
}
return $template;
}
NB: If you use the same action hooks in your single-product-custom.php template you will get the same look as the default single-product.php. You could 'rename' all the hooks and then could add existing functions (such as those for add to cart buttons, etc) to the new hooks in order to achieve a totally custom look.

Wordpress Fusion Core Plugin working on Custom Post Types

So I want to include fusion builder's post editor on some custom post types that I've created. There is a fix to this go to fusion-core > admin > class-pagebuilder.php and edit line 53.
var $allowed_post_types = array('page','post','avada_faq','avada_portfolio', 'add my custom types here');
But anytime there is an update this will be deleted and I'd like to not have to worry about this, or worry about it! So is there anyway i can create a plugin helper, or add something to my functions.php file that wont get replaced every time there is an update.
the instance is create line 22 of the file fusion-core.php
so to overide this, you can try something like this :
add_action ("plugins_loaded", function () {
// unregister habitual call
remove_action( 'plugins_loaded', array( 'Fusion_Core_PageBuilder', 'get_instance' ) );
// call of the instance
// you have to change the path of the fusion-core plugin
if( ! get_option( 'avada_disable_builder' ) ) {
if ( is_admin() ) {
require_once( path of the fusion-core plugin . 'admin/class-pagebuilder.php' );
$instance = Fusion_Core_PageBuilder::get_instance();
$instance->allowed_post_types[] = "custom post type";
}
}
}, 9); // priority 9 to be called before the line of fusion-core.php
For me, I found that there was no need to remove the action...and in fact, it did not work when I did so. Instead, I simply called the same action and changed the values. I also found that I only needed the "UI instance". Here's what worked for me. I've now added the page builder successfully to ten different post types on my site see below:
if ( is_admin() ) {
require_once('path to plugin directory/fusion-core/admin/class-pagebuilder.php' );
require_once('path to plugin directory/fusion-core/admin/page-builder/classes/class-ui.php' );
$ui = Fusion_Core_PageBuilder_UI::get_instance();
$ui->settings['allowed_post_types'][] = 'your_custom_post_type';
}

wordpress get all publish pages permalinks

I want to get the permalinks of all published pages and export it to an excel file.
What is the best solution?
Should I go to wp-admin panel and copy-paste the permalinks from the on Page editor?
Can I get the export data using a mysql query?
It is possible but very difficult to do via a SQL query, because WordPress allows you to change your Permalink structure - so the SQL query would need to regard all permalink options to build the correct permalink when the query is executed.
And I guess you are looking for a way that does not require you to copy paste links from the admin page ;-)
By far the best and easiest thing to do is write a small script that runs the export for you within WordPress and uses the functions get_pages and get_permalink:
// Get a list of all published pages from WordPress.
$pages = get_pages( 'post_status=publish' );
// Loop through all pages and fetch the permalink for each page.
foreach ( $pages as $page ) { //fixed this too
$permalink = get_permalink( $page->ID );
// Do something with the permalink now...
}
Note: This code will only run inside WordPress, i.e. as as Plugin or inside a Theme. Also how to do the excel export is beyond the scope of my answer...
Personally I'd create a WordPress plugin (there are many guides out there on how this works, like this one).
In the plugin you could simply check for a URL param, and if this param is present then export the data. Additionally I would check if the user that requests the export has admin permissions before exporting the data.
A bit like this:
/**
* The WordPress plugin header...
*/
$allowed = false;
$requested = false;
// Check if the current user has admin capabilies.
if ( current_user_can( 'manage_options' ) ) { $allowed = true; }
// Check if the user requested the export.
// i.e. by calling URL http://yoursite.com?export_permalinks=1
if ( 1 == $_GET['export_permalinks'] ) { $requested = true; }
if ( $requested && $allowed ) {
// 1. Get a list of all published pages from WordPress.
$pages = get_pages( 'post_status=publish' );
// 2. Build the export data.
$export = array();
foreach ( $pages as $page ) {
$permalink = get_permalink( $page->ID );
$export[] = array( $page->ID, $permalink );
}
// 3. Export the data (I just var_dump it as example).
var_dump( $export );
// We're done, so don't execute anything else.
exit;
}
Please note that this code should only explain my suggested workflow. It does not use best practices and I don't recommend to use it like this on a live site

wordpress: loading javascript only where shortcode appears

have an interesting conundrum. I need to load about 8 javascript files and the same number of styles for my plugin. These are only needed where ever my shortcode is ran.
I've tried to load them with print_styles and print_scripts but they aren't rendering properly, plus to do so breaks xhtml validation. So at the moment they load on every page and due to the number of files needed its not feasible to leave it like this.
On another project I wrote a function into my plugin's index.php file that would take the current page, search it for my shortcode and if found only then would it print the scripts, but this is an ugly hack.
Has anybody got any suggestions or solutions?
any help would be appreciated,
regards,
Daithi
to answer my own question... I had it write the first time. You have to search each page to check that your shortcode is being used. This has to be done when page data is loaded and before page is displayed. To me it is complete overkill on the system, but unfortunately it is the way it is. I got this information from:
get_shortcode_regex
and
old nabble
So first:
add_action('template_redirect','wp_my_shortcode_head');
then:
function wp_my_shortcode_head(){
global $posts;
$pattern = get_shortcode_regex();
preg_match('/'.$pattern.'/s', $posts[0]->post_content, $matches);
if (is_array($matches) && $matches[2] == 'YOURSHORTCODE') {
//shortcode is being used
}
}
replace 'YOURSHORTCODE' with the name of your shortcode and add your wp_enqueue_scripts into where it says //shortcode is being used.
I read a solution in here: http://scribu.net/wordpress/conditional-script-loading-revisited.html
Basically if using wordpress 3.3 you can enqueue your scripts in your short code function.
function my_shortcode($atts){
wp_enqueue_script( 'my-script', plugins_url( 'plugin_name/js/script.js' ), array('jquery'), NULL, true);
// if you add a css it will be added to the footer
//wp_enqueue_style( 'my-css', plugins_url( 'plugin_name/css/style.css' ) );
//the rest of shortcode functionality
}
Loading Scripts and Styles Dynamically Per Page Using a Shortcode
Advantages
Does not search through all the posts everytime the shortcode is called.
Able to add styles as well as scripts dynamically only when shortcode is on the page.
Does not use regexes since they tend to be slower than strstr() or strpos(). If you need to pickup args then you should use the shortcode regex mentioned above.
Reduces file calls
Explanation of Code
Finds the shortcodes on page using the save_post hook only when the post is not a revision and matches the specified post_type.
Saves the found post ids as an array using add_option() with autoload set to yes unless the entry is already present. Then it will use update_option().
Uses hook wp_enqueue_scripts to call our add_scripts_and_styles() function.
That function then calls get_option() to retrieve our array of page ids. If the current $page_id is in the $option_id_array then it adds the scripts and styles.
Please note: I converted the code from OOP Namespaced classes so I may have missed something. Let me know in the comments if I did.
Code Example: Finding Shortcode Occurences
function find_shortcode_occurences($shortcode, $post_type = 'page')
{
$found_ids = array();
$args = array(
'post_type' => $post_type,
'post_status' => 'publish',
'posts_per_page' => -1,
);
$query_result = new WP_Query($args);
foreach ($query_result->posts as $post) {
if (false !== strpos($post->post_content, $shortcode)) {
$found_ids[] = $post->ID;
}
}
return $found_ids;
}
function save_option_shortcode_post_id_array( $post_id )
{
if ( wp_is_post_revision( $post_id ) OR 'page' != get_post_type( $post_id )) {
return;
}
$option_name = 'yourprefix-yourshortcode';
$id_array = find_shortcode_occurences($option_name);
$autoload = 'yes';
if (false == add_option($option_name, $id_array, '', $autoload)) update_option($option_name, $id_array);
}
add_action('save_post', 'save_option_shortcode_id_array' );
Code Example: Shortcode Dynamically Include Scripts and Styles
function yourshortcode_add_scripts_and_styles() {
$page_id = get_the_ID();
$option_id_array = get_option('yourprefix-yourshortcode');
if (in_array($page_id, $option_id_array)) {
wp_enqueue_script( $handle, $src, $deps, $ver, $footer = true );
wp_enqueue_style( $handle, $src , $deps);
}
}
add_action('wp_enqueue_scripts', 'yourshortcode_add_scripts_and_styles');
Just read this tutorial over here: http://scribu.net/wordpress/optimal-script-loading.html
Seems to be the best way.
add_action('init', 'register_my_script');
add_action('wp_footer', 'print_my_script');
function register_my_script() {
wp_register_script('my-script', plugins_url('my-script.js', __FILE__), array('jquery'), '1.0', true);
}
function print_my_script() {
global $add_my_script;
if ( ! $add_my_script )
return;
wp_print_scripts('my-script');
}
In this case, the script will be enqueued only if the $add_my_script
global was set at some point during the rendering of the page.
add_shortcode('myshortcode', 'my_shortcode_handler');
function my_shortcode_handler($atts) {
global $add_my_script;
$add_my_script = true;
// actual shortcode handling here
}
So, the script will be added if [myshortcode ...] was found in any of
the posts on the current page.
Load Scripts and Styles if Post/Page has Short Code
The best solution is to load the files into the page header if, and only if, the current post or page has the short code inside its content. And that’s exactly what the following function does:
function flip_register_frontend_assets()
{
//register your scripts and styles here
wp_register_style('pp_font','plugin_styles.css', null, null, 'all');
global $post;
//check whether your content has shortcode
if(isset($post->post_content) && has_shortcode( $post->post_content, 'your-
shortcode')){
//Enqueue your scripts and styles here
wp_enqueue_style( 'pp_font');
}
}
Simply place this function inside of one of your plugin files and you’re good to go.
You will need to replace [your-shortcode] with the short code you want to search for, and you will also need to replace plugin_styles.css with your stylesheet name.
You can just use this code to check if the shortcode is implemented in page content or in sidebar widgets.
<?php
if ( shortcode_exists( 'gallery' ) ) {
// The [gallery] short code exists.
}
?>
I use WordPress Version 5.4 with OOP style of code i dont know if this affect why none of the above solutions didn't work for me so i come up with this solution:
public function enqueue_scripts() {
global $post;
//error_log( print_r( $post, true ) );
//error_log( print_r( $post->post_content, true ) );
//error_log( print_r( strpos($post->post_content, '[YOUR_SHORTCODE]'),true));
if ( is_a( $post, 'WP_Post' ) && strpos($post->post_content, '[YOUR_SHORTCODE]') )
{
wp_register_style('my-css', $_css_url);
wp_register_script('my-js', $_js_url);
}
}
Hope this help someone.
How many pages are these scripts going to be loaded on? Would it be feasible to maintain an array of pages, and only load the scripts/stylesheets when the current page is in the array?
Otherwise, without scanning the code there is no way to do this, as WP doesn't even know the shortcode exists until well into the page load.
BraedenP is right, I'm pretty sure there is no way to detect shortcode usage at the execution time of wp_enqueue_scripts / when the stylesheets load.
Is there any reason you must do this in 8 files? One would just be more efficient, then it may not be a problem to load it on every page.
You could consider a PHP stylesheet solution that only executes certain styles if needed. A css.php file may resemble:
<?php
header("content-type: text/css");
/* You can require the blog header to refer to WP variables and make queries */
//require '../../../wp-blog-header.php';
$css = '';
$css .= file_get_contents('style.css');
/* Consider using GET variables or querying a variable in the WP database to determine which stylesheets should be loaded. You could add an option to the backend that allows a stylesheet to be turned on or off. */
if($condition1 == TRUE) $css .= file_get_contents('condition1.css');
if($condition2 == TRUE) $css .= file_get_contents('condition2.css');
?>
Less scripts and less stylesheets means less http requests and a faster load time.

Categories