Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save oneblackcrayon/ec6b006d1b16c589001bd9374c8e71ab to your computer and use it in GitHub Desktop.
Save oneblackcrayon/ec6b006d1b16c589001bd9374c8e71ab to your computer and use it in GitHub Desktop.
WP - Optimizations and Cleanup

** WP - Optimizations and Cleanup **

Here you can find a a list of WP optimization and cleanup functions and methodology.

  1. .htaccess
  • Force https to your site.
  • Enable Browser Cache for your static files. This will fix the "Leverage Browser Caching" in the google pagespeed results.
  • Enable file compreassion for faster page load.
  1. wp-config.php
  • Example of how to enable wp-debug and log the errors, during development.
  • Limit posts revisions, in order to have smaller DB.
  • Change the update method. /!\ This is usefull usually when bringing a site from server to localhost.
  1. functions.php
  • Organize your functions.php by including your custom files for better readability. You can seperate you custom files, by responsibility, by back/frond end, by what they modify (e.g. woocommerce mods).
  1. cds-wp-admin-tweaks-n-extras.php
  • Example custom function to add an extra column to the admin area of the posts list.
  1. cds-optimizations-n-tweaks.php

-- Example custom functions for optimizing WP and removing tags for security

  • Clean wp_head. Remove unnecessary links, scripts and the_generator (the wp one) from .
  • Remove WPML generator.
  • Remove Slider Revolution generator.
  • Remove Visual Composer / WPBakery Page Builder generator.
  • Remove comment-reply.min.js completely.
  • Remove jQuery Migrate Script from header and Load jQuery from Google API.
  • Remove Yoast SEO comments.
  • Remove Query Strings (the version) from script and style files, some files won't be cached if there is a query string in them. /!\ may produce errors! check carefully!
  • remove wp version param from any enqueued scripts (using wp_enqueue_script()) or styles (using wp_enqueue_style()).
# ##################################
# SECURITY
# ##################################
# Disable the server signature
ServerSignature Off
# Add default charset
AddDefaultCharset UTF-8
# Disable directory browsing
Options All -Indexes
# Redirect all trafic to https
<IfModule mod_rewrite.c>
RewriteEngine On
# Redirect http to https
# RewriteEngine On
# RewriteCond %{HTTPS} !=on
# RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301,NE]
# Redirect www to non-www and http to https
RewriteCond %{HTTPS} off [OR]
RewriteCond %{HTTP_HOST} ^www\. [NC]
RewriteCond %{HTTP_HOST} ^(?:www\.)?(.+)$ [NC]
RewriteRule ^ https://%1%{REQUEST_URI} [L,NE,R=301]
# Redirect non-www to www and http to https
# RewriteCond %{HTTP_HOST} !^www\. [NC,OR]
# RewriteCond %{HTTPS} off
# RewriteCond %{HTTP_HOST} ^(?:www\.)?(.+)$ [NC]
# RewriteRule ^ https://www.%1%{REQUEST_URI} [R=301,L,NE]
</IfModule>
# Protect System Files, Disable PHP in Uploads, Filter Request Methods, by iThemes Security
<IfModule mod_rewrite.c>
RewriteEngine On
# Protect System Files
RewriteRule ^wp-admin/install\.php$ - [F]
RewriteRule ^wp-admin/includes/ - [F]
RewriteRule !^wp-includes/ - [S=3]
RewriteRule ^wp-includes/[^/]+\.php$ - [F]
RewriteRule ^wp-includes/js/tinymce/langs/.+\.php - [F]
RewriteRule ^wp-includes/theme-compat/ - [F]
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule (^|.*/)\.(git|svn)/.* - [F]
# Disable PHP in Uploads
RewriteRule ^wp\-content/uploads/.*\.(?:php[1-7]?|pht|phtml?|phps)\.?$ - [NC,F]
# Filter Request Methods
RewriteCond %{REQUEST_METHOD} ^(TRACE|TRACK) [NC]
RewriteRule ^.* - [F]
</IfModule>
# Secure Important Files
<FilesMatch "^.*(error_log|wp-config\.php|\.ini|\.[hH][tT][aApP].*)$">
Order deny,allow
Deny from all
</FilesMatch>
## Prevent access to specific types of files
#<FilesMatch "\.(htaccess|htpasswd|ini|phps|fla|psd|log|sh)$">
# Order Allow,Deny
# Deny from all
#</FilesMatch>
# Protect System Files
<files .htaccess>
Order allow,deny
Deny from all
</files>
<files readme.html>
Order allow,deny
Deny from all
</files>
<files readme.txt>
Order allow,deny
Deny from all
</files>
<files wp-config.php>
Order allow,deny
Deny from all
</files>
# Block WordPress xmlrpc.php requests
<Files xmlrpc.php>
order deny,allow
deny from all
</Files>
# Security Headers
# May cause errors, usually when loading external scripts, iframes etc..
<IfModule mod_headers.c>
# Use HTTP Strict Transport Security to force client to use secure connections only.
# max-age=15768000 is 6 Months
Header always set Strict-Transport-Security "max-age=15768000; includeSubDomains; preload"
# Enforce enable the cross-site scripting (XSS) filter built into modern web browsers.
Header set X-XSS-Protection "1; mode=block"
# Provide clickjacking protection by not allowing iframes to load our website.
header always set x-frame-options "SAMEORIGIN"
# Prevent IE and Chrome from sniffing a response away from the declared content-type. This helps reduce the danger of drive-by downloads and helps treat the content the right way.
Header always set x-content-type-options "nosniff"
# Activate CORS
<FilesMatch "\.(ttf|ttc|otf|eot|woff|woff2|font.css|css|js|gif|png|jpe?g|svg|svgz|ico|webp)$">
Header set Access-Control-Allow-Origin "*"
</FilesMatch>
# Set Content security policy as to:
# default-src - Is the default policy for loading content such as JS, Images, CSS, Fonts etc..
# https: - Allows loading resources only over HTTPS on any domain.
# data: - Allows loading resources via the data scheme (eg Base64 encoded images).
# 'unsafe-inline' - allow inline css,js
# 'unsafe-eval' - Allows unsafe dynamic code evaluation such as JavaScript eval()
# More info: https://content-security-policy.com/
Header always set Content-Security-Policy "default-src https: data: 'unsafe-inline' 'unsafe-eval'"
# Set the Referrer-Policy
# no-referrer-when-downgrade - The origin, path, and querystring of the URL are sent as a referrer when
# the protocol security level stays the same or improves,
# but isn't sent to less secure destinations.
Header set Referrer-Policy "no-referrer-when-downgrade"
# Set the Feature-policy
Header set Feature-Policy "vibrate 'self'; push *; camera 'none'; microphone 'none'"
</IfModule>
# ##################################
# PERFORMANCE
# ##################################
# cds - BEGIN DEFLATE COMPRESSION
<IfModule mod_deflate.c>
# Compress HTML, CSS, JavaScript, Text, XML and fonts
<IfModule mod_filter.c>
FilterDeclare COMPRESS
FilterProvider COMPRESS DEFLATE resp=Content-Type $text/css
FilterProvider COMPRESS DEFLATE resp=Content-Type $text/html
FilterProvider COMPRESS DEFLATE resp=Content-Type $text/javascript
FilterProvider COMPRESS DEFLATE resp=Content-Type $text/plain
FilterProvider COMPRESS DEFLATE resp=Content-Type $text/xml
FilterProvider COMPRESS DEFLATE resp=Content-Type $application/javascript
FilterProvider COMPRESS DEFLATE resp=Content-Type $application/json
FilterProvider COMPRESS DEFLATE resp=Content-Type $application/x-javascript
FilterProvider COMPRESS DEFLATE resp=Content-Type $application/atom+xml
FilterProvider COMPRESS DEFLATE resp=Content-Type $application/rss+xml
FilterProvider COMPRESS DEFLATE resp=Content-Type $application/xhtml+xml
FilterProvider COMPRESS DEFLATE resp=Content-Type $application/xml
FilterProvider COMPRESS DEFLATE resp=Content-Type $application/vnd.ms-fontobject
FilterProvider COMPRESS DEFLATE resp=Content-Type $application/x-font-ttf
FilterProvider COMPRESS DEFLATE resp=Content-Type $application/x-font
FilterProvider COMPRESS DEFLATE resp=Content-Type $application/x-font-opentype
FilterProvider COMPRESS DEFLATE resp=Content-Type $application/x-font-otf
FilterProvider COMPRESS DEFLATE resp=Content-Type $application/x-font-truetype
FilterProvider COMPRESS DEFLATE resp=Content-Type $font/opentype
FilterProvider COMPRESS DEFLATE resp=Content-Type $image/svg+xml
FilterProvider COMPRESS DEFLATE resp=Content-Type $image/x-icon
FilterChain COMPRESS
FilterProtocol COMPRESS DEFLATE change=yes;byteranges=no
</IfModule>
<IfModule !mod_filter.c>
# Compress HTML, CSS, JavaScript, Text, XML and fonts
AddOutputFilterByType DEFLATE application/javascript
AddOutputFilterByType DEFLATE application/rss+xml
AddOutputFilterByType DEFLATE application/vnd.ms-fontobject
AddOutputFilterByType DEFLATE application/x-font
AddOutputFilterByType DEFLATE application/x-font-opentype
AddOutputFilterByType DEFLATE application/x-font-otf
AddOutputFilterByType DEFLATE application/x-font-truetype
AddOutputFilterByType DEFLATE application/x-font-ttf
AddOutputFilterByType DEFLATE application/x-javascript
AddOutputFilterByType DEFLATE application/xhtml+xml
AddOutputFilterByType DEFLATE application/xml
AddOutputFilterByType DEFLATE font/opentype
AddOutputFilterByType DEFLATE font/otf
AddOutputFilterByType DEFLATE font/ttf
AddOutputFilterByType DEFLATE image/svg+xml
AddOutputFilterByType DEFLATE image/x-icon
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE text/javascript
AddOutputFilterByType DEFLATE text/plain
AddOutputFilterByType DEFLATE text/xml
</IfModule>
# Remove browser bugs (only needed for really old browsers)
<IfModule mod_setenvif.c>
BrowserMatch ^Mozilla/4 gzip-only-text/html
BrowserMatch ^Mozilla/4\.0[678] no-gzip
BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
SetEnvIfNoCase Request_URI \.(?:gif|jpe?g|png)$ no-gzip dont-vary
</IfModule>
<IfModule mod_headers.c>
Header append Vary User-Agent env=!dont-vary
Header append Vary Accept-Encoding
</IfModule>
</IfModule>
# cds - END DEFLATE COMPRESSION
# cds - START EXPIRES CACHING - Optimizing cache-control #
<IfModule mod_expires.c>
ExpiresActive On
ExpiresDefault "access plus 1 month"
ExpiresByType text/html "access plus 1 seconds"
ExpiresByType text/xml "access plus 1 seconds"
ExpiresByType text/plain "access plus 1 seconds"
ExpiresByType application/xml "access plus 1 seconds"
ExpiresByType application/rss+xml "access plus 1 seconds"
ExpiresByType application/json "access plus 1 seconds"
ExpiresByType text/css "access plus 1 month"
ExpiresByType text/javascript "access plus 1 month"
ExpiresByType application/javascript "access plus 1 month"
ExpiresByType application/x-javascript "access plus 1 month"
ExpiresByType image/x-ico "access plus 1 year"
ExpiresByType image/x-icon "access plus 1 year"
ExpiresByType image/gif "access plus 1 year"
ExpiresByType image/png "access plus 1 year"
ExpiresByType image/jpe "access plus 1 year"
ExpiresByType image/jpg "access plus 1 year"
ExpiresByType image/jpeg "access plus 1 year"
ExpiresByType video/ogg "access plus 1 month"
ExpiresByType audio/ogg "access plus 1 month"
ExpiresByType video/mp4 "access plus 1 month"
ExpiresByType video/webm "access plus 1 month"
ExpiresByType font/truetype "access plus 1 month"
ExpiresByType font/opentype "access plus 1 month"
ExpiresByType application/x-font-woff "access plus 1 month"
ExpiresByType image/svg+xml "access plus 1 year"
ExpiresByType application/pdf "access plus 1 month"
ExpiresByType application/vnd.ms-fontobject "access plus 1 month"
<IfModule mod_mime.c>
AddType image/vnd.microsoft.icon .ico
ExpiresByType image/vnd.microsoft.icon "access plus 1 year"
</IfModule>
<IfModule mod_headers.c>
# Turn ETags Off
Header unset ETag
Header unset Pragma
Header unset Last-Modified
Header set Connection keep-alive
Header append Cache-Control "public, no-transform, must-revalidate"
</IfModule>
</IfModule>
# cds - END EXPIRES CACHING - Optimizing cache-control #
## cds - BEGIN Cache-Control Headers
#<ifModule mod_headers.c>
#<filesMatch "\.(ico|jpeg|jpg|png|gif|swf|pdf|svg)$">
#Header set Cache-Control "public"
#</filesMatch>
#<filesMatch "\.(css)$">
#Header set Cache-Control "public"
#</filesMatch>
#<filesMatch "\.(js)$">
#Header set Cache-Control "private"
#</filesMatch>
#<filesMatch "\.(x?html?|php)$">
#Header set Cache-Control "private, must-revalidate"
#</filesMatch>
#</ifModule>
## cds - END Cache-Control Headers
# Now that we're sending far-future expires headers (previous step),
# we can disable all ETags that otherwise would have been sent by the server
# From: https://htaccessbook.com/disable-etags/
FileETag none
# BEGIN WordPress
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
# END WordPress
# Block PHP Files in Uploads Directory
<FilesMatch "\.(?i:php)$">
<IfModule !mod_authz_core.c>
Order allow,deny
Deny from all
</IfModule>
<IfModule mod_authz_core.c>
Require all denied
</IfModule>
</FilesMatch>
<?php
// WP memory settings
// define('WP_MEMORY_LIMIT', '256M');
// Enable debug log in wp-content/debug.log
define('WP_DEBUG', false);
define('WP_DEBUG_LOG', false);
define('WP_DEBUG_DISPLAY', false);
// Limit revisions to 3
define('WP_POST_REVISIONS', 3);
// OR
// Disable revisions
// define('WP_POST_REVISIONS', false);
// Require SSL for Admin and Logins
define( 'FORCE_SSL_ADMIN', true );
// Disable the Plugin and Theme Editor
define( 'DISALLOW_FILE_EDIT', true );
// Block external URL requests by defining WP_HTTP_BLOCK_EXTERNAL as true and this will only allow localhost and your blog to make requests
define( 'WP_HTTP_BLOCK_EXTERNAL', true );
// define( 'WP_ACCESSIBLE_HOSTS', 'api.wordpress.org,*.github.com' ); //comma separated list of hostnames to allow, wildcard domains are supported
// Solve problem of wordpress asking for ftp
// when updating plugins in localhost
// define('FS_METHOD','direct');
<?php
/************************************************************************
* load Optimization file, which has various
* functions to improve pagespeed of the site
* and cleanup WP
***********************************************************************/
include( get_stylesheet_directory() . './cds-optimizations-n-tweaks.php' );
/************************************************************************
* load cds-wp-admin-tweaks-n-extras file, which has various
* functions to make changes/additions to the WP admin area
***********************************************************************/
include( get_stylesheet_directory() . './cds-wp-admin-tweaks-n-extras.php' );
<?php
/**
* CubeDesigns - Wordpress Optimizations and Tweaks
*
* Some of the below function are from the Plugin: Meta Generator and Version Info Remover
* (https://wordpress.org/plugins/meta-generator-and-version-info-remover/)
*/
/************************************************************************
* Header items cleaning.
*
* @return void
***********************************************************************/
function cds_clean_the_header_outout() {
remove_action( 'wp_head', 'wp_generator' ); // Remove WP Generator Vesion.
remove_action( 'wp_head', 'wp_resource_hints', 2 ); // Remove s.w.org DNS-Prefetch.
remove_action( 'wp_head', 'wlwmanifest_link' ); // Remove wlwmanifest.xml.
remove_action( 'wp_head', 'rsd_link' ); // Remove Really Simple Discovery Link.
remove_action( 'wp_head', 'wp_shortlink_wp_head', 10, 0 ); // Remove Shortlink URL.
remove_action( 'wp_head', 'print_emoji_detection_script', 7 ); // Remove Emoji's Styles and Scripts.
remove_action( 'wp_print_styles', 'print_emoji_styles' ); // Remove Emoji's Styles and Scripts.
remove_action( 'admin_print_scripts', 'print_emoji_detection_script' ); // Remove Emoji's Styles and Scripts from Admin.
remove_action( 'admin_print_styles', 'print_emoji_styles' ); // Remove Emoji's Styles and Scripts from Admin.
remove_action( 'wp_head', 'index_rel_link' ); // Remove Link to Home Page.
remove_action( 'wp_head', 'feed_links_extra', 3 ); // Remove Every Extra Links to RSS Feeds.
remove_action( 'wp_head', 'adjacent_posts_rel_link_wp_head', 10 ); // Remove Prev-Next Links from Header - Not from Post.
remove_action( 'wp_head', 'adjacent_posts_rel_link', 10, 0 ); // Remove Prev-Next Links.
remove_action( 'wp_head', 'start_post_rel_link', 10, 0 ); // Remove Random Link Post.
remove_action( 'wp_head', 'parent_post_rel_link', 10, 0 ); // Remove parent Post Link.
add_filter( 'the_generator', '__return_false' ); // Remove Generator Name from RSS Feed.
}
add_action( 'after_setup_theme', 'cds_clean_the_header_outout' );
/************************************************************************
* Remove WPML generator
***********************************************************************/
if ( !empty ( $GLOBALS['sitepress'] ) ) {
function cds_remove_wpml_generator() {
remove_action(
current_filter(),
array ( $GLOBALS['sitepress'], 'meta_generator_tag' )
);
}
add_action( 'wp_head', 'cds_remove_wpml_generator', 0 );
}
/************************************************************************
* Remove Slider Revolution generator
***********************************************************************/
function cds_remove_revslider_meta_tag() {
return '';
}
add_filter( 'revslider_meta_generator', 'cds_remove_revslider_meta_tag' );
/************************************************************************
* Remove Visual Composer / WPBakery Page Builder generator
***********************************************************************/
function cds_remove_visual_composer_generator() {
if ( class_exists( 'Vc_Manager' ) || class_exists( 'Vc_Base' ) ) {
remove_action('wp_head', array(visual_composer(), 'addMetaData'));
}
}
add_action('init', 'cds_remove_visual_composer_generator', 100);
/************************************************************************
* Remove comment-reply.min.js completely
***********************************************************************/
function cds_remove_comment_reply_js() {
wp_deregister_script( 'comment-reply' );
}
add_action('init', 'cds_remove_comment_reply_js', 10);
/************************************************************************
* Remove jQuery Migrate Script from header
* and Load jQuery from Google API
***********************************************************************/
function cds_remove_jquery_migrate_load_google_hosted_jquery(){
if (!is_admin()) {
wp_deregister_script('jquery');
wp_register_script('jquery', 'https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js', false, null);
wp_enqueue_script('jquery');
}
}
add_action('init','cds_remove_jquery_migrate_load_google_hosted_jquery');
/************************************************************************
* Remove Yoast SEO comments
***********************************************************************/
function cbs_remove_yoast_seo_comments() {
if ( ! class_exists( 'WPSEO_Frontend' ) ) {
return;
}
$instance = WPSEO_Frontend::get_instance();
// To ensure that future version of the plugin does not cause any problem
if ( ! method_exists( $instance, 'debug_mark') ) {
return;
}
remove_action( 'wpseo_head', array( $instance, 'debug_mark' ), 2 );
}
add_action('template_redirect', 'cbs_remove_yoast_seo_comments', 9999);
add_filter('wpseo_debug_markers', '__return_false', 9999); // Requires Yoast > v14.0
/************************************************************************
* Remove Query Strings (the version) from script and style files,
* some files won't be cached if there is a query string in them
***********************************************************************/
// function cds_remove_script_version( $src ){
// $parts = explode( '?ver', $src );
// return $parts[0];
// }
// add_filter( 'script_loader_src', 'cds_remove_script_version', 15, 1 );
// add_filter( 'style_loader_src', 'cds_remove_script_version', 15, 1 );
/************************************************************************
* remove wp version param from any enqueued scripts
* (using wp_enqueue_script()) or styles (using wp_enqueue_style()).
***********************************************************************/
function cds_remove_appended_version_script_style( $target_url ) {
$filename_arr = explode('?', basename($target_url));
$filename = $filename_arr[0];
/* check if "ver=" argument exists in the url or not */
if (strpos( $target_url, 'ver=' )) {
$target_url = remove_query_arg( 'ver', $target_url );
}
/* check if "version=" argument exists in the url or not */
if (strpos( $target_url, 'version=' )) {
$target_url = remove_query_arg( 'version', $target_url );
}
return $target_url;
}
/**
* Priority set to 20000. Higher numbers correspond with later execution.
* Hook into the style loader and remove the version information.
*/
add_filter('style_loader_src', 'cds_remove_appended_version_script_style', 20000);
/**
* Hook into the script loader and remove the version information.
*/
add_filter('script_loader_src', 'cds_remove_appended_version_script_style', 20000);
<?php
/**
* CubeDesigns - Wordpress Admin Tweaks and Extras
*
*/
/************************************************************************
* Add and Display featured image column in Posts list
***********************************************************************/
function cds_add_featured_image_column( $columns ) {
$columns['featured_image_thumb'] = 'Featured Image';
return $columns;
}
add_filter('manage_posts_columns' , 'cds_add_featured_image_column', 5);
function cds_display_featured_image_column_data( $column, $post_id ) {
switch ( $column ) {
case 'featured_image_thumb':
echo get_the_post_thumbnail($post_id, 'thumbnail');
break;
}
}
add_action( 'manage_posts_custom_column' , 'cds_display_featured_image_column_data', 5, 2 );
if ( current_user_can( 'manage_options' ) && get_current_user_id() == 2 ) {
global $wpdb;
// Get expired wp_sessions *use LIMIT if you have a LOT of wp_sessions
$expiration_keys = $wpdb->get_results( "
SELECT option_name, option_value
FROM $wpdb->options
WHERE option_name LIKE '_wp_session_expires_%'
AND option_value < NOW()
LIMIT 0, 50000
" );
$now = time(); // EPOCH time
$expired_sessions = array();
foreach( $expiration_keys as $expiration ) {
// Double check that the session has expired
if ( $now > intval( $expiration->option_value ) ) {
// Get the session ID by parsing the option_name
$session_id = str_replace("_wp_session_expires_", "", $expiration->option_name);
$expired_sessions[] = $expiration->option_name;
$expired_sessions[] = "_wp_session_$session_id";
}
}
// Delete all expired sessions in a single query
if ( ! empty( $expired_sessions ) ) {
$option_names = implode( "','", $expired_sessions );
// highlight_string("<?php\n\$option_names =\n" . var_export($option_names) . ";\n");
$wpdb->query( "DELETE FROM $wpdb->options WHERE option_name IN ('$option_names')" );
}
}
<?php
/**
* CubeDesigns - Varius functions for specific cases
*
*/
/**
* [cds_clean_attached_image_attrs]
*
* Remove srcset and sizes in specific page
*
* @param [type] $attr [description]
* @param [type] $attachment [description]
* @param [type] $size [description]
* @return [type] [description]
*/
function cds_clean_attached_image_attrs( $attr, $attachment, $size ) {
// Limit to specific page. e.g. posts grid page with lots of images
// If page is: #some_page_id
if ( is_page(137) ) {
// highlight_string("<?php\n\$attr =\n" . var_export($attr, true) . ";\n");
// Remove srcset and sizes
if ( isset($attr["srcset"]) ) { unset($attr["srcset"]); }
if ( isset($attr["sizes"]) ) { unset($attr["sizes"]); }
}
return $attr;
}
add_filter( 'wp_get_attachment_image_attributes', 'cds_clean_attached_image_attrs', 10, 3 );
/**
* [cds_disable_wp_responsive_images]
*
* disable srcset on frontend
*
* @return [type] [description]
*/
function cds_disable_wp_responsive_images() {
return 1;
}
add_filter('max_srcset_image_width', 'cds_disable_wp_responsive_images');
/**
* [cds_style_loader_tag_filter]
* Add display=swap to google fonts, when not having access to the creation enque style
*
* @return the modified <link> tag
*/
add_filter('style_loader_tag', 'cds_style_loader_tag_filter', 10, 2);
function cds_style_loader_tag_filter($html, $handle) {
// add &display=swap in google fonts Roboto
if ($handle === 'Roboto') {
if ( function_exists('simplexml_load_file') ) {
$xmlFromHtml = simplexml_load_string($html);
$hrefs = $xmlFromHtml->xpath("//@href");
if (isset($hrefs) && !empty($hrefs) && is_array($hrefs)) {
foreach($hrefs as $href) {
$modified_href = (string)$href . '&display=swap';
$final_link = "<link rel='stylesheet' id='Roboto-css' href='" . $modified_href . "' type='text/css' media='all' />";
$html = $final_link;
break;
}
}
}
}
return $html;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment