I found this 2 year old solution that essentially counts the and removes the loading attribute where the count =1 and implimented via snippets plugin for Wordpress.
Unfortunately GTMetrix is still flagging "don't lazy load LCP" and when I inspect the image in my browsers I still see the attribute loading="lazy" for the 1st (and every) image on every post.
I suspected it was counting the site logo in the header as the 1st image but it too has loading="lazy" so it seems that the code isn't working at all.
Wordpress 6.0.1
Theme: Hello Elementor Child
Elementor + Elementor Pro
JetEngine for custom post type
Imagify for webP conversion & optimization
I'm not running any lazy-loading plugin and don't want to disable wordpress's global lazy load for all images, just the one above the fold in the LCP.
Snippet I'm running:
/* Remove lazy load first image */
function add_responsive_class($content)
{
if ( is_single() || is_page() || is_front_page() || is_home() )
{
$content = mb_convert_encoding($content, 'HTML-ENTITIES', "UTF-8");
$document = new DOMDocument();
libxml_use_internal_errors(true);
$document->loadHTML(utf8_decode($content));
$imgs = $document->getElementsByTagName('img');
$img = $imgs[0];
if ($imgs[0] == 1)
{ // Check first if it is the first image
$img->removeAttribute( 'loading' );
$html = $document->saveHTML();
return $html;
}
else
{
return $content;
}
}
else
{
return $content;
}
}
add_filter ('the_content', 'add_responsive_class');
If anyone can help me understand why this doesn't work on my site or has a different solution I'd appreciate the help.
Better if you give a higher priority to your filter. It could be that you try to remove something that still doesn't exist.
Elementor is responsible for the output of the image, and it may filter the content after your filter and add the loading parameter after your filter.
As a side note, you can't know if all the first images are always visible. Imagine for example an accordion, or something similar. I don't say that your script is not useful, but that it doesn't always guarantee the best results. Be sure you don't have hidden images. This may also be the cause of the failure of your script. Maybe you are removing the loading parameter to the first hidden images.
In the case of a hidden image, it would be better if they are lazy-loaded.
But if in your specific case, you are sure, then you should not have issues. In that case, check the priority of the filter.
You can also give the possibility in the Elementor editor to remove the lazy load. You can use this code:
add_action( 'elementor/element/image/section_image/before_section_end', function( $element, $args ) {
$element->start_injection( [
'at' => 'after',
'of' => 'link',
] );
$element->add_control(
'my_image_lazy_loading',
[
'label' => __( 'Lazy Loading','lazy-load-control-for-elementor' ),
'type' => \Elementor\Controls_Manager::SELECT,
'default' => 'lazy',
'options' => [
'lazy' => __( 'Lazy load','lazy-load-control-for-elementor' ),
'no_lazy' => __( 'Do not lazy load','lazy-load-control-for-elementor' ),
],
]
);
$element->end_injection();
}, 10, 2 );
add_action( 'elementor/widget/render_content', function( $content, $widget ){
if( $widget->get_name() === 'image' ){
$settings = $widget->get_settings();
if( isset( $settings['my_image_lazy_loading'] ) && 'no_lazy' === sanitize_text_field( $settings['my_image_lazy_loading'] ) ){
$content = str_replace( ' loading="lazy"','',$content );
}
}
return $content;
}, 10, 2 );
Then the user can decide which images should not be lazy loaded.
Related
I am trying to apply styles to all images that are inserted into my wp_editor() textarea using PHP. I have tried the following but had no success:
<?php
$settings = array(
'style_formats' => array(
array(
'block' => 'img',
'styles' => array(
'width' => '100%'
)
)
)
);
echo wp_editor('', 'email-content', $settings);
?>
What is the correct syntax to do this?
I have used the following docs to try complete this task:
https://developer.wordpress.org/reference/functions/wp_editor/
https://www.tiny.cloud/docs/configure/content-formatting/
If you only want to make all images 100%, then it might be more appropriate to just do it in your CSS stylesheet.
If you need to customise the WP Editor (which uses the TinyMCE editor), there are a few ways to do it, depending on what you want. The description and the code in your question don't match so I've given both options below:
1. Add a "Custom Styles" dropdown to the editor toolbar
The code in your question is what you would use to add a custom styles dropdown, similar to the default styles (Paragraph, Heading 1 etc). You can do this using the following code to your functions.php.
This adds a dropdown called "Formats" with 2 options - one to add the style directly on the image and one that adds a custom class to the image (which is preferable because it gives you more flexibility):
1. Set up the custom styles in the TinyMCE Editor settings
function my_mce_insert_custom_styles( $settings) {
// Create your array of custom styles to add
$style_formats = array(
// 1. OPTION TO ADD STYLE DIRECTLY TO THE IMAGE
array(
'title' => '100% Width Image Style',
'selector' => 'img',
'styles' => array( 'width' => '100%' )
),
// 2. OPTION TO ADD A CLASS TO THE IMAGE
array(
'title' => 'Add My Class to Image',
'selector' => 'img',
'classes' => 'my_image_class',
)
);
// Add the array the 'style_formats' setting
$init_array['style_formats'] = json_encode( $style_formats );
return $init_array;
}
add_filter( 'tiny_mce_before_init', 'my_mce_insert_custom_styles' );
// 2. Add custom styles to the 2nd toolbar of your Wordpress editor
function my_mce_buttons_2($buttons) {
array_unshift($buttons, 'styleselect');
return $buttons;
}
add_filter('mce_buttons_2', 'my_mce_buttons_2');
Now will have an extra "Formats" drop down in the 2nd toolbar on the editor. When you select an image, you can choose either of the formats above to apply to the image.
2. Automatically add a style / class to the inserted image
Even though you were using the code above, your description sounds like you want to automatically apply styling.
You can do this by adding the the following to your functions.php. Again, I have given options for adding the style directly to the image, or adding a class - you can remove the option you don't need:
function my_custom_image_styling($html, $id, $caption, $title, $align, $url, $size, $alt) {
$doc = new DOMDocument();
$doc->loadHTML($html);
$imgs = $doc->getElementsByTagName('img');
foreach($imgs as $img){
// 1. ADD THE STYLE ATTRIBUTE DIRECTLY TO THE IMAGE
$styles = $img->getAttribute("style");
$img->setAttribute("style", $styles."width:100%;");
// OR 2. ADD A CLASS TO THE IMAGE
$classes = $img->getAttribute("class");
$img->setAttribute("class", $classes." my_image_class");
}
$html = $doc->saveHTML();
return $html;
}
add_filter('image_send_to_editor', 'my_custom_image_styling', 1, 8);
Now, depending on which lines you use, the style or class will automatically be added to the image when it is being inserted into the editor.
References
tiny_mce_before_init hook
image_send_to_editor hook
I'm unsure about your request but if you're trying to inject css into the admin panel this is the way:
<?php function theme_admin_css() {
echo '
<style media="screen">
/* ... Your custom css goes here ... */
</style>
'; }
add_action( 'admin_head', 'theme_admin_css' ); ?>
I've been searching for examples of this online and through the WP documentation on filters but I can't find a suitable hook, so apologies for posting a question without a good example of what I'm trying to do!
When you add a link to text or to a button in the editor, you can search for the page/post you want to link to. What you can't search for is a post type archive link.
I want to be able to type the name of a post type into the search box (pictured below), and include the post type archive link in the search results. In this example, I have a post type called members that I'd like to link to.
I find the need to do this a lot, and I always end up just typing /post-type-link into the box and leaving it at that, but I don't think this is an elegant solution and is clunky for users.
I have tried to write some code, but I don't believe I have the right hook:
function include_cpt_search( $query ) {
if ( is_admin() && is_single() ) {
$query->set( 'post_type', array( 'services' ) );
}
return $query;
}
add_filter( 'pre_get_posts', 'include_cpt_search' );
Has anyone done this before? Know of a filter or hook I could work with? Anything really!
The Link format in the RichText toolbar uses the Search REST API endpoint at /wp/v2/search, so although that endpoint doesn't provide a specialized hook for filtering the response, you can use rest_post_dispatch to add custom links to the search results returned via /wp/v2/search.
So in the examples below, I'm checking if the route is /wp/v2/search and if so, then we add the (custom) post type's archive link. Also note that, you should provide an array with the items mentioned here (the LinkControl component used by the Link format).
Basic Example
Includes only the (i.e. one) post type whereby its name matched exactly the search keyword.
add_filter( 'rest_post_dispatch', 'so_62472641', 10, 3 );
function so_62472641( $response, $server, $request ) {
// Don't modify the data if the REST API route is not /wp/v2/search
if ( 'post' !== $request->get_param( 'type' ) ||
'/wp/v2/search' !== $request->get_route() ) {
return $response;
}
// Let's see if there's a post type that matched the search keyword.
$search = $request->get_param( 'search' );
if ( ! $post_type = get_post_type_object( $search ) ) {
return $response;
}
// Now add the post type archive URL, if any, to the response data.
if ( $url = get_post_type_archive_link( $search ) ) {
$data = (array) $response->get_data();
$data[] = [
'id' => 'post_type-' . $search,
'type' => 'Post Type Archive',
'title' => $post_type->label,
'url' => $url,
];
$response->set_data( $data );
}
return $response;
}
Extended Example
Includes all post types whereby the name/label matched the search keyword.
add_filter( 'rest_post_dispatch', 'so_62472641', 10, 3 );
function so_62472641( $response, $server, $request ) {
// Don't modify the data if the REST API route is not /wp/v2/search
if ( 'post' !== $request->get_param( 'type' ) ||
'/wp/v2/search' !== $request->get_route() ) {
return $response;
}
$search = $request->get_param( 'search' );
$post_types = get_post_types( [], 'objects' );
$extra_data = [];
// Let's see if there's a post type that matched the search keyword.
foreach ( $post_types as $obj ) {
if ( $search === $obj->name ||
// look for the search keyword in the post type name/slug and labels (plural & singular)
false !== stripos( "{$obj->name} {$obj->label} {$obj->labels->singular_name}", $search )
) {
if ( $url = get_post_type_archive_link( $obj->name ) ) {
$extra_data[] = [
'id' => 'post_type-' . $obj->name,
'type' => 'Post Type Archive',
'title' => $obj->label,
'url' => $url,
];
}
}
}
// Now add the post type archive links, if any, to the response data.
if ( ! empty( $extra_data ) ) {
$response->set_data( array_merge( (array) $response->get_data(), $extra_data ) );
}
return $response;
}
Sample Output (for the second example above)
Note: The above is a screenshot of a real response, but I deliberately (via PHP) changed the domain name to example.com (i.e. the actual domain name is different).
And the examples were both tried & tested working on WordPress 5.5.1 (latest release as of writing). Also, you can exclude the default post post type, if you want to.
Additional Notes
It should be noted that the examples do not take into account the pagination, which means, if there were 10 post types that matched the search keyword, then they would always be included in the response (on page 1, 2, 3, etc.). So you might want to just use the first example because at least it always includes at most 1 post type only. However, with the second example, you can actually limit the $extra_data to, say, 5 items (per page - but it's up to you on how to distribute the items per page).
You can also use a custom search handler class, e.g. one that extends the default class (WP_REST_Post_Search_Handler) and use the wp_rest_search_handlers hook to add your class to the list. Here's a very basic example...
In your-class.php:
class My_WP_REST_Post_Search_Handler extends WP_REST_Post_Search_Handler {
// ... you'll need to actually write the code on your own..
}
return new My_WP_REST_Post_Search_Handler;
In the theme's functions.php file or somewhere in your plugin:
add_filter( 'wp_rest_search_handlers', 'my_wp_rest_search_handlers' );
function my_wp_rest_search_handlers( $search_handlers ) {
$search_handlers[] = include_once '/path/to/the/your-class.php';
return $search_handlers;
}
Is this possible in Wordpress? I am trying to use a pre-defined template for my contents. To do that, I use something like this:
add_filter( 'default_content', 'custom_editor_content' );
function custom_editor_content( $content ) {
$args = array(
'posts_per_page'=> 15,
'orderby' => array(
'ID' => 'DESC' ,
),
);
$query = new WP_Query( $args );
$query_contents=Array();
while ( $query->have_posts() ) {
$query->the_post();
array_push($query_contents,Array(
"id"=>get_the_ID(),
"title"=>get_the_title(),
"url"=>get_permalink(),
));
}
$content = '
'.get_the_title( $id ).'
';
return $content;
}
But I can't get the post title (the one I am creating at that moment), somehow. Does someone know how to do this? If I put the while statement into $content, it shows the whole query in the editor and that's not what I want of course.
All I want to do is to fetch the post title and show it in the content editor (after posting or before, that wouldn't matter)
Could someone help me out?
I think that at the time of execution of this script (which is before the page loads) the post you are "creating" doesn't exists yet and therefore you cannot fetch its title.
You can try following, as the default_content supports second argument, which is the edited post:
add_filter( 'default_content', 'custom_editor_content' );
function custom_editor_content( $content, $post ) {
...
$content = '
'.$post->post_title.'
';
return $content;
}
However I think you will be facing the same issue as mentioned at the beginning of my answer. If you want to add title to content for new post, you will probably need a javascript which will copy the title into content as you write it (only if the content is still empty).
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.
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.