Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add module to alert about excessive JS and CSS assets #54

Merged
merged 21 commits into from
Jan 28, 2022
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
a7883dc
Plugin https://github.com/audrasjb/site-health-audit-enqueued-assets/…
manuelRod Dec 8, 2021
83fd785
partial unit testing added.
manuelRod Dec 9, 2021
69d1208
Adding more unit testing.
manuelRod Dec 9, 2021
bda604d
adding missing tests.
manuelRod Dec 10, 2021
663fe3a
removing duplicated get_transient
manuelRod Dec 15, 2021
3a5cc54
Adding filter for transient, and invalidate cache on switch_theme, ac…
manuelRod Dec 15, 2021
2e555a1
Adding user action to null transient cache.
manuelRod Dec 15, 2021
c668003
redirects after cleaning cache to site-health.php without query args
manuelRod Dec 16, 2021
2baf8fe
All prefix needs to be updated to perflab_
manuelRod Dec 16, 2021
327bed3
adding functionality to get resources sizes
manuelRod Dec 16, 2021
f7c2a60
Adding filesize to the transient cache, and functionality related to it.
manuelRod Dec 17, 2021
5333d7d
Merge branch 'trunk' into add/sitehealth-enqueued-assets
manuelRod Jan 10, 2022
b0ccda4
migrating module to new module structure
manuelRod Jan 10, 2022
2757e8c
migration to new module structure
manuelRod Jan 10, 2022
07a6a70
split code refactor, creation of a new helper file with helper method…
manuelRod Jan 10, 2022
47f4f9f
prefix fix
manuelRod Jan 10, 2022
84af518
refactor adding suggestions:
manuelRod Jan 10, 2022
a528fb4
changing wording and adding information about bellow threshold limits.
manuelRod Jan 11, 2022
e42b9c2
implementing new threshold limits
manuelRod Jan 11, 2022
90c17f8
Adding filters for limits. Fixing _n translatable strings.
manuelRod Jan 26, 2022
35edbca
nit-pick fixes
manuelRod Jan 27, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 100 additions & 0 deletions modules/site-health/audit-enqueued-assets/helper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
<?php
/**
* Helper functions used by module.
*
* @package performance-lab
* @since 1.0.0
*/

/**
* Gets total of enqueued scripts.
*
* @since 1.0.0
*
* @return int|false Number of total scripts or false if transient hasn't been set.
*/
function perflab_aea_get_total_enqueued_scripts() {
$enqueued_scripts = false;
$list_enqueued_scripts = get_transient( 'aea_enqueued_front_page_scripts' );
if ( $list_enqueued_scripts ) {
$enqueued_scripts = count( $list_enqueued_scripts );
}
return $enqueued_scripts;
}

/**
* Gets total size in bytes of Enqueued Scripts.
*
* @since 1.0.0
*
* @return int|false Byte Total size or false if transient hasn't been set.
*/
function perflab_aea_get_total_size_bytes_enqueued_scripts() {
$total_size = false;
$list_enqueued_scripts = get_transient( 'aea_enqueued_front_page_scripts' );
if ( $list_enqueued_scripts ) {
foreach ( $list_enqueued_scripts as $enqueued_script ) {
$total_size += $enqueued_script['size'];
}
manuelRod marked this conversation as resolved.
Show resolved Hide resolved
}
return $total_size;
}

/**
* Gets total of enqueued styles.
*
* @since 1.0.0
*
* @return int|false Number of total styles or false if transient hasn't been set.
*/
function perflab_aea_get_total_enqueued_styles() {
$enqueued_styles = false;
$list_enqueued_styles = get_transient( 'aea_enqueued_front_page_styles' );
if ( $list_enqueued_styles ) {
$enqueued_styles = count( $list_enqueued_styles );
}
return $enqueued_styles;
}

/**
* Gets total size in bytes of Enqueued Styles.
*
* @since 1.0.0
*
* @return int|false Byte Total size or false if transient hasn't been set.
*/
function perflab_aea_get_total_size_bytes_enqueued_styles() {
$total_size = false;
$list_enqueued_styles = get_transient( 'aea_enqueued_front_page_styles' );
if ( $list_enqueued_styles ) {
foreach ( $list_enqueued_styles as $enqueued_style ) {
$total_size += $enqueued_style['size'];
}
manuelRod marked this conversation as resolved.
Show resolved Hide resolved
}
return $total_size;
}

/**
* Convert full URL paths to absolute paths.
*
* @since 1.0.0
*
* @param string $resource_url URl resource link.
* @return string Returns absolute path to the resource.
*/
function perflab_aea_get_path_from_resource_url( $resource_url ) {
return ABSPATH . wp_make_link_relative( $resource_url );
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is okay for a start, but it's a bit oversimplified:

  • It is possible for URLs to be in a location that is not within ABSPATH, for example several sites have their wp-content directory separate, which is supported by WordPress.
  • WordPress may be in a subdirectory of the domain.

For most sites what you have here will work, but we should make sure to also accomodate those other sites.

I suggest we expand this as follows to at least cover for these two cases a bit better:

Suggested change
return ABSPATH . wp_make_link_relative( $resource_url );
if ( 0 === strpos( $resource_url, WP_CONTENT_URL ) ) {
return WP_CONTENT_DIR . substr( $resource_url, strlen( WP_CONTENT_URL ) );
}
$site_url = untrailingslashit( site_url() );
if ( 0 === strpos( $resource_url, $site_url ) ) {
return ABSPATH . substr( $resource_url, strlen( $site_url ) );
}
return ABSPATH . wp_make_link_relative( $resource_url );

Copy link
Contributor Author

@manuelRod manuelRod Jan 26, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@felixarntz can you give me an example of the first case? I cannot see it clearly.

Regarding WordPress may be in a subdirectory of the domain.
Do you mean something like this?
https://example.com/blog/wp-content/themes/test-theme/style.css ?
If that's the case, doesn't ABSPATH . wp_make_link_relative( $resource_url ) covers it too?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@manuelRod Some popular environments like https://github.com/roots/bedrock have their wp-content directory outside of the (rest of the) WordPress directory, so that URLs would be e.g. https://example.com/content/themes/... and https://example.com/wp/wp-includes/.... Both conditions I'm suggesting here cover that use-case, the first is for assets that come from the wp-content directory in a custom location, the second one for when the WordPress directory is in a subdirectory.

If that's the case, doesn't ABSPATH . wp_make_link_relative( $resource_url ) covers it too?

I don't think it does, since wp_make_link_relative simply removes the protocol and domain. Looking at my example above, that means you get /wp/wp-includes/..., and when you append that to ABSPATH, the wp directory would basically be in there twice. That's why for these cases we have to use the site_url() function, which is the "URL equivalent" of ABSPATH (the same way that WP_CONTENT_URL is the "URL equivalent" to WP_CONTENT_DIR).

}

/**
* If file exists, returns its size.
*
* @since 1.0.0
*
* @param string $file_src Path to the file.
* @return int Returns size if file exists, 0 if it doesn't.
*/
function perflab_aea_get_resource_file_size( $file_src ) {
return file_exists( $file_src ) ? filesize( $file_src ) : 0;
}

232 changes: 232 additions & 0 deletions modules/site-health/audit-enqueued-assets/load.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
<?php
/**
* Module Name: Audit Enqueued Assets
* Description: Adds a CSS and JS resource checker in Site Health checks.
* Experimental: No
*
* @package performance-lab
* @since 1.0.0
*/

/**
* Require helper functions.
*/
require_once __DIR__ . '/helper.php';

/**
* Audit enqueued scripts in is_front_page(). Ignore /wp-includes scripts.
*
* It will save information in a transient for 12 hours.
*
* @since 1.0.0
*/
function perflab_aea_audit_enqueued_scripts() {
if ( ! is_admin() && is_front_page() && current_user_can( 'view_site_health_checks' ) && false === get_transient( 'aea_enqueued_front_page_scripts' ) ) {
global $wp_scripts;
$enqueued_scripts = array();

foreach ( $wp_scripts->queue as $handle ) {
$src = $wp_scripts->registered[ $handle ]->src;
if ( $src && ! strpos( $src, 'wp-includes' ) ) {
$enqueued_scripts[] = array(
'src' => $src,
'size' => perflab_aea_get_resource_file_size( perflab_aea_get_path_from_resource_url( $src ) ),
);
}
}
$expiration = apply_filters( 'perflab_aea_enqueued_front_page_scripts_expiration_in_seconds', 12 * HOUR_IN_SECONDS );
manuelRod marked this conversation as resolved.
Show resolved Hide resolved
set_transient( 'aea_enqueued_front_page_scripts', $enqueued_scripts, $expiration );
}
}
add_action( 'wp_print_scripts', 'perflab_aea_audit_enqueued_scripts' );

/**
* Audit enqueued styles in the frontend. Ignore /wp-includes styles.
*
* It will save information in a transient for 12 hours.
*
* @since 1.0.0
*/
function perflab_aea_audit_enqueued_styles() {
if ( ! is_admin() && is_front_page() && current_user_can( 'view_site_health_checks' ) && false === get_transient( 'aea_enqueued_front_page_styles' ) ) {
global $wp_styles;
$enqueued_styles = array();
foreach ( $wp_styles->queue as $handle ) {
$src = $wp_styles->registered[ $handle ]->src;
if ( $src && ! strpos( $src, 'wp-includes' ) ) {
$enqueued_styles[] = array(
'src' => $src,
'size' => perflab_aea_get_resource_file_size( perflab_aea_get_path_from_resource_url( $src ) ),
);
}
}
$expiration = apply_filters( 'perflab_aea_enqueued_front_page_styles_expiration_in_seconds', 12 * HOUR_IN_SECONDS );
manuelRod marked this conversation as resolved.
Show resolved Hide resolved
set_transient( 'aea_enqueued_front_page_styles', $enqueued_styles, $expiration );
}
}
add_action( 'wp_print_styles', 'perflab_aea_audit_enqueued_styles' );

/**
* Adds tests to site health.
*
* @since 1.0.0
*
* @param array $tests Site Health Tests.
* @return array
*/
function perflab_aea_add_enqueued_assets_test( $tests ) {
$tests['direct']['enqueued_js_assets'] = array(
'label' => esc_html__( 'JS assets', 'performance-lab' ),
'test' => 'perflab_aea_enqueued_js_assets_test',
);
$tests['direct']['enqueued_css_assets'] = array(
'label' => esc_html__( 'CSS assets', 'performance-lab' ),
'test' => 'perflab_aea_enqueued_css_assets_test',
);

return $tests;
}
add_filter( 'site_status_tests', 'perflab_aea_add_enqueued_assets_test' );

/**
* Callback for enqueued_js_assets test.
*
* @since 1.0.0
*
* @return array
*/
function perflab_aea_enqueued_js_assets_test() {
/**
* If the test didn't run yet, deactivate.
*/
$enqueued_scripts = perflab_aea_get_total_enqueued_scripts();
if ( false === $enqueued_scripts ) {
return array();
}

$result = array(
'label' => esc_html__( 'Enqueued scripts', 'performance-lab' ),
'status' => 'good',
'badge' => array(
'label' => esc_html__( 'Performance', 'performance-lab' ),
'color' => 'blue',
),
'description' => sprintf(
/* translators: 1: Number of enqueued scripts. 2: "script" word. 3.Scripts size. */
'<p>' . esc_html__( 'The amount of %1$s enqueued %2$s (size: %3$s) is acceptable.', 'performance-lab' ) . '</p>',
$enqueued_scripts,
_n( 'script', 'scripts', $enqueued_scripts, 'performance-lab' ),
manuelRod marked this conversation as resolved.
Show resolved Hide resolved
size_format( perflab_aea_get_total_size_bytes_enqueued_scripts() )
),
'actions' => '',
'test' => 'enqueued_js_assets',
);

if ( $enqueued_scripts > 30 || perflab_aea_get_total_size_bytes_enqueued_scripts() > 300000 ) {
manuelRod marked this conversation as resolved.
Show resolved Hide resolved
$result['status'] = 'recommended';
$result['badge']['color'] = 'orange';
$result['description'] = sprintf(
/* translators: 1: Number of enqueued scripts. 2: "script" word. 3.Scripts size. */
'<p>' . esc_html__( 'Your website enqueues %1$s %2$s (size: %3$s). Try to reduce the number or to concatenate them.', 'performance-lab' ) . '</p>',
$enqueued_scripts,
_n( 'script', 'scripts', $enqueued_scripts, 'performance-lab' ),
manuelRod marked this conversation as resolved.
Show resolved Hide resolved
size_format( perflab_aea_get_total_size_bytes_enqueued_scripts() )
);
$result['actions'] .= sprintf(
/* translators: 1: HelpHub URL. 2: Link description. 3.URL to clean cache. 4. Clean Cache text. */
'<p><a target="_blank" href="%1$s">%2$s</a></p><p><a href="%3$s">%4$s</a></p>',
esc_url( __( 'https://wordpress.org/support/article/optimization/', 'performance-lab' ) ),
esc_html__( 'More info about performance optimization', 'performance-lab' ),
esc_url( add_query_arg( 'action', 'clean_aea_audit', wp_nonce_url( admin_url( 'site-health.php' ), 'clean_aea_audit' ) ) ),
esc_html__( 'Clean Test Cache', 'performance-lab' )
);
}

return $result;
}

/**
* Callback for enqueued_css_assets test.
*
* @since 1.0.0
*
* @return array
*/
function perflab_aea_enqueued_css_assets_test() {
/**
* If the test didn't run yet, deactivate.
*/
$enqueued_styles = perflab_aea_get_total_enqueued_styles();
if ( false === $enqueued_styles ) {
return array();
}
$result = array(
'label' => esc_html__( 'Enqueued styles', 'performance-lab' ),
'status' => 'good',
'badge' => array(
'label' => esc_html__( 'Performance', 'performance-lab' ),
'color' => 'blue',
),
'description' => sprintf(
/* translators: 1: Number of enqueued styles. 2: "styles" word. 3.Styles size. */
'<p>' . esc_html__( 'The amount of %1$s enqueued %2$s (size: %3$s) is acceptable.', 'performance-lab' ) . '</p>',
$enqueued_styles,
_n( 'style', 'styles', $enqueued_styles, 'performance-lab' ),
manuelRod marked this conversation as resolved.
Show resolved Hide resolved
size_format( perflab_aea_get_total_size_bytes_enqueued_styles() )
),
'actions' => '',
'test' => 'enqueued_css_assets',
);

if ( $enqueued_styles > 10 || perflab_aea_get_total_size_bytes_enqueued_styles() > 100000 ) {
$result['status'] = 'recommended';
$result['badge']['color'] = 'orange';
$result['description'] = sprintf(
/* translators: 1: Number of enqueued styles. 2: "style" word. 3.Styles size. */
'<p>' . esc_html__( 'Your website enqueues %1$s %2$s (size: %3$s). Try to reduce the number or to concatenate them.', 'performance-lab' ) . '</p>',
$enqueued_styles,
_n( 'style', 'styles', $enqueued_styles, 'performance-lab' ),
manuelRod marked this conversation as resolved.
Show resolved Hide resolved
size_format( perflab_aea_get_total_size_bytes_enqueued_styles() )
);

$result['actions'] .= sprintf(
/* translators: 1: HelpHub URL. 2: Link description. 3.URL to clean cache. 4. Clean Cache text. */
'<p><a target="_blank" href="%1$s">%2$s</a></p><p><a href="%3$s">%4$s</a></p>',
esc_url( __( 'https://wordpress.org/support/article/optimization/', 'performance-lab' ) ),
esc_html__( 'More info about performance optimization', 'performance-lab' ),
esc_url( add_query_arg( 'action', 'clean_aea_audit', wp_nonce_url( admin_url( 'site-health.php' ), 'clean_aea_audit' ) ) ),
esc_html__( 'Clean Test Cache', 'performance-lab' )
);
}

return $result;
}

/**
* Invalidate both transients/cache on user clean_aea_audit action.
* Redirects to site-health.php screen adter clean up.
*
* @since 1.0.0
*/
function perflab_aea_clean_aea_audit_action() {
if ( isset( $_GET['action'] ) && 'clean_aea_audit' === $_GET['action'] && current_user_can( 'view_site_health_checks' ) ) {
check_admin_referer( 'clean_aea_audit' );
perflab_aea_invalidate_cache_transients();
wp_safe_redirect( remove_query_arg( array( 'action', '_wpnonce' ), wp_get_referer() ) );
}
}
add_action( 'admin_init', 'perflab_aea_clean_aea_audit_action' );

/**
* Invalidate both transients/cache.
*
* @since 1.0.0
*/
function perflab_aea_invalidate_cache_transients() {
delete_transient( 'aea_enqueued_front_page_scripts' );
delete_transient( 'aea_enqueued_front_page_styles' );
}
add_action( 'switch_theme', 'perflab_aea_invalidate_cache_transients' );
add_action( 'activated_plugin', 'perflab_aea_invalidate_cache_transients' );
add_action( 'deactivated_plugin', 'perflab_aea_invalidate_cache_transients' );

Loading