Bricks - Enqueues scripts and stylesheets at the document head?

Published on by in Tutorials.

While developing a plugin, I noticed that Bricks Builder doesn’t load custom elements’ stylesheets at the document head. If scripts or stylesheets aren't coded well, loading those critical resources after the above-the-fold content may cause browser reflow which is bad for SEO and end-users.

For more information about critial resources and browser rendering mechanism, you may read these articles: Understanding the critical path and Rendering: repaint, reflow

After diving into Bricks’ sourcecode, the only solution I found is to loop through Bricks data to see whether an element appears in a document or not before enqueuing its scripts and stylesheets.

Suppose that we have an element called abc-element (the name of the element when registering with Bricks).

On the backend, we only enqueue backend scripts and stylesheets so that the element can work properly when editing:

public function enqueue_scripts()
{
    // Ensure that it is on the backend only.
    if (!$this->is_frontend) { // `$is_frontend` is available for every element extending the Bricks\Element.
        wp_enqueue_style('abc-element-backend', ELEMENT_URI . '/backend.min.css', [], ELEMENT_VERSION);
        wp_enqueue_script('abc-element-backend', ELEMENT_URI . '/backend.min.js', [], ELEMENT_VERSION, true);
    }
}


On the frontend, we have four situations:

If your elements can be used for the Header section only.

We need to retrieve Bricks data of the Header, loop through it and load scripts & stylesheets accordingly:

use Bricks\Database;

function wpclevel_enqueue_abc_element_scripts()
{
    // Ensure that it is on the frontend only.
    if (bricks_is_frontend()) {
        // The data is an array of all elements being used on the Header.
        $bricks_data = Database::get_template_data('header');
        if ($bricks_data) {
            foreach ($bricks_data as $element) {
                // Only load scripts & stylesheets when the `abc-element` is being used.
                if ('abc-element' === $element['name']) {
                    wp_enqueue_style('abc-element-frontend', ELEMENT_URI . '/frontend.min.css', [], ELEMENT_VERSION);
                    wp_enqueue_script('abc-element-frontend', ELEMENT_URI . '/frontend.min.js', [], ELEMENT_VERSION, true);
                    break; // Stop the loop immediately to avoid redundant loops.
                }
            }
        }
    }
}
add_action('wp_enqueue_scripts', 'wpclevel_enqueue_abc_element_scripts');

If your elements can be used for the Content section only.

For the content section, it’s a bit tricky. We have to retrieve Bricks data based on the template type being included:

use Bricks\Helpers;
use Bricks\Database;

function wpclevel_get_bricks_content()
{
    global $wp_query;

    // Only get data of the main query
    if (!$wp_query->is_main_query()) {
        return false;
    }

    $content = false;

    if ($wp_query->is_404()) {
        $content = Helpers::get_bricks_data($wp_query->queried_object_id, 'error');
    } elseif ($wp_query->is_search()) {
        $content = Database::get_template_data('search');
    } elseif ($wp_query->is_post_type_archive('product')) {
        if (function_exists('is_shop') && is_shop()) {
            $post_id = wc_get_page_id('shop');
            $template_type = 'content';
        } else {
            $post_id = $wp_query->queried_object_id;
            $template_type = 'wc_archive';
        }
        $content = Helpers::get_bricks_data($post_id, $template_type);
    } elseif ($wp_query->is_archive()) {
        $content = Database::get_template_data('archive');
    } else {
        if ($wp_query->is_home() && !$wp_query->is_front_page()) {
            $post_id = (int)get_option('page_for_posts'); // Blog page
        } elseif (!$wp_query->is_home() && $wp_query->is_front_page()) {
            $post_id = (int)get_option('page_on_front'); // Home page
        } else {
            $post_id = $wp_query->queried_object_id;
        }
        $content = Helpers::get_bricks_data($post_id, 'content');
    }

    return $content;
}

function wpclevel_enqueue_abc_element_scripts()
{
    // Ensure that it is on the frontend only.
    if (bricks_is_frontend()) {
        // The data is an array of all elements being used on the content.
        $bricks_data = wpclevel_get_bricks_content();
        if ($bricks_data) {
            foreach ($bricks_data as $element) {
                // Only load scripts & stylesheets when the `abc-element` is being used.
                if ('abc-element' === $element['name']) {
                    wp_enqueue_style('abc-element-frontend', ELEMENT_URI . '/frontend.min.css', [], ELEMENT_VERSION);
                    wp_enqueue_script('abc-element-frontend', ELEMENT_URI . '/frontend.min.js', [], ELEMENT_VERSION, true);
                    break; // Stop the loop immediately to avoid redundant loops.
                }
            }
        }
    }
}
add_action('wp_enqueue_scripts', 'wpclevel_enqueue_abc_element_scripts');

Same as the Header, but the template type is footer now:

use Bricks\Database;

function wpclevel_enqueue_abc_element_scripts()
{
    // Ensure that it is on the frontend only.
    if (bricks_is_frontend()) {
        // The data is an array of all elements being used on the Footer.
        $bricks_data = Database::get_template_data('footer');
        if ($bricks_data) {
            foreach ($bricks_data as $element) {
                // Only load scripts & stylesheets when the `abc-element` is being used.
                if ('abc-element' === $element['name']) {
                    wp_enqueue_style('abc-element-frontend', ELEMENT_URI . '/frontend.min.css', [], ELEMENT_VERSION);
                    wp_enqueue_script('abc-element-frontend', ELEMENT_URI . '/frontend.min.js', [], ELEMENT_VERSION, true);
                    break; // Stop the loop immediately to avoid redundant loops.
                }
            }
        }
    }
}
add_action('wp_enqueue_scripts', 'wpclevel_enqueue_abc_element_scripts');

If your elements can be used anywhere.

In this case, you can get Bricks data of all the three section types above and loop through it to check. Make sure to break the loop once the element found.

So, that the solution I found. If you have any better solutions or questions, let me know in the comment section.