Last active
August 26, 2022 11:29
-
-
Save bfiessinger/94c79e3b15f1079ce0c9471feaa471d6 to your computer and use it in GitHub Desktop.
Custom WordPress asset loader Class with the ability to add scripts / styles conditionally, add extra attributes and more!
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Script and Style includes and helper Methods | |
*/ | |
namespace bf; | |
if ( ! defined('ABSPATH')) exit('restricted access'); | |
class script_loader { | |
public $enqueued_scripts = []; | |
public $enqueued_stylesheets = []; | |
public $extra_attribute_prefix = 'yourtheme_assets_extra_attributes&#'; | |
function __construct(int $priority = 10) { | |
add_action( 'wp_enqueue_scripts', [ $this, 'script_enqueue' ], $priority ); | |
add_filter('script_loader_tag',function($tag, $handle, $src){ | |
return $this->scriptAndStyleTagAttributeAdder($tag, $handle, $src, null, false); | |
},$priority,4); | |
add_filter('style_loader_tag',function($tag, $handle, $src, $media){ | |
return $this->scriptAndStyleTagAttributeAdder($tag, $handle, $src, $media, true); | |
},$priority,4); | |
} | |
/** | |
* Small Helper Utility to determine if an array | |
* is multidimensional or not | |
* | |
* @param array $a - The Array to check | |
* | |
* @since 2.0.0 | |
*/ | |
function array_is_multi( $a ) { | |
$rv = array_filter( $a, 'is_array' ); | |
if( count( $rv ) > 0 ) | |
return true; | |
return false; | |
} | |
function check_restrictions( array $restrictions ) { | |
foreach ( $restrictions as $rule ) { | |
$allow = true; | |
// Skip one iteration if $rule matches | |
if ( true !== $rule ) | |
$allow = false; | |
yield $allow; | |
} | |
} | |
/** | |
* Determine if a script or stylesheet is allowed on the current view | |
* | |
* @param array $restrictions - Array with callable restrictions. | |
* Might even be multidimensional to specify the relation between the restrictions as an argument | |
* | |
* @return bool | |
* | |
* @since 2.0.0 | |
*/ | |
function restrict( array $restrictions ) { | |
$restriction_relation = ( isset( $restrictions['relation'] ) ) ? $restrictions['relation'] : 'OR'; | |
unset( $restrictions['relation'] ); | |
/** | |
* Flatten the restrictions Array. | |
* Works only with 2 dimensional Arrays | |
*/ | |
if ( $this->array_is_multi( $restrictions ) ) { | |
$restrictions = call_user_func_array('array_merge', $restrictions); | |
} | |
/** | |
* Check if the current script is allowed to enqueue | |
* otherwise just return false from this function | |
*/ | |
if ( $restriction_relation != 'OR' ) { | |
foreach ( $this->check_restrictions( $restrictions ) as $allowed ) { | |
if ( ! $allowed ) | |
return false; | |
} | |
} elseif ( ! in_array(true, \iterator_to_array( $this->check_restrictions( $restrictions ) ), true) ) { | |
return false; | |
} | |
return true; | |
} | |
/** | |
* Custom Enqueue Script function with the ability to add | |
* attributes and restrictions | |
* | |
* @param string $handle - File handler | |
* @param string $src - Path to the file - Default: '' | |
* @param array $deps - Script dependencies - Default: [] | |
* @param mixed $ver - Script version - Default: null | |
* @param bool $in_footer - Enqueue the script in the header or the footer - Default: true | |
* @param array $atts - Custom Script Attributes - Default: [] | |
* @param array $restrictions - Restrict enqueueing the script. This array accepts callables. If one returns a value thats falsy the script won't enqueue | |
* @param array $localize - Setup data for wp_localize_script to pass PHP variables | |
* | |
* @since 2.0.0 | |
*/ | |
function add_script( string $handle, string $src = '', array $deps = [], $ver = null, bool $in_footer = true, array $atts = [], array $restrictions = [], array $localize = [] ) { | |
if ( ! empty( $restrictions ) ) { | |
if ( $this->restrict( $restrictions ) === false ) | |
return; | |
} | |
$this->enqueued_scripts[] = [ | |
'handle' => $handle, | |
'src' => $src, | |
'deps' => $deps, | |
'ver' => $ver, | |
'in_footer' => $in_footer, | |
'atts' => $atts, | |
'localize' => $localize | |
]; | |
} | |
/** | |
* Custom Enqueue Stylesheet function with the ability to add | |
* attributes and restrictions | |
* | |
* @param string $handle - File handler | |
* @param string $src - Path to the file - Default: '' | |
* @param array $deps - Stylesheet dependencies - Default: [] | |
* @param mixed $ver - Stylesheet version - Default: null | |
* @param string $media - The media type for the enqueued stylesheet - Default: 'all' | |
* @param array $atts - Custom Stylesheet Attributes - Default: [] | |
* @param array $restrictions - Restrict enqueueing the Stylesheet. This array accepts callables. If one returns a value thats falsy the Stylesheet won't enqueue | |
* | |
* @since 2.0.0 | |
*/ | |
function add_stylesheet( string $handle, string $src = '', array $deps = [], $ver = null, string $media = 'all', array $atts = [], array $restrictions = [] ) { | |
if ( ! empty( $restrictions ) ) { | |
if ( $this->restrict( $restrictions ) === false ) | |
return; | |
} | |
$this->enqueued_stylesheets[] = [ | |
'handle' => $handle, | |
'src' => $src, | |
'deps' => $deps, | |
'ver' => $ver, | |
'media' => $media, | |
'atts' => $atts | |
]; | |
} | |
/** | |
* Wrapper function that registers, enqueues, localizes and adds custom | |
* attributes for scripts and styles | |
* | |
* @since 2.0.0 | |
*/ | |
function script_enqueue() { | |
foreach ( $this->enqueued_scripts as $script ) { | |
wp_register_script( $script['handle'], $script['src'], $script['deps'], $script['ver'], $script['in_footer'] ); | |
wp_enqueue_script( $script['handle'] ); | |
// Add additional Attributes to the script tag if needed | |
if ( is_array( $script['atts'] ) && ! empty( $script['atts'] ) ) { | |
foreach ( $script['atts'] as $key => $value ) { | |
if ( $key == 'conditional' ) | |
wp_script_add_data( $script['handle'], $key, $value ); | |
else | |
wp_script_add_data( $script['handle'], $this->extra_attribute_prefix . $key, $value ); | |
} | |
} | |
if ( | |
is_array( $script['localize'] ) && | |
! empty( $script['localize'] ) && | |
isset( $script['localize']['handle'] ) && | |
isset( $script['localize']['data'] ) && | |
\gettype( $script['localize']['handle'] ) == 'string' && | |
\gettype( $script['localize']['data'] ) == 'array' | |
) { | |
wp_localize_script( $script['handle'], $script['localize']['handle'], $script['localize']['data'] ); | |
} | |
} | |
foreach ( $this->enqueued_stylesheets as $stylesheet ) { | |
wp_register_style( $stylesheet['handle'], $stylesheet['src'], $stylesheet['deps'], $stylesheet['ver'], $stylesheet['media'] ); | |
wp_enqueue_style( $stylesheet['handle'] ); | |
// Add additional Attributes to the script tag if needed | |
if ( is_array( $stylesheet['atts'] ) && ! empty( $stylesheet['atts'] ) || true ) { | |
foreach ( $stylesheet['atts'] as $key => $value ) { | |
if ( $key == 'conditional' ) | |
wp_style_add_data( $stylesheet['handle'], $key, $value ); | |
else | |
wp_style_add_data( $stylesheet['handle'], $this->extra_attribute_prefix . $key, $value ); | |
} | |
} | |
} | |
} | |
/** | |
* Callback for WP to hit before echoing out an enqueued resource. This callback specifically checks for any key-value pairs that have been added | |
* through `add_data()` and are prefixed with a special value to indicate they should be injected into the final HTML | |
* | |
* @param {string} $tag - Will be the full string of the tag (`<link>` or `<script>`) | |
* @param {string} $handle - The handle that was specified for the resource when enqueuing it | |
* @param {string} $src - the URI of the resource | |
* @param {string|null} $media - if resources is style, should be the target media, else null | |
* @param {boolean} $isStyle - If the resource is a stylesheet | |
* | |
* @since 2.0.0 | |
*/ | |
function scriptAndStyleTagAttributeAdder($tag, $handle, $src, $media, $isStyle){ | |
$extra_attribute_pattern = '/' . $this->extra_attribute_prefix . '(.+)/'; | |
$extraAttrs = []; | |
$nodeName = ''; | |
// Get the WP_Dependency instance for this handle, and grab any extra fields | |
if ($isStyle) { | |
$nodeName = 'link'; | |
$extraAttrs = wp_styles()->registered[$handle]->extra; | |
} else { | |
$nodeName = 'script'; | |
$extraAttrs = wp_scripts()->registered[$handle]->extra; | |
} | |
// Check stored properties on WP resource instance against our pattern | |
$attribsToAdd = []; | |
foreach ($extraAttrs as $fullAttrKey => $attrVal) { | |
$matches = []; | |
preg_match($extra_attribute_pattern, $fullAttrKey, $matches); | |
if (count($matches) > 1) { | |
$attrKey = $matches[1]; | |
$attribsToAdd[$attrKey] = $attrVal; | |
} | |
} | |
$replacementStr = '<' . $nodeName; | |
foreach ($attribsToAdd as $attrKey => $attrVal) { | |
$replacementStr .= ' ' . $attrKey . '="' . $attrVal . '"'; | |
} | |
$tag = preg_replace('/<' . $nodeName . '/', $replacementStr, $tag ); | |
return $tag; | |
} | |
} | |
// Usage Instructions: | |
/** | |
* Create an instance | |
* @param int $priority | |
*/ | |
$scriptLoaderInstance = new \bf\script_loader(11); | |
/** | |
* Add a script to the queue | |
* | |
* @param string $handle - File handler | |
* @param string $src - Path to the file - Default: '' | |
* @param array $deps - Script dependencies - Default: [] | |
* @param mixed $ver - Script version - Default: null | |
* @param bool $in_footer - Enqueue the script in the header or the footer - Default: true | |
* @param array $atts - Custom Script Attributes - Default: [] | |
* @param array $restrictions - Restrict enqueueing the script. This array accepts callables. If one returns a value thats falsy the script won't enqueue | |
* @param array $localize - Setup data for wp_localize_script to pass PHP variables | |
*/ | |
$scriptLoaderInstance->add_script( | |
'your-handle', // Handle | |
'path/to/your/script.js', // source | |
[ | |
'lodash', | |
'wp-i18n' | |
], // Dependencies | |
'1.0.0', // Version | |
true, // in footer | |
[ | |
'async' => 'async' | |
], // Custom script attributes | |
[ | |
'relation' => 'AND', | |
[ | |
( is_single() || is_page() ), | |
( comments_open() || get_comments_number() ), | |
! post_password_required() | |
] | |
], // Restrictions | |
[ | |
'ajaxUrl' => admin_url( 'admin-ajax.php' ) | |
] // localize | |
); | |
/** | |
* Add a stylesheet to the queue | |
* | |
* @param string $handle - File handler | |
* @param string $src - Path to the file - Default: '' | |
* @param array $deps - Stylesheet dependencies - Default: [] | |
* @param mixed $ver - Stylesheet version - Default: null | |
* @param string $media - The media type for the enqueued stylesheet - Default: 'all' | |
* @param array $atts - Custom Stylesheet Attributes - Default: [] | |
* @param array $restrictions - Restrict enqueueing the Stylesheet. This array accepts callables. If one returns a value thats falsy the Stylesheet won't enqueue | |
*/ | |
$scriptLoaderInstance->add_stylesheet( | |
'your-handle', // Handle | |
'path/to/your/script.css', // source | |
[ | |
'dashicons' | |
], | |
'1.0.0', // Version | |
'all', // media | |
[ | |
'crossorigin' => 'anonymous' // Custom Stylesheet attributes | |
], | |
[ | |
'relation' => 'OR', | |
[ | |
is_singular(), | |
is_post_type_archive(['book']) | |
] | |
] // Restrictions | |
); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment