Saving Private Divi

Namaste!

One complaint that I have heard a lot in the Divi world is that it isn’t easy to find/access the save button on the front-end builder. Wouldn’t it be great if it was right in the admin bar at the top of your screen? In this tutorial, I’ll show you how to modify the functions.php file of your child theme (you are using a child theme, right?) and add in some javascript to accomplish this. Best of all, you can give you new button some color so that your clients can find it!

All of this code is posted on github for you to fork and make your own. First, we will start by adding the button. Open up your child theme functions.php file. Do NOT edit the main Divi theme functions.php file. Even if you don’t brick your site, you risk losing your custom php during the next upgrade! In order to add this button we will use the ‘add_node()’ method. 

function shd_add_divi_fb_save_button( $wp_admin_bar ) {
    $args = array(
        'id' => 'shd-divi-save-button',
        'title' => 'Save',
        'meta' => array(
            'class' => 'shd-button-class--save',
            )
        );
    $wp_admin_bar->add_node($args);
}
add_action( 'admin_bar_menu', 'shd_add_divi_fb_save_button', 1500 );

Okay, let’s walk through it. First, we call our function a unique name – ‘shd_add_divi_fb_save_button’. Okay, okay, I’m being a little crazy with the name. I posted my code on a github and the wonderful Jonathan Bossenger, who runs Divi Hackers United, gave me an important reminder. When you introduce a new function into a WordPress environment through the functions.php or through a plugin, it is competing with every other public function – if it doesn’t have a unique name you will get a conflict. Here is a great article about it. At any point, I’m prefixing with my group’s initials and using adding a meaningful function name. I’m also passing in the class that WordPress uses to generate the toolbar, ‘$wp_admin_bar’. This allows us to make changes to the toolbar within out function.

Next, I’m setting up an array of arguments that describe our new button. The ‘id’ is used on the backend and is not the ‘ID’ we would assign when programming in HTML. The ‘title’ is the label that will be added to our button – we could pass in HTML tags if we wanted. The final argument we are defining is ‘meta’, which accepts an array of parameters. In this case, I’m only setting the class of the button. Here is a link to the WordPress codex describing the parameters that can be passed to add_node(). Finally, I add the $args array to the toolbar by using the object operator (‘->’) to use the add_node method on the $wp_admin_bar.

We finish this section off by telling WordPress that we want to run this function whenever it loads in the ‘admin_bar_menu’ hook. Additionally, I have given this action a priority of 1500. This number determines when the function is run compared to all of the other functions being run when WordPress gets to the ‘admin_bar_menu’ hook. In this case, I set the priority higher than the ‘Exit Visual Builder’ button, so it will display after that button, or to the right of it.

Next up, I’m going to hide the button when we are on an admin page using a little CSS. Note-I will also be modifying my child theme styling sheet to hide the button when we aren’t using the front-end builder

#wpadminbar li.shd-button-class--save {
    display: none;
        background-color: #0F0;
}

, but this won’t impact the look of the button on the dashboard, because our theme styling isn’t loaded there. 

function shd_divi_save_button_styling() {
    echo ' <style>
#wpadminbar li.shd-button-class--save {
    display: none;
}
</style>';
}
add_action( 'admin_head', 'shd_divi_save_button_styling' );

All I’m doing with this function is saying that when WordPress loads the head of the admin pages, I want to inject the following styling. The ‘admin_head’ hook is useful for hooking up any style sheets for modifying the look of your dashboard.

The final thing that I’m adding to my functions.php file is a directive to enqueue my javascript that I’ll be writing next.

function shd_divi_save_button() {
    wp_enqueue_script( 'button-query', get_stylesheet_directory_uri() . '/js/jquery.visualsave.js', array( 'jquery' ), null, false );
}
add_action( 'wp_enqueue_scripts', 'shd_divi_save_button' );

Not too much to comment on here.

Moving on to the javascript side of things. Overall, what we need to do is:

  1. Make the button appear when we are in the visual builder only.
  2. Set up our new save button to act like the existing buttons.
(function($){
 var urlParams = getQueryVariable( 'et_fb' );
 if (urlParams == 1 ) {
 var startListening = setInterval(function() { iconCheck() }, 600); 
 };

 function getQueryVariable( variable ) {
 var query = window.location.search.substring(1);
 var vars = query.split("&");
 for (var i=0;i<vars.length;i++) {
 var pair = vars[i].split("=");
 if(pair[0] == variable){return pair[1];}
 }
 return(false);
 };
 
 function iconCheck() {
  if ($('.et-fb-icon--move')[0]){
    stopListening();
    catchClicks();
    }
 };

 function stopListening() {
   clearInterval(startListening);
 };

 function catchClicks() {
   $('.shd-button-class--save').css('display', 'list-item');
   if ($('.et-fb-button--save-draft')[0]){
     $(".shd-button-class--save").click(function(){
       $('.et-fb-button--save-draft').trigger('click');
     });
   };
   if (($('.et-fb-button--publish')[0])) {
     $(".shd-button-class--save").click(function(){
       $('.et-fb-button--publish').trigger('click');
     });
   }; 
   if ($('#wp-admin-bar-et-disable-visual-builder')[0]) {
     $('#wp-admin-bar-et-disable-visual-builder').click(function(){
     $('.shd-button-class--save').css('display', 'none');
   });
   };
 };
}(jQuery));

First, a thank you to Bruno Bouyajdad of indikator-design.de and Jonathan again for suggestions on improving this code. Now, let’s walk through to understand what is going on. To start, the whole of the script is being run as an anonymous self-executing function with jQuery being passed in so that we can use ‘$’ instead of having to type out jQuery each time. Remember, WordPress runs in noConflict mode by default.

To solve for list item one – only revealing the button when the visual builder is active – We use a function named  ‘getQueryVariable’. The Divi builder passes a variable in the URL when you activate the visual builder. That is the portion after the ‘?’. We retrieve this portion of the URL  using ‘window.location.search.substring(1)’. That substring is then split and parsed to look at the name and value of each variable. If this function finds the variable we passed in when we called it, it will return the value of the variable. On almost all browsers (I’m looking at you Microsoft), there is an easier way to do this using the Web API’s URLSearchParams() constructor, but I wanted to make sure this worked for everyone..Once we identify that the visual builder has been activated 

Once we identify that the visual builder has been activated we start a timer. This timer calls the ‘iconCheck()’ function every 600ms, waiting for all of the page elements to load in. Both the ‘$(window).load()’ and ‘$(document).ready()’ methods fire too early for our purposes. In this case, I am surveying the DOM for the presence of the round purple button with a class of ‘et-fb-icon–move’ that appears at the bottom of the viewport once the visual builder loads in. The line of code ‘ if( $(‘.et-fb-icon–move)[0]) {‘ could be re-written as, ‘if ( $(‘.et-fb-icon–move).length > 0) {‘. So basically, I’m just checking if the element exists. If the element is found, the timer is turned off using ‘clearInterval()’ and a call is made to a new function, ‘catchClicks()’.

The ‘catchClicks()’ function first causes the save button to be revealed by changing the ‘display’ value to ‘list-item’. It then sets-up two click listeners. The class of the save button depends on if the particular page has been previously published or is brand-new. So, the first two ‘if’ statements test which particular button exists and then set a click listener on our newly revealed save button to trigger that particular Divi save button. The last ‘if’ statement turns the visibility of the new save button off when the user clicks on the exit visual builder button.

And that is it! Sometime in the future, I will release this as a free plugin. I’m debating whether I make a go at refactoring this in OOP first or not. As always, if you have any questions or corrections, feel free to shoot me an e-mail or make a comment. Hope this helps someone!

Metta!!

Published: 04.29.2017

In: Legacy, Programming

4 thoughts on “Saving Private Divi”

  1. I use a simple shortcut for saving – ctrl+s. Works nicely for me)

    1. Bob Means says:

      ctrl + s does open the bottom menu, but as far as I know, it doesn’t save your changes, am I wrong? Many clients who don’t know Divi get confused by this. They are used to hitting ctrl +s and moving on. So, adding a simple button for saving makes sense for some clients.

  2. It should save all changes. More shortcuts here. There is a learning curve for that, but it can help afterward.

    1. Bob Means says:

      Cool to know, thanks!
      I don’t use the front-end builder much. My tut was in response to multiple people on Facebook complaining that their clients had problems updating aspects of their sites and wanting a more visible save button. it is good that there are alternative short key alternatives.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.