Disable all Bricks features on certain pages; post types

I don’t want our clients to be able to access Bricks for certain pages and custom post types.

Specifically, this should suppress:

  • Yellow “EDIT WITH BRICKS” butons on post editor
  • Bricks-related links in post list page (e.g., ‘Edit with Bricks’,
  • No Bricks top menubar item on frontend
  • (Is that all?)

I am doing this with custom code, but it’s a lot of work and feeling a bit hacky right now in some places (e.g., Post list page links).

Is there a proper way to do this?

Thanks!

This is coming in Bricks 2.0. It will probably be available as a stable feature in about a month. See this post: Bricks 2.0 Changelog – Bricks

Funny after using Bricks for a long time … within a month of this feature coming out officially, I spend hours hacking a solution… Oh well! I will watch for this release - TY @GrowPlugins

Well don’t throw your code away. It’s possible something very specific you need to restrict won’t be possible right away. Maybe it will still come in handy.

Thanks. One issue I note is that it was easier to suppress the EDIT WITH BRICKS button in Gutenberg. When using the Classic editor the Bricks tab is front by default (not sure why), and that was not easy to deal with.

I am looking forward to this update! :slight_smile:

Hi @GrowPlugins !

Ok yes I do see this item in the 2.0 Changelog :blush::

  • Post types: Select which post types can be edited using Bricks.

We also need to disable Bricks on specific posts for our clients (such as only certain Pages)… E.g., some are off-limits (templated), and we only want them to be able to edit the post title, content, author, etc.

Just curious if this will be included in Bricks 2.0, or if not, if we can get a feature request in for this?

Thanks again!

Good question. I haven’t played around with the alpha yet. Hopefully that is planned or will be implemented via feature request.

This would probably be something you will need to combine CPT with the builder capabilities functionality.

It seems this is not yet a thing.

Perhaps it will come as a setting, or there will be a supported/recommended way to extend the current capabilities to include individual posts in the future.

Thanks

Hi everyone,
Unfortunately, even in the latest version of Bricks, it’s still not possible to disable the builder for specific pages or groups of regular WordPress pages.
I’d really love to see this feature added. Alternatively, if anyone has a working code snippet to achieve this, I’d be very grateful!
Some colleagues are simply impossible to educate. Even though they call themselves administrators, they really aren’t. Don’t even get me started. :grinning_face_with_smiling_eyes:
The simplest solution would be an option to disable Bricks for a specific page and all its child pages. Just select the page, disable Bricks, and that’s it. Problem solved!
Thanks in advance!

Hi,

I saw your question and it got me thinking. Ofcourse if we can create a group of users and we can restrict them with full builder access, but we cannot restrict users for specific pages or posts. I have developed a small plugin which can do this. It has got a small interface screen where we can select the users, pages, posts, etc. to restrict. Once installed, you can go to settings and can access the Bricks Access Manager screen. Unfortunately, I cannot attach the full plugin zip file here, hence adding the full code. Just create a folder named bricks-access-manager in the plugins folder and create a file bricks-access-manager.php and paste the entire code. Activate the plugin and your set.

A word of caution though: Please test the plugin thoroughly on a staging or local environment site and then migrate to a live production server.

<?php
/**
 * Plugin Name: Bricks Access Manager
 * Description: Per-user Bricks editing restrictions for posts, pages and custom post types.
 * Version: 1.0.0
 * Requires PHP: 7.4
 * Author: Bricks Access Manager
 */

if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

final class Bricks_Access_Manager {

    const OWNER_OPTION = 'bam_owner_id';
    const RULES_OPTION = 'bam_restrictions';

    public static function init() {

        add_action( 'admin_menu', [ __CLASS__, 'menu' ] );
        add_action( 'admin_init', [ __CLASS__, 'block_builder' ], 1 );
        add_action( 'template_redirect', [ __CLASS__, 'block_builder' ], 1 );

        add_action( 'admin_bar_menu', [ __CLASS__, 'admin_bar' ], 999 );
        add_filter( 'post_row_actions', [ __CLASS__, 'row_actions' ], 999, 2 );
        add_filter( 'page_row_actions', [ __CLASS__, 'row_actions' ], 999, 2 );
    }

    public static function activate() {

        if ( ! get_option( self::OWNER_OPTION ) ) {
            update_option(
                self::OWNER_OPTION,
                get_current_user_id(),
                false
            );
        }

        if ( false === get_option( self::RULES_OPTION ) ) {
            add_option( self::RULES_OPTION, [], '', false );
        }
    }

    private static function owner_id() {
        return (int) get_option( self::OWNER_OPTION, 0 );
    }

    private static function is_owner() {
        return get_current_user_id() === self::owner_id()
            && current_user_can( 'manage_options' );
    }

    private static function rules() {
        $rules = get_option( self::RULES_OPTION, [] );

        return is_array( $rules ) ? $rules : [];
    }

    private static function is_restricted( $post_id, $user_id = 0 ) {

        $user_id = $user_id ?: get_current_user_id();
        $post_id = absint( $post_id );

        if ( ! $post_id || ! $user_id ) {
            return false;
        }

        // The designated owner is never restricted.
        if ( (int) $user_id === self::owner_id() ) {
            return false;
        }

        $rules = self::rules();

        return in_array(
            $post_id,
            array_map( 'absint', $rules[ $user_id ] ?? [] ),
            true
        );
    }

    public static function menu() {

        if ( ! self::is_owner() ) {
            return;
        }

        add_management_page(
            'Bricks Access Manager',
            'Bricks Access Manager',
            'manage_options',
            'bricks-access-manager',
            [ __CLASS__, 'screen' ]
        );
    }

    public static function screen() {

        if ( ! self::is_owner() ) {
            wp_die( 'Access denied.' );
        }

        $users = get_users( [
            'orderby' => 'display_name',
            'order'   => 'ASC',
        ] );

        $selected_user = isset( $_REQUEST['bam_user'] )
            ? absint( $_REQUEST['bam_user'] )
            : 0;

        if (
            ! $selected_user ||
            $selected_user === self::owner_id() ||
            ! get_userdata( $selected_user )
        ) {
            $selected_user = 0;

            foreach ( $users as $user ) {
                if ( (int) $user->ID !== self::owner_id() ) {
                    $selected_user = (int) $user->ID;
                    break;
                }
            }
        }

        $search = isset( $_GET['bam_search'] )
            ? sanitize_text_field( wp_unslash( $_GET['bam_search'] ) )
            : '';

        $post_type = isset( $_GET['bam_type'] )
            ? sanitize_key( $_GET['bam_type'] )
            : 'all';

        $page = max( 1, absint( $_GET['paged'] ?? 1 ) );

        $types = get_post_types(
            [ 'public' => true, 'show_ui' => true ],
            'objects'
        );

        // Bricks templates are excluded from this version.
        unset( $types['attachment'], $types['bricks_template'] );

        if ( $post_type !== 'all' && ! isset( $types[ $post_type ] ) ) {
            $post_type = 'all';
        }

        $query = new WP_Query( [
            'post_type'      => $post_type === 'all'
                ? array_keys( $types )
                : $post_type,
            'post_status'    => [ 'publish', 'draft', 'private', 'pending', 'future' ],
            'posts_per_page' => 25,
            'paged'          => $page,
            's'              => $search,
            'orderby'        => 'title',
            'order'          => 'ASC',
        ] );

        $rules = self::rules();

        if (
            $_SERVER['REQUEST_METHOD'] === 'POST' &&
            isset( $_POST['bam_save'] )
        ) {
            check_admin_referer( 'bam_save_rules' );

            $posted_user = absint( $_POST['bam_user'] ?? 0 );

            if (
                $posted_user &&
                $posted_user === $selected_user &&
                $posted_user !== self::owner_id() &&
                get_userdata( $posted_user )
            ) {
                $visible_ids = isset( $_POST['bam_visible'] )
                    ? array_map( 'absint', (array) wp_unslash( $_POST['bam_visible'] ) )
                    : [];

                $checked_ids = isset( $_POST['bam_locked'] )
                    ? array_map( 'absint', (array) wp_unslash( $_POST['bam_locked'] ) )
                    : [];

                // Only modify the items displayed on this page.
                $existing = array_map(
                    'absint',
                    $rules[ $posted_user ] ?? []
                );

                $existing = array_diff( $existing, $visible_ids );

                $checked_ids = array_intersect(
                    $checked_ids,
                    $visible_ids
                );

                $rules[ $posted_user ] = array_values(
                    array_unique(
                        array_merge( $existing, $checked_ids )
                    )
                );

                update_option( self::RULES_OPTION, $rules, false );

                echo '<div class="notice notice-success is-dismissible"><p>Restrictions saved.</p></div>';
            }
        }

        $locked = array_map(
            'absint',
            $rules[ $selected_user ] ?? []
        );

        $base_url = admin_url( 'tools.php?page=bricks-access-manager' );

        ?>
        <div class="wrap">
            <h1>Bricks Access Manager</h1>

            <p>
                Select a user and restrict Bricks editing
                for individual pages and posts.
                Normal WordPress editing remains available.
            </p>

            <form method="get" style="margin:20px 0;">
                <input type="hidden" name="page"
                       value="bricks-access-manager">

                <label for="bam_user"><strong>User:</strong></label>

                <select name="bam_user" id="bam_user">
                    <?php foreach ( $users as $user ) :
                        if ( (int) $user->ID === self::owner_id() ) {
                            continue;
                        }
                        ?>
                        <option value="<?php echo esc_attr( $user->ID ); ?>"
                            <?php selected( $selected_user, $user->ID ); ?>>
                            <?php echo esc_html( $user->display_name . ' (' . $user->user_login . ')' ); ?>
                        </option>
                    <?php endforeach; ?>
                </select>

                <label for="bam_type">Content type:</label>

                <select name="bam_type" id="bam_type">
                    <option value="all">All types</option>
                    <?php foreach ( $types as $type ) : ?>
                        <option value="<?php echo esc_attr( $type->name ); ?>"
                            <?php selected( $post_type, $type->name ); ?>>
                            <?php echo esc_html( $type->labels->name ); ?>
                        </option>
                    <?php endforeach; ?>
                </select>

                <input type="search"
                       name="bam_search"
                       value="<?php echo esc_attr( $search ); ?>"
                       placeholder="Search content">

                <?php submit_button( 'Filter', 'secondary', '', false ); ?>
            </form>

            <?php if ( $selected_user ) : ?>

            <form method="post">
                <?php wp_nonce_field( 'bam_save_rules' ); ?>

                <input type="hidden" name="bam_user"
                       value="<?php echo esc_attr( $selected_user ); ?>">

                <p>
                    <strong><?php echo count( $locked ); ?></strong>
                    restricted items for this user.
                </p>

                <p>
                    <button type="button" class="button"
                            id="bam-select-all">Restrict all visible</button>

                    <button type="button" class="button"
                            id="bam-clear-all">Allow all visible</button>
                </p>

                <table class="widefat striped">
                    <thead>
                        <tr>
                            <th>Content</th>
                            <th>Type</th>
                            <th>Status</th>
                            <th>Restrict Bricks</th>
                        </tr>
                    </thead>
                    <tbody>
                    <?php if ( $query->have_posts() ) : ?>
                        <?php foreach ( $query->posts as $post ) : ?>
                            <tr>
                                <td>
                                    <strong>
                                        <?php echo esc_html( get_the_title( $post ) ?: '(No title)' ); ?>
                                    </strong>

                                    <input type="hidden"
                                           name="bam_visible[]"
                                           value="<?php echo esc_attr( $post->ID ); ?>">
                                </td>

                                <td>
                                    <?php echo esc_html( get_post_type_object( $post->post_type )->labels->singular_name ); ?>
                                </td>

                                <td>
                                    <?php echo esc_html( $post->post_status ); ?>
                                </td>

                                <td>
                                    <input type="checkbox"
                                           class="bam-checkbox"
                                           name="bam_locked[]"
                                           value="<?php echo esc_attr( $post->ID ); ?>"
                                           <?php checked( in_array( $post->ID, $locked, true ) ); ?>>
                                </td>
                            </tr>
                        <?php endforeach; ?>
                    <?php else : ?>
                        <tr><td colspan="4">No content found.</td></tr>
                    <?php endif; ?>
                    </tbody>
                </table>

                <p>
                    <?php submit_button(
                        'Save Restrictions',
                        'primary',
                        'bam_save',
                        false
                    ); ?>
                </p>
            </form>

            <?php
            $pagination = paginate_links( [
                'base'      => add_query_arg(
                    [
                        'bam_user'   => $selected_user,
                        'bam_type'   => $post_type,
                        'bam_search' => $search,
                        'paged'      => '%#%',
                    ],
                    $base_url
                ),
                'format'    => '',
                'current'   => $page,
                'total'     => $query->max_num_pages,
                'type'      => 'plain',
            ] );

            if ( $pagination ) {
                echo '<div class="tablenav"><div class="tablenav-pages">';
                echo wp_kses_post( $pagination );
                echo '</div></div>';
            }
            ?>

            <?php endif; ?>
        </div>

        <script>
        document.addEventListener('DOMContentLoaded', function () {
            const checkboxes = document.querySelectorAll('.bam-checkbox');

            document.getElementById('bam-select-all')
                ?.addEventListener('click', function () {
                    checkboxes.forEach(el => el.checked = true);
                });

            document.getElementById('bam-clear-all')
                ?.addEventListener('click', function () {
                    checkboxes.forEach(el => el.checked = false);
                });
        });
        </script>
        <?php

        wp_reset_postdata();
    }

    /**
     * Block the standard Bricks builder URL.
     *
     * This does not intercept every internal Bricks save endpoint.
     */
    public static function block_builder() {

        if ( ! is_user_logged_in() ) {
            return;
        }

        if ( self::is_owner() ) {
            return;
        }

        $bricks = isset( $_GET['bricks'] )
            ? sanitize_text_field( wp_unslash( $_GET['bricks'] ) )
            : '';

        if ( $bricks !== 'run' ) {
            return;
        }

        $post_id = absint( $_GET['post'] ?? 0 );

        if ( ! $post_id && ! is_admin() ) {
            $post_id = get_queried_object_id();
        }

        if ( self::is_restricted( $post_id ) ) {
            wp_die(
                'You do not have permission to edit this content with Bricks.',
                'Bricks Access Restricted',
                [ 'response' => 403 ]
            );
        }
    }

    /**
     * Remove Bricks-related row actions.
     */
    public static function row_actions( $actions, $post ) {

        if ( ! self::is_restricted( $post->ID ) ) {
            return $actions;
        }

        foreach ( $actions as $key => $html ) {
            if (
                stripos( $key, 'bricks' ) !== false ||
                stripos( $html, 'bricks=run' ) !== false
            ) {
                unset( $actions[ $key ] );
            }
        }

        return $actions;
    }

    /**
     * Remove Bricks builder links from the admin bar
     * for restricted content.
     */
    public static function admin_bar( $bar ) {

        if ( self::is_owner() ) {
            return;
        }

        $post_id = get_queried_object_id();

        if ( ! $post_id && is_admin() ) {
            $post_id = absint( $_GET['post'] ?? 0 );
        }

        if ( ! self::is_restricted( $post_id ) ) {
            return;
        }

        foreach ( (array) $bar->get_nodes() as $node ) {
            if (
                stripos( $node->id, 'bricks' ) !== false ||
                (
                    ! empty( $node->href ) &&
                    stripos( $node->href, 'bricks=run' ) !== false
                )
            ) {
                $bar->remove_node( $node->id );
            }
        }
    }
}

register_activation_hook(
    __FILE__,
    [ 'Bricks_Access_Manager', 'activate' ]
);

Bricks_Access_Manager::init();

Just a thought: You could create a public github repo for this and share the link to it. :slight_smile:

When you say it, it seems the obvious choice. I feel awkward for not thinking about it earlier. Anyway, thank you for pointing it out.:folded_hands: