How to enqueue jQuery asynchronously in wordpress? - javascript

My theme uses the bundled jQuery of Wordpress and I want to load it asynchronously. (Yeah, PageSpeed Insights...)

There is a hook for this script_loader_tag. You can use it as below
add_filter( 'script_loader_tag', 'add_async_to_script', 10, 3 );
function add_async_to_script( $tag, $handle, $src ) {
//You can use this to make all async
$tag = str_replace( ' src', ' async src', $tag );
// You can use this to make it work as below for a specific script
if ( 'dropbox.js' === $handle ) {
$tag = '<script async type="text/javascript" src="' . esc_url( $src ) . '"></script>';
}
return $tag;
}

Depending on the functionalities of your website, deferring or loading jquery asyncronously might possibly impact on the way the page is loaded or even break functionality. It may as well run smoothly.
But in order to give you a correct answer I must recommend you not to do it.
Here is some reference if you want to still try
https://wpshout.com/make-site-faster-async-deferred-javascript-introducing-script_loader_tag/

Related

Wordpress - enqueue script only if specific class is on page

What would be the most appropriate solution to enqueue a script in WordPress only when a class of .google-map is detected on that page?
In my main.js I can detect the item on the page and do something, but I am not so sure you can use the enqueue function in a JS file.
$(document).ready(function(){
if (document.getElementsByClassName('.google-map')) {
alert(true);
}
});
The above is just attempt #1. Please feel free to provide any other solutions, using functions or anything else. I am simply not too sure what is possible that's why I don't have more examples.
Ordinarily add the file google.js (or whatever name you choose) to WP footer by adding the code below into your functions.php file. This will add the javascript file into WP footer the right way. https://developer.wordpress.org/reference/functions/wp_enqueue_script/
function my_scriptings_scripts() {
wp_enqueue_script( 'my_scriptings', get_template_directory_uri() . '/js/google.js', array('jquery'), '20171212', true );
}
add_action( 'wp_enqueue_scripts', 'my_scriptings_scripts' );
Inside your js/google.js
Using Vanilla javascript, check for the element with class name. If it exists then call the function for the action.
var element = document.getElementByClassName('google-map');
if (typeof(element) != 'undefined' && element != null)
{
//call function for google actions
google_acts_like_this();
}
function google_acts_like_this(){
console.log('Google will take over the world');
alert('Google will take over the world');
}
OR Try wienter code hereth Jquery -
if ($(document).find(.google-map).length > 0)
{
//If the element exist, then do something.
google_acts_like_this();
}
function google_acts_like_this(){
console.log('Google will take over the world');
alert('Google will take over the world');
}

wp_enqueue_scripts doesn't work

I created my own javascript file and now I want to integrate into my module. I'm trying to do as told in this site https://developer.wordpress.org/reference/functions/wp_enqueue_script/
But it does not work, I don't understand why
P.S: I am in the main file of my module (exampe.php)
class exemple
{
public function __construct()
{
register_activation_hook(__FILE__, array('exemple_bd', 'install'));
register_uninstall_hook(__FILE__, array('exemple_bd', 'uninstall'));
include_once plugin_dir_path( __FILE__ ).'settings.php';
new Settings();
add_action('admin_menu', array($this, 'add_admin_menu'));
add_action('admin_init', array($this, 'load_JS'));
}
public function add_admin_menu()
{
add_menu_page('monTitre', 'Monplugin', 'manage_options','xxx', array($this, 'menu_html'),'dashicons-email');
add_submenu_page('xxx', 'NouveauTitre', 'NouveauTitre', 'manage_options', 'xxx', array($this, 'menu_html'));
}
public function load_JS()
{
wp_register_script('myfunction',plugins_url( '/js/function.js', __FILE__ ));
wp_enqueue_script('myfunction');
}
You need to register them with action hook "wp_enqueue_scripts".
Use "admin_enqueue_scripts" for admin scripts.
The function should be called using the wp_enqueue_scripts action hook if you want to call it on the front-end of the site, like in the examples above...
https://developer.wordpress.org/reference/functions/wp_enqueue_script/#notes
if all the paths are good, an you have a custom theme, make sure your main theme file references wp_head()
it should be just before the closing 'head' tag like this:
<?php ...
wp_head();
?></head>

Run a function on a WP page template - is_page_template

I am trying to run a function on a specific WP page template. The specific page is called archive.php.
This is what I have so far in functions.php
if ( is_page_template( 'bloginfo("stylesheet_directory")/archive.php' ) ) {
function add_isotope() {
wp_register_script( 'isotope', get_template_directory_uri().'/js/isotope.pkgd.min.js', array('jquery'), true );
wp_register_script( 'isotope-init', get_template_directory_uri().'/js/isotope-hideall.js', array('jquery', 'isotope'), true );
wp_enqueue_script('isotope-init');
}
add_action( 'wp_enqueue_scripts', 'add_isotope' );
} else {
function add_isotope() {
wp_register_script( 'isotope', get_template_directory_uri().'/js/isotope.pkgd.min.js', array('jquery'), true );
wp_register_script( 'isotope-init', get_template_directory_uri().'/js/isotope.js', array('jquery', 'isotope'), true );
wp_enqueue_script('isotope-init');
}
add_action( 'wp_enqueue_scripts', 'add_isotope' );
}
The different between the functions is isotope-hideall, which hides all categories when the page is loaded. When not using if/else it hides all categories from all page templates when page is loaded, and that is not what I want. Therefor I am using if/else to locate the correct page template.
I have tried the following, but nothing seems to work:
is_page_template( 'archive.php' )
is_page_template( 'get_template_directory_uri()'.'/archive.php' )
Am I doing something wrong, or do you have a working solution for this?
Page can be found here.
As Pieter Goosen points out, archive.php is reserved for built in WordPress-functionality. Rename your file to something else, for instance to archives.php and make sure you are naming your custom page template at det top of the file:
<?php /* Template Name: Archives */ ?>
Your code should then work with is_page_template('archives.php') as longs as its located on root in your template folder. If not add whatever folder structure you have in front of the filename, like so: /folder/folder2/archives.php .
To avoid repeating the function twice you should also consider solving this something like so:
function add_isotope( $isotope ) {
wp_register_script( 'isotope', get_template_directory_uri().'/js/isotope.pkgd.min.js', array('jquery'), true );
wp_register_script( 'isotope-init', get_template_directory_uri().'/js/' . $isotope . '.js', array('jquery', 'isotope'), true );
wp_enqueue_script('isotope-init');
}
add_action( 'wp_enqueue_scripts', 'add_isotope' );
if ( is_page_template( 'archives.php' ) :
add_isotope( 'isotope-hideall' );
else :
add_isotope( 'isotope' );
endif;
Your complete logic is wrong here. Archives are targeted with is_archive() or the more specific conditional tag is_date() for normal archives. Note that is_archive() returns true on category, author, tag, date and taxonomy pages, so is_archive() might be a bit too generic to use if you only need to target archive
Also, your conditionals should be inside the function, not outside it as the conditional checks are way too late for the wp_enqueue_scripts hook.
Your code should be something like this
function add_isotope() {
if ( is_archive() ) { // Change as needed as I said
// Enqueue scripts for archive pages
} else {
// Enqueue scripts for all other pages
}
}
add_action( 'wp_enqueue_scripts', 'add_isotope' );

Enqueue Wordpress plugin scripts below all other JS

I am developing a simple Wordpress app but I am having an issue as all of the plugin scripts are rendered before those which are enqueued in my functions.php.
Here is a sample section of the functions.php:
function my_scripts() {
wp_register_script('app-js', get_template_directory_uri() . '/javascripts/app.js', array('jquery'), null, true );
wp_enqueue_script('app-js');
}
add_action( 'wp_enqueue_scripts', 'my_scripts');
The important this to note is that (following best practice my JS is set to render at the bottom of the page.
I also have couple of plugins running on the theme. The problem is that the output looks like this:
<!-- Note the plugin appears first -->
<script type='text/javascript' src='http://localhost/wordpress/wp-content/plugins/my-plugin/acl-plugin.js'></script>
<!-- And the main JS appears second -->
<script type='text/javascript' src='http://localhost/wordpress/wp-content/themes/my-theme/javascripts/app.js'></script>
</body>
</html>
How can I force Wordpress to display the main JS (which i believe is rendered by wp_head() to appear at the very bottom of the page?
The WordPress wp_head() method will only output scripts or styles that have that last parameter in the WordPress wp_enqueue_script() set to false.. when it is set to true it will render in the footer via the wp_footer()
you can change the priority of when its called and inserted by adjusting the $priority parameter in the add_action()
http://codex.wordpress.org/Function_Reference/add_action
$priority
(int) (optional) Used to specify the order in which the functions associated with a particular action are executed. Lower numbers correspond with earlier execution, and functions with the same priority are executed in the order in which they were added to the action. Default: 10
add_action( $hook, $function_to_add, $priority, $accepted_args );
And also look at the following two WordPress methods:
wp_enqueue_script() :
https://developer.wordpress.org/reference/functions/wp_enqueue_script/
wp_enqueue_script( string $handle, string $src = '', array $deps = array(), string|bool|null $ver = false, bool $in_footer = false )
wp_register_script() :
https://developer.wordpress.org/reference/functions/wp_register_script/
wp_register_script( string $handle, string $src, array $deps = array(), string|bool|null $ver = false, bool $in_footer = false )
Try this..
You might have to play with that $priority parameter
function my_scripts() {
wp_register_script('app-js', get_template_directory_uri() . '/javascripts/app.js', array('jquery'), null, true );
wp_enqueue_script('app-js');
}
add_action( 'wp_enqueue_scripts', 'my_scripts', 20, 1);

Adding page-specific Javascript to each view in CakePHP

In an attempt to keep my scripts maintainable, I'm going to move each into their own file, organised by controller and action:
// scripts which only apply to /views/posts/add.ctp
/app/webroot/js/page/posts/add.js
// scripts which only apply to /view/users/index.ctp
/app/webroot/js/page/users/index.js
That's all cool, however I'd like for these to be automatically added by the Controller, since it obviously knows the name of both the controller and action.
I figure the best place for this is in AppController::beforeRender(). (yes?)
The only problem is that I don't know how to actually add this into the $scripts_for_layout variable. I thought that getting a reference to the javascript helper object would work, but I can't find it from the controller!
class AppController extends Controller {
var $helpers = array("javascript", "html", "form");
function beforeRender() {
// ???
}
}
Very easy to do in your default.ctp layout file:
An example to automatically include .css files per controller and/or controller/action (because I had this lying around, easily adaptable to .js files):
<head>
...
<?php
if (is_file(WWW_ROOT . 'css' . DS . $this->params['controller'] . '.css')) {
echo $html->css($this->params['controller']);
}
if (is_file(WWW_ROOT . 'css' . DS . $this->params['controller'] . DS . $this->params['action'] . '.css')) {
echo $html->css($this->params['controller'] . '/' . $this->params['action']);
}
?>
...
</head>
Like deceze is saying, we do it using the layout, although I find our solution a bit more elegant :)
In default.ctp:
if(isset($cssIncludes)){
foreach($cssIncludes as $css){
echo $html->css($css);
}
}
if(isset($jsIncludes)){
foreach($jsIncludes as $js){
echo $javascript->link($js);
}
}
Then, in our controller actions, we define these arrays:
$this->set('cssIncludes',array('special')); // this will link to /css/special.css
$this->set('jsIncludes',array('jquery')); // this will link to /js/jquery.js
For files that need to be loaded in each view, we simply add the same type of link "statically" to the top of the layout, like:
echo $javascript->link('global');
echo $html->css('global');
This works really well for us. Good luck!
Kinda new to this, but after reading this added the following to my layout:
if ($handle = opendir(WWW_ROOT . 'js' . DS . $this->params['controller'] . DS . $this->params['action']))
{
while (false !== ($entry = readdir($handle)))
{
$entry = str_replace(".js", "", $entry);
echo $this->Html->script($entry);
}
closedir($handle);
}
I just had to do page specific inclusion, but I've found a neater way to do it in the documentation. You can just load it into some script block in your default.ctp. And in corresponding view just use HTML helper to push a script:
You can append the script tag to a specific block using the block
option:
echo $this->Html->script('wysiwyg', array('block' => 'scriptBottom'));
Which appends <script type="text/javascript" href="/js/wysiwyg.js"></script> to a block.
In your layout you can output all the script tags added to
‘scriptBottom’:
echo $this->fetch('scriptBottom');
The best way I can think of is to create your own custom AppView and have all your controllers use that:
class myController extends AppController {
var view = 'AppView';
...
}
Then, somewhere in your AppView, you'd want to do something like:
function __construct(&$controller, $register){
parent::__construct($controller,$register);
$this->addScript('<script type="text/javascript" src="/path/to/js/' . $this->controller . '/' . $this->action . '.js"></script>');
}
But I'd take a step back and think about a few things, first.
How big are your scripts, on average? Is the overhead of an external script call (before the script is cached by the client) better than adding a few hundred bytes to your main output stream (by just sticking the script into the page, inline)?
Perhaps you'd be better of somewhere in the middle -- split your scripts up by controller, but not action. That way, after the first visit to any action, the client has all scripts for all actions. This way, you avoid a big initial download for all the application's script, but you avoid adding N http round-trips (where N is the number of actions a brand new user visits).
Another way to approach the problem is to do it all in javascript. Just figure out a lazy-loading scheme. So your app just loads a very small loader.js, and that script figures out which other javascript sources to pull in.
Note: I've never tested my extend-the-view hack, but I bet it'll work if you really want to do this.
There's a nuts and bolts of CakePHP blog post on Convention over Configuration – what's the big deal? - which uses a helper for specifying Javascript files:
<?php
class JsManagerHelper extends AppHelper {
var $helpers = array('Javascript');
//where's our jQuery path relevant to CakePHP's JS dir?
var $_jqueryPath = 'jquery';
//where do we keep our page/view relevant scripts?
var $_pageScriptPath = 'page_specific';
function myJs() {
return $this->Javascript->link($this->_jqueryPath . '/' .
$this->_pageScriptPath .'/' .
$this->params['controller'] . '_' .
$this->params['action'], false);
}
}
?>
And then you just have $jsManager->myJs(); in your view.
I have authored a Plugin for this exact issue.
If you have two files:
/app/View/Post/add.ctp
/app/View/Post/add.js
it will include the add.js into the script block of the page.
OR
app/View/Post/add.js
app/webroot/js/post/add.js
it will include /js/post/add.js into the script block of the page.
A few cute features are in there and it's simple as beans. You can even use PHP inside your .js files and use viewVars which you set in the action. Most of all, you don't need to hack the view or layout files to make it work, simply fetch the 'script' block in the layout. You can also simply write the .js to another view block.
You can check it out here: https://github.com/dizyart/cakephp-viewautoload
It's in the early stages, so make sure to comment and wishlist!
LI worked a little (very little) bit over W1ckd snippet and made it easier for sharing the same js for different actions:
if ( is_dir(WWW_ROOT . 'js' . DS . $this->params['controller'] ) && ( $handle = opendir( WWW_ROOT . 'js' . DS . $this->params['controller'] ) ) )
{
while ( false !== ( $entry = readdir( $handle ) ) )
{
if ( in_array( $this->params['action'], explode( '.', $entry ) ) ) {
$entry = str_replace( ".js", "", $entry );
echo $this->Html->script( $this->params['controller'].DS.$entry );
}
}
closedir( $handle );
}
This way you can have something like:
webroot/js/controller/view.edit.add.js
And this js will be included in those three actions (view, edit, add).
With Cake v3 you can do it like this. Add the scripts you want in the specific controller.
//YourController.php
public function beforeRender (Event $event)
{
array_push($this->scripts, 'Admin/gallery');
parent::beforeRender($event);
}
Set the default in intialize and render once
//AppController.php
public function initialize()
{
parent::initialize();
$this->scripts = [];
}
public function beforeRender (Event $event)
{
/* Define scripts in beforeRender of Child */
$this->set('scripts', $this->scripts);
/*-----------------------------------------*/
}
Now you can run this function once.
<?= $this->Html->script($scripts) ?>

Categories