I want to speed up the loading of my wordpress website. I write a simple plugin that will add the defer attribute to some scripts that are used by the custom theme I've installed. I'm facing the issue that the site is locked to the preloader screen and no error is present in the chrome dev console nor xdebug error are showed. Maybe I'm doing something wrong, I don't know, is possible that the main javascript file that is responsable to load the theme are not loaded also if isn't present in the array of the scripts that are processed to add the defer attribute?
All the scripts are dependencies of the theme and are using jQuery that is not part of the list.
Any help will be appreciated.
class WP_scriptDefer {
private $scripts = [
'bootstrap.min.js',
'lazyload.min.js',
'viewportchecker.min.js',
'universal-parallax.min.js',
];
public function __construct()
{
$this->init();
}
public function init()
{
add_filter( 'script_loader_tag', [$this, 'deferScripts'], 10 );
}
public function deferScripts()
{
foreach( $this->scripts as $script ){
if( true == strpos($tag, $script) ){
return str_replace('src', 'defer="defer" src', $tag);
}
}
}
}
new WP_scriptDefer;
I edit your class, check it please:
class WP_scriptDefer
{
private $scripts = [
'bootstrap.min.js',
'lazyload.min.js',
'viewportchecker.min.js',
'universal-parallax.min.js',
];
public function __construct()
{
$this->init();
}
public function init()
{
add_filter('script_loader_tag', [ $this, 'deferScripts'], 10, 3);
}
public function deferScripts( $tag, $handle, $src )
{
foreach( $this->scripts as $script ){
if( true === strpos($tag, $script) ){
return str_replace('src', 'defer="defer" src', $tag);
}
}
return $tag;
}
}
new WP_scriptDefer;
After a day and also thanks to the suggestion of Dmitry I've found the correct way to let the plugin work. The array scripts needs to contain the names assigned inside the wp_enqueue_script() of each script and not the file name. This isn't very clear over the web because usually this filter is applied directly inside the function.php of a theme.
Here is the full working code:
<?php
class WP_deferScripts {
private $defer_scripts = [
'bootstrap',
'lazyload',
'swiper',
];
public function __construct()
{
add_filter( 'script_loader_tag', [$this, 'deferScripts'], 10, 2);
}
public function deferScripts( string $tag, string $handle ) : string
{
#var_dump($handle, $tag);
foreach( $this->defet_scripts as $script ){
if( $script === $handle ){
return str_replace('src', 'defer="defer" src', $tag);
}
}
return $tag;
}
}
?>
Related
I am using the following class to have a directory created with dynamic value - based on a woo custom checkout field. Works perfect on page refresh and directory is created like expected.
just need this to only trigger/instantiate on the WooCommerce actions
woocommerce_order_status_completed
or
woocommerce_order_status_changed
or
woocommerce_thankyou_page
how can this be done so that it does not always run every time a page is loaded to decrease the load and have better efficiency in general.
here is the complete class
//add_action( 'plugins_loaded', array( 'pos__URL', 'init' )); //uncomment to trigger on page refresh
class pos__URL {
public static function init() {
$POS__sys_URL = __CLASS__;
new $POS__sys_URL;
}
public function __construct()
{
add_action('init', array($this, 'pos__URL_Field'));
}
public function pos__URL_Field()
{
//--------to access the value----start-----
$orders = wc_get_orders(array(
'customer_id' => get_current_user_id(),
'return' => 'ids',
));
//add the id of the custom meta field that lies in the order
$meta_data = array();
foreach ($orders as $order_id) {
$meta_data[$order_id] = get_post_meta($order_id, '_engx_text_field_id', true);
}
//--------to access the value----end-----
if( isset($meta_data[$order_id]) ) { //is the field set
$curdir = getcwd(); //delcare variables
if (!file_exists($meta_data[$order_id])) {
if( mkdir( $curdir . "/" . $meta_data[$order_id], 0777) ) {
//below section for for testing purposes to see if the command ran - and yes shows correctly and creates directory as expected IF the POS url is set - (triggers at the moment on page refresh)
echo "directory created"; //comment out when done testing
}else{
echo "directory NOT created"; //comment out when done testing
}
}
}else{
if( empty($meta_data[$order_id]) ) {
//do nothing
}
}
}
} //end function
I have tried the following to set the action on the inside of class but I am not doing it right and it didn't work
class pos__URL
{
public function init()
{
add_action( 'woocommerce_order_status_changed', array('pos__URL') );
}
public function __construct()
{
add_action('init', array($this, 'pos__URL_Field'));
}
public function pos__URL_Field()
{
//--------to access the value----start-----
$orders = wc_get_orders(array(
'customer_id' => get_current_user_id(),
'return' => 'ids',
));
//add the id of the custom meta field that lies in the order
$meta_data = array();
foreach ($orders as $order_id) {
$meta_data[$order_id] = get_post_meta($order_id, '_engx_text_field_id', true);
}
//--------to access the value----end-----
if( isset($meta_data[$order_id]) ) { //is the field set
$curdir = getcwd(); //delcare variables
if (!file_exists($meta_data[$order_id])) {
if( mkdir( $curdir . "/" . $meta_data[$order_id], 0777) ) {
//below section for for testing purposes to see if the command ran - and yes shows correctly and creates directory as expected IF the POS url is set - triggers at momment on page refresh
echo "directory created"; //comment out when done testing
}else{
echo "directory NOT created"; //comment out when done testing
}
}
}else{
if( empty($meta_data[$order_id]) ) {
//do nothing
}
}
}
}
You should follow the same pattern you use for the plugins_loaded but this time replace it with whatever action you want to trigger the callback for. eg:
add_action( 'woocommerce_order_status_completed', array( 'pos__URL', 'init' ));
add_action( 'woocommerce_order_status_changed', array( 'pos__URL', 'init' ));
add_action( 'woocommerce_thankyou_page', array( 'pos__URL', 'init' ));
The init function of the pos_URL class will trigger when any of the above actions occur.
I've used this plugin for adding specific templates for page.
class PageTemplater {
protected $plugin_slug;
private static $instance;
protected $templates;
public static function get_instance() {
if( null == self::$instance ) {
self::$instance = new PageTemplater();
}
return self::$instance;
}
private function __construct() {
$this->templates = array();
add_filter('page_attributes_dropdown_pages_args', array($this, 'register_project_templates'));
// add_filter('wp_insert_post_data', array($this, 'register_project_templates'));
add_filter('template_include', array($this, 'view_project_template'));
$this->templates = array(
'page-json.php' => 'JSON list',
);
}
public function register_project_templates( $atts ) {
// Create the key used for the themes cache
$cache_key = 'page_templates-' . md5( get_theme_root_uri() . '/' . 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)])) {
}
$file = plugin_dir_path(__FILE__) . get_post_meta($post->ID, '_wp_page_template', true);
// Just to be safe, we check if the file exists first
if (file_exists($file)) {
return $file;
} else {
echo $file;
}
return $template;
}
}
add_action( 'plugins_loaded', array( 'PageTemplater', 'get_instance' ) );
But when I've have updated a WordPress to 4.7 page template options had stopped to show. Maybe I use some deprecated functions?
Please help.
Fixed code:
// Add a filter to the attributes metabox to inject template into the cache.
if ( version_compare( floatval( get_bloginfo( 'version' ) ), '4.7', '<' ) ) {
// 4.6 and older
add_filter(
'page_attributes_dropdown_pages_args',
array( $this, 'register_project_templates' )
);
} else {
// Add a filter to the wp 4.7 version attributes metabox
add_filter(
'theme_page_templates', array( $this, 'add_new_template' )
);
}
/**
* Adds our template to the page dropdown for v4.7+
*
*/
public function add_new_template( $posts_templates ) {
$posts_templates = array_merge( $posts_templates, $this->templates );
return $posts_templates;
}
source: http://www.wpexplorer.com/wordpress-page-templates-plugin/
I am extending an existing plugin. The author of said plugin provided an action hook in the main class of their plugin:
public static function instance() {
if ( ! isset( self::$instance ) && ! (self::$instance instanceof self) ) {
self::$instance = new self();
self::$instance->setup_constants();
self::$instance->actions = array();
self::$instance->filters = array();
add_action( 'plugins_loaded', array( self::$instance, 'load_textdomain' ) );
add_action( 'bp_loaded', array( self::$instance, 'bp_include' ) );
global $ap_classes;
$ap_classes = array();
self::$instance->includes();
self::$instance->ajax_hooks();
self::$instance->site_include();
self::$instance->anspress_forms = new AnsPress_Process_Form();
self::$instance->anspress_query_filter = new AnsPress_Query_Filter();
self::$instance->anspress_cpt = new AnsPress_PostTypes();
self::$instance->anspress_reputation = new AP_Reputation();
/*
* ACTION: anspress_loaded
* Hooks for extension to load their codes after AnsPress is leaded
*/
do_action( 'anspress_loaded' );
self::$instance->setup_hooks();
}
return self::$instance;
}
I am trying to use this hook to run my code, but it isn't working. I'm using has_action() to try and see if it is running of this action hook, but it's not.
if(has_action('anspress_loaded', 'find_do_for_anspress')){
echo 'fd is hooked';
} else {
echo 'NOT WORKING CORRECTLY';
}
The code above is at the bottom of the main plugin's php file, outside of any classes. Any idea how to troubleshoot this??
I tried to declare a new time interval for a WP_CRON.
When I do it in a PHP file it works.
When I do it in a PHP Class it doesn't.
Can someone see what I'm doing wrong ?
I'm using the plugin cron view to check if the declaration is working or not.
If I solve this problem I think it will also solve my problem to know why my cron job is not triggered in the class but works properly when not in a class.
=> File myplugin.php
function set_up_option_page() {
add_options_page( [...]);
}
add_action( 'admin_menu', 'set_up_option_page' );
function do_some_rock() {
$instance = My_Plugin_Class::instance();
if ( isset($_POST['action']) && 'do-magic' == $_POST['action'] ) {
$instance->do_stuff();
}else{
// Display the form.
<?
}
}
=> File My_Plugin_Class.php
<?php
if ( ! defined( 'ABSPATH' ) ) exit;
class My_Plugin_Class {
private static $_instance = null;
public function __construct () {
[...]
add_filter( 'cron_schedules', array($this,'cron_time_intervals'));
}
public function cron_time_intervals( $schedules ) {
echo "——— cron time intervals —— ";
$schedules['minutes_1'] = array(
'interval' => 10*60,
'display' => 'Once 10 minutes'
);
return $schedules;
}
public static function instance () {
if ( is_null( self::$_instance ) ) {
self::$_instance = new self();
}
return self::$_instance;
} // End instance ()
Best regards.
I am almost sure that do_some_rock() is not called every time - only when someone goes to that page. You can move add_filter( 'cron_schedules', array($this,'cron_time_intervals')); from your class constructor to main plugin file myplugin.php and do more or less something like this
add_action( 'admin_menu', 'set_up_option_page' );
$instance = My_Plugin_Class::instance();
add_filter( 'cron_schedules', array($instance ,'cron_time_intervals'));
One extra question. Does My_Plugin_Class constructor contain any code you would like to prevent being executed during each request?
I think the proper way to do this, is to have a specific class for my Cron.
This class is instanciated on each request this is why the code shouldn't be in a class with a static instance as I did before.
Also I think it's better to have the Cron outside the plugin class for logic and cleaner code purpose. Thanks to Lukas Pawlik for the help.
if (!defined('ABSPATH')) exit;
new My_Cron();
class My_Cron {
public function __construct() {
add_filter('cron_schedules', array($this, 'cron_time_intervals'));
add_action( 'wp', array($this, 'cron_scheduler'));
add_action( 'cast_my_spell', array( $this, 'auto_spell_cast' ) );
}
public function cron_time_intervals($schedules)
{
$schedules['minutes_10'] = array(
'interval' => 10 * 60,
'display' => 'Once 10 minutes'
);
return $schedules;
}
function cron_scheduler() {
if ( ! wp_next_scheduled( 'cast_my_spell' ) ) {
wp_schedule_event( time(), 'minutes_10', 'cast_my_spell');
}
}
function auto_spell_cast(){
My_Plugin_Class::instance()->launch_spell();
}
}
I am not Sure But Try this.
add_filter( 'cron_schedules', array($this,'cron_time_intervals'),1);
And Check cron_time_intervals() Function is Call or Not.
Anyone know of a way to remove the main editor from the page edit screen? And not just with css. I've added a few other meta boxes with the tinymce and they collide with the main one.
I have a class that removes other meta boxes from the edit screen, but I cant get rid of the main editor this way. I've tried to add 'divpostrich' and 'divpost' to the array in the class (but with no luck):
class removeMetas{
public function __construct(){
add_action('do_meta_boxes', array($this, 'removeMetaBoxes'), 10, 3);
}
public function removeMetaBoxes($type, $context, $post){
/**
* usages
* remove_meta_box($id, $page, $context)
* add_meta_box($id, $title, $callback, $page, $context = 'advanced', $priority = 'default')
*/
$boxes = array( 'slugdiv', 'postexcerpt', 'passworddiv', 'categorydiv',
'tagsdiv', 'trackbacksdiv', 'commentstatusdiv', 'commentsdiv',
'authordiv', 'postcustom');
foreach ($boxes as $box){
foreach (array('link', 'post', 'page') as $page){
foreach (array('normal', 'advanced', 'side') as $context){
remove_meta_box($box, $type, $context);
}
}
}
}
}
$removeMetas = new removeMetas();
I have also tried removing the 'divpostrich' with jquery. But cant figure out where to put the js for it to work. When I remove the 'postdivrich' in the browser with firebug - my remaining tinymce fields work perfect.
Any ideas?
There is built in WP support for this so you don't have to fiddle directly with the globals and ensure forwards compatibility if they ever change how features are handled. The WP Core code does pretty much the exact same logic as #user622018 answer however
function remove_editor() {
remove_post_type_support('page', 'editor');
}
add_action('admin_init', 'remove_editor');
What you are looking for is the global $_wp_post_type_features array.
Below is a quick example of how it can be used
function reset_editor()
{
global $_wp_post_type_features;
$post_type="page";
$feature = "editor";
if ( !isset($_wp_post_type_features[$post_type]) )
{
}
elseif ( isset($_wp_post_type_features[$post_type][$feature]) )
unset($_wp_post_type_features[$post_type][$feature]);
}
add_action("init","reset_editor");
Add the following code to your functions.
function remove_editor_init() {
if ( is_admin() ) {
$post_id = 0;
if(isset($_GET['post'])) $post_id = $_GET['post'];
$template_file = get_post_meta($post_id, '_wp_page_template', TRUE);
if ($template_file == 'page-home.php') {
remove_post_type_support('page', 'editor');
}
}
}
add_action( 'init', 'remove_editor_init' );
Couldn't you just disable the TinyMCE editor, leaving the HTML editor, as your meta boxes are colliding with it? :)
To disable the editor you will need to edit your wp-config.php file and add this line to the top:
define('DISALLOW_FILE_EDIT', true);