So I'm trying to figure out a way to automatically lazy load all images in a blogpost on a Wordpress site for a client.
As a developer, I'd rather not use a WP plugin (like BJ Lazy Load or A3 Lazy Load), preferring instead to use a JS plugin (JQuery Lazy by eisbhr) to give me more control.
So far, all the SO solutions I've found haven't worked.
Attempt #1
I used the the_content hook to change the src to data-src. The code I used is basic.
function add_data_src_to_content($content) {
return str_replace("src=", "data-src=", $content);
};
add_filter('the_content', 'add_data_src_to_content');
While it did change the src to data-src, the browser still loads the images below the fold (which defeats the purpose of lazy loading). I surmised that the_content hook actually also uses another hook to load images in. Which is how I got to my second attempt.
Attempt #2
For my second attempt, I tried using the image_send_to_editor hook. The code:
function add_data_src($html, $id, $caption, $title, $align, $url) {
return str_replace("<img src", '<img data-src', $html);
};
add_filter('image_send_to_editor', 'add_data_src', 10, 9);
This wouldn't work on posts that are already published. So I had to re-insert the images for this code snippet to work. I was also successful at converting src to data-src! The problem: yet again, WP still loads the image (when checking the Network tab in Dev Tools), defeating the purpose of lazy loading.
At this point, I'm stumped. How do I prevent WP from loading images below the fold without using a plugin?
I've figured out what was wrong: apparently, Wordpress automatically adds an srcset and sizes attribute to all images inserted (apparently, this has been in place since WP 4.4). I figured this out when I tried playing with the image_send_to_editor hook. The JS plugin I'm using requires me to make the srcset into data-srcset and sizes into data-sizes for the lazy load to work. Applying those to the changes on the the_content hook actually worked. Final code (which worked) is:
function add_data_src_to_content($content) {
$content = str_replace("<img src=", "<img data-src=", $content);
$content = str_replace("srcset=", "data-srcset=", $content);
$content = str_replace("sizes=", "data-sizes=", $content);
return $content;
};
add_filter('the_content', 'add_data_src_to_content');
I assume you are referring to images within content entered via post/page editors and not images in say sidebar widgets or the home page (these will obviously still load).
I added your Attempt#1 to my custom site plugin, and images added via post editor were load hobbled and did not display. However; images inserted by other means e.g. shortcodes continued to be loaded and displayed unless I gave your filter function "low priority".
Try making your Attempt #1 filter function run after "everything else". add_filter('the_content', 'add_data_src_to_content', 9999);
Remove your lazy load Javascript and then clear cache and browse one of your pages and view (HTML) source. If your filter is working or partially working you will see "data-src=" attributes in your HTML instead of "src="; if so then the problem may relate to your Javascript set-up and "early" non lazy loading.
It will add 'loading=”lazy”' attribute to all 'img loading="lazy"' and 'iframe loading="lazy" iframe' tags automatically when a new post or page is created.
It is implemented in the following way:
add_filter( 'save_post', 'add_lazy_load', 10, 3 );
function add_lazy_load($post_id, $post, $update)
{
if (wp_is_post_revision($post_id))
{
return;
}
if ( ! class_exists( 'DOMDocument', false ) )
return;
remove_action('save_post', 'add_lazy_load');
$post_status = get_post_status();
Read more: https://www.plerdy.com/blog/lazy-loading-setup-wordpress/
I think that the most viable solution for lazy loading is native lazy loading. In this case, you just have to add a loading attribute to your img tags. Then, the browser will be in charge of lazy loading.
Here are the supported values for the loading attribute:
auto: Default lazy-loading behavior of the browser, which is the same as not including the attribute
lazy: Defer loading of the resource until it reaches a calculated distance from the viewport.
eager: Load the resource immediately, regardless of where it's located on the page.
It is supported by Chrome, Edge, Opera and Firefox.
https://web.dev/browser-level-image-lazy-loading/
Related
I have a CPT custom post type of Books. The single template being used is 'single-books.php'. However, when I make changes to this file, they don't show up in the front-end. There is no browser or server caching.
I tested this by creating a new book post with the slug 'test'. Then, I duplicated the template and renamed it 'single-books-test.php'. As expected, the new book page started loading this template. However, when I made changes to 'single-books-test.php', the new changes won't show up.
Is there any way to clear Wordpress page template cache? Any help will be highly appreciated!
Not sure if this is your case but I’ve just discovered that the template I am using (Nanospace) itself utilizes a WordPress caching mechanism and the page is only re-rendered when I change the page using the WordPress editor.
The caching mechanism consists of two PHP functions: get_transient() and set_transient().
In the particular case of the Nanospace template, I found the get_transient() call in the file wp-content/themes/nanospace/includes/frontend/class-post.php:
$output = get_transient( $cache_key );
if ( ! $output ) {
and changed it to following:
$output = false;
if ( ! $output ) {
My changes are now applied as I expected.
Bit is a basic question here but can someone confirm that this statement be confirmed: WordPress Pages (certain templates created within) can pull different CSS and JS?
Or - does WordPress only permit universal CSS + JS to be pulled across the entire site?
Thanks for clearing this up.
Depends on what plugin and themes you use. The WordPress/PHP functions wp_enqueue_style() and wp_enqueue_script() can be used literally by everyone (core, themes, plugins, you) to request WordPress to load styles or JavaSctript. You can combine this with WordPress functions to check whether the current page is something you want to filter for (post type, post, front-page, category archive, template, etc.). Here is an example to load a custom style if on front page :
if (is_front_page()) {
wp_enqueue_style('custom-frontpage', 'my/path/to/frontpage.css');
}
You will have to hook this piece of code to the wp_enqueue_script action so that WordPress executes it at the appropriate time. Here is an example using an anonymous function:
add_action('wp_enqueue_scripts', function() {
if (is_front_page())
wp_enqueue_style('custom-frontpage', 'my/path/to/frontpage.css');
});
You can also register your code as a "normal" function and pass the functions name to add_action() instead.
Edit: Enabling and disabling plugins is a bit more difficult, since you can never know how they implement their features without examining the source code. Here are my thoughts on this:
The plugin likely uses the above method (wp_enqueue_styles, wp_enqueue_scripts) to register it's styles and scripts. The plugin, since it assumes to be needed on all pages and posts, does this on every page without the conditional checking described earlier.
You could do one of the following to stop the plugin from doing this:
Identify the place where the plugin loads the styles and scripts and add the if-statement to only do so if the post-ID matches your desired post-ID. This method is bad since your changes are lost every time the plugin is updated.
Write a "counter plugin" (you could just add it to your theme or find a plugin that allowes you to add PHP to your page) that "dequeues" the style and script added by the plugin with inversed conditional tag
The counter-plugin approach would look as follows:
function custom_unregister_plugin() {
if (not the desired blog post) {
wp_dequeue_style('my-plugin-stylesheet-handle');
wp_dequeue_script('my-plugin-script-handle');
}
}
Make sure this function is executed after the enqueuing-code of your plugin by giving it a low priority in the same hook (999 is just an example, test it yourself):
add_action('wp_enqueue_scripts', 'custom_unregister_plugin', 999);
With wp_enqueue_style() you can add stylesheet (https://developer.wordpress.org/reference/functions/wp_enqueue_style/)
You can use it after detecting which template is used
function enqueue_custom_stylesheet() {
if(get_page_template() == 'contact.php')
wp_enqueue_style( 'contact-style', get_template_directory_uri().'/contact.css' );
}
add_action( 'wp_enqueue_scripts', 'enqueue_custom_stylesheet' );
You can use wp_enqueue_style for your CSS, wp_enqueue_script for your JS, wp_localize_script to pass variables from PHP to JS.
You can call these with hooks like:
funtion enqueue_my_stuff()
{
// your enqueue function calls
}
add_action('wp_enqueue_scripts','enqueue_my_stuff'); //front end
add_action('admin_enqueue_scripts','enqueue_my_stuff'); //admin panel
add_action('login_enqueue_scripts','enqueue_my_stuff'); //login screen
I'm developing WP site. I want the content to display soundcould embedded player within the content.
By default it adds query argument visible-true. What I need is to set this to false. So I'm trying the oembed_fetch_url filter, but It's not event called.
I've searched google all over, there's no information when this filter is even called. I've tried this just to make sure it's working:
function soundcloud_url_change($provider, $url, $args) {
return "somedummyurl.com";
}
add_filter('oembed_fetch_url', 'soundcloud_url_change', 10, 3);
The url remained correct. So I have no idea how to manipulate the oembed url.
You'd probably want to hook into the filter:
oembed_result
I needed to modify the url of a youtube embed and ended up with this block:
function mod_oembed_youtube_url($html,$url,$args){
if(strpos($html, 'youtu.be') !== false || strpos($html, 'youtube.com') !== false){
$out = preg_replace("#src=(['\"])?([^'\">\s]*)#", "src=$1$2&rel=0", $html);
return $out;
}
return $html;
}
add_filter('oembed_result','mod_oembed_youtube_url',10,3);
This obviously could be more efficient and is only geared for YouTube but hopefully can lead you in the right direction. For reference, the oembed_result is in:
/wp-includes/class-oembed.php Line: 126
WordPress actually caches the result of the fetch, so if you're running into this, it could be it's short-circuiting before it gets to the filter because it finds the markup in the cache. Check out this for clearing the oembed cache and then see if your filter doesn't run.
That being said, YouTube strips out any query vars you send along, so you'll need to use the other answer listed here for YouTube embeds specifically.
In my plugin i have created a custom template that prints a requested sidebar. and for running the code of this template i assigned a custom page to it (by calling update_metadata) .
Is it a good idea for getting content of a specific sidebar into Ajax call ?
Now my problem is that WORDPRESS shows it in the dashboard and front page , and after searching i have not found any easy to understand solution for Hiding a page completely so only can be accessed by its id .
Can any one tell me how to do that ?
you are going about this the wrong way. You can create a function that can create anything that can be created on a wordpress page.
But if you really must you can create a page outside of the database, etc:
add_action('init', 'add_rewrite_rule');
function add_rewrite_rule(){
// add_rewrite_rule(REGEX url, location, priority (i.e. top is before other rewrite rules)
// I created a custom post type for this plugin called market -- replace post_type with whatever you want
//basically tell wordress to add a query var if sidebar is added to url.
add_rewrite_rule('^sidebar?','index.php?is_sidebar_page=1&post_type=market','top');
}
// register a query var
add_action('query_vars','market_set_query_var');
function market_set_query_var($vars) {
array_push($vars, 'is_sidebar_page');
return $vars;
}
// associate a template with your quer_var
add_filter('template_include', 'market_include_template', 1000, 1);
function market_include_template($template){
if(get_query_var('is_sidebar_page')){
$new_template = (theme or plugin path).'/pages/yourpage.php'; // change this path to your file
if(file_exists($new_template))
$template = $new_template;
}
return $template;
}
This will not be a page that will be in the admin section or in any query that relates to pages but someone could of course navigate to this page. But as i said above you would be better to create a function to create your sidebar. If you want a seperate file to handle the "view" you use require_once 'filename'; a file and keep your functions area free of html.
If you are creating functions in a wordpress plugin dont forget many functions may not be available until later in the load process. Use add_action() if you run into any undefined functions
edit:
you are loading wordpress before you get to the template so you have all the functions. (google wp load for more info) + get_header() / get_footer() will also load a few things like css, etc. I had a small typo in the code above, fixed that but basically what you are doing is telling wordpress if someone lands on www.example.com/sidebar to apply a query_var (rewrite rule). Wordpress will look up its saved vars (final function) and return the template assoc. The 2nd function just registers the var.
You also have wp_functions in any file you create and include in a plugin, etc hence why you can create a file that does exactly the same as this page.
I am writing a custom widget for my own WordPress theme.
From WordPress 3.5 there is a new Media Uploader instead of the old ThickBox.
My widget used to work fine on WordPress versions older than 3.5, but now the new media uploader prevent the old working behavior.
I added a check in the costructor for the presence of wp_enqueue_media function:
if( function_exists( 'wp_enqueue_media' ) ) {
wp_enqueue_media();
}
but when this part of cose is executed javascript throw an error in the console stopping Js engine:
Uncaught TypeError: Cannot read property 'id' of undefined load-scripts.php:69
I removed all the widget code and reduced it to bare bones... the error is caused by wp_enqueue_media() calls, but I cannot get my head around why and how to fix it.
I also read Wordpress 3.5 custom media upload for your theme options, but there is no mention to this issue
Can anyone point me in the right direction? Is there any documentation available for the the WordPress 3.5 Media Uploader?
It's too late for you now, but might be helpful for other people. I managed to make it work using
add_action( 'admin_enqueue_scripts', 'wp_enqueue_media' );
Hope it helps!
The problem you are experiencing is because you probably put your custom jquery in the header and you didn't registered wordpress jquery. If multiple jquery are defined you will get that error.
My sugestion is you should either remove your jquery script or remove the one from wordpress
function remove_jquery() {
wp_deregister_script('jquery');
//wp_register_script('jquery', ("//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"), false);
}
if(!is_admin()){add_action('init', 'remove_jquery');}
I suggest you use the jquery wordpress provides you, if not, the proper way to enqueue it is to deregister the default one an register your jquery. Just remove the comments from the remove_jquery function.
Also, the above code should go in functions.php
Cheers.
From codex [1], the function wp_enqueue_media( $args ) should be called from 'admin_equeue_scripts' action hook. or later.
Example:
function enqueue_media() {
if( function_exists( 'wp_enqueue_media' ) ) {
wp_enqueue_media();
}
}
add_action('admin_enqueue_scripts', 'enqueue_media');
Hope it helped.
[1]. https://codex.wordpress.org/Function_Reference/wp_enqueue_media
To debug, you need to get the non-minified versions of the js sent to the browser. See the docs:
SCRIPT_DEBUG
SCRIPT_DEBUG is a related constant that will force WordPress to use the "dev" versions of core CSS and Javascript files rather than the minified versions that are normally loaded. This is useful when you are testing modifications to any built-in .js or .css files. Default is false.
define('SCRIPT_DEBUG', true);