Every Mother

How to Limit a WordPress Editor to Specific Pages (Without a Plugin)

H

Standard WordPress roles are often too broad. But you don’t need a heavy permissions plugin to fix this.


Why Restrict the Editor Role? (The “Principle of Least Privilege”)

By default, a WordPress Editor can edit every page and post on your site. For many clients, this is a recipe for disaster. They want to hand-over some of the website updates to a consultant or the front-desk team, but not provide all access. Here’s a solution that uses PHP and can be added directly to your site using the Free Snippets plugin (or your functions.php).


Limit Editor Permissions PHP CodeSnippet for WordPress

While many “Role Editor” plugins exist, they are often overkill—bloating your database and requiring constant manual updates. This “Restrict Editors” script is a lightweight, set-it-and-forget-it solution. Here’s how it works.


Step 1: Find Your Page IDs

Before we can lock the doors, we need to know the address of the pages we want to leave open. There are two quick ways to find a Page ID in WordPress:

Method A: The “Hover” Trick

Go to Pages > All Pages. Hover your mouse over the title of the page you want to allow. Look at the very bottom-left corner of your browser (the status bar). You’ll see a URL that contains post=XXXX. That number is your ID.

Method B: The “Edit” Method

Click to Edit the page. Once the editor loads, look at your browser’s address bar at the top. The URL will look something like yoursite.com/wp-admin/post.php?post=1623&action=edit. 1623 is your ID.


Step 2: Implementation

You can add this code to your child theme’s functions.php file, but for a cleaner, safer workflow, I recommend using the WP Code Snippets plugin. It allows you to toggle the code on and off without risking a “White Screen of Death” if you make a typo. Make sure to set your script to “Run Everywhere” in Snippets, which is the default, and it will easily work to limit what EDITOR roles on your WordPress website can edit.

Copy the code below exactly. You will be editing lines 9 and 10 to fit your needs.

Step 3: Customizing the Logic (Lines 9 & 10)

This script is built to be flexible. Here is how to configure it for your specific project:

  • To Allow a “Directory” (Parent and Children): If you have a main “Gallery” page (ID 2133) and you want every single page nested under it to be editable, put that ID on Line 10. If you don’t need any other random pages, you can comment out or delete Line 9.
  • To Allow a Single Page: On Line 9, replace 1623 with your ID. If you don’t have a “directory” or parent page, simply delete Line 10 or turn it into a comment by adding // at the very beginning of the line.
  • To Allow Multiple Pages: You can add as many IDs as you want to the brackets, separated by commas. Example: $allowed_individual_ids = [1623, 1624, 1700];

The “Editor Permissions” Script

PHP

/**
 * Restrict Editors to Specific Pages & Directories
 * Author: DesignerToFullStack.com
 */

add_action('init', function() {

    // --- CONFIGURATION: DROP YOUR IDS HERE ---
    $allowed_individual_ids = [1623]; // Line 9: Individual Pages
    $allowed_directory_ids  = [2133]; // // Line 10: Parent Pages (Directories)
    // -----------------------------------------

    // 1. PERMISSIONS: The Hard Lockdown
    add_filter( 'map_meta_cap', function( $caps, $cap, $user_id, $args ) use ($allowed_individual_ids, $allowed_directory_ids) {

        $edit_caps = ['edit_post', 'delete_post', 'edit_page', 'delete_page', 'edit_others_pages', 'edit_published_pages'];
        if ( ! in_array( $cap, $edit_caps, true ) ) return $caps; 

        $user = get_userdata( $user_id );
        if ( ! $user || ! in_array( 'editor', (array) $user->roles, true ) ) return $caps; 

        $post_id = isset( $args[0] ) ? intval( $args[0] ) : 0;
        if ( ! $post_id ) return $caps;

        // Allow if in individual list
        if ( in_array( $post_id, $allowed_individual_ids ) ) return $caps;

        // Allow if in directory list or is a child/descendant
        if ( in_array( $post_id, $allowed_directory_ids ) ) return $caps;
        
        $ancestors = get_post_ancestors( $post_id );
        foreach ( $allowed_directory_ids as $dir_id ) {
            if ( in_array( $dir_id, $ancestors ) ) return $caps;
        }

        // Slam the door on everything else
        return [ 'do_not_allow' ];
    }, 10, 4 );

    // 2. VISIBILITY: The "All Pages" Filter
    add_filter( 'pre_get_posts', function( $query ) use ($allowed_individual_ids, $allowed_directory_ids) {
        if ( ! is_admin() || ! $query->is_main_query() ) return;

        global $pagenow;
        if ( $pagenow !== 'edit.php' || $query->get('post_type') !== 'page' ) return;

        if ( ! current_user_can('editor') ) return;

        // Dynamically find all children of allowed directories
        $all_allowed = $allowed_individual_ids;
        foreach ( $allowed_directory_ids as $parent_id ) {
            $all_allowed[] = $parent_id;
            $children = get_posts([
                'post_type' => 'page',
                'post_parent' => $parent_id,
                'posts_per_page' => -1,
                'post_status' => 'any',
                'fields' => 'ids',
            ]);
            $all_allowed = array_merge($all_allowed, (array)$children);
        }

        $query->set( 'post__in', array_unique($all_allowed) );
        $query->set( 'hierarchical', false ); // Force flat list so children show up
    });
});

FAQ: Common Permission Questions

Can I limit a WordPress user to just one page?

Yes. By using the allowed_individual_ids array in our script, you can lock a user down to a single ID. They won’t even see the other pages in their list.

How do I restrict access to child pages automatically?

Our script uses get_post_ancestors. This means if you allow a “Parent” page, the Editor automatically gets permission for every child and grandchild page added under that parent.

Will this hide the pages from the Admin menu?

This script filters the “All Pages” list. While the “Pages” link still exists in the sidebar, clicking it will only show the authorized pages. To hide the sidebar menu items entirely, you can use remove_menu_page().


Why Most Plugins are Overkill

1. Capability vs. Context (The “What” vs. The “Which”)

Most WordPress permission plugins (like User Role Editor or Members) are built around Capabilities. They answer the question: “Can this user edit pages?”

They are not naturally built to answer the question: “Can this user edit this specific page ID?”

  • The Plugin Way: You often have to buy a “Pro” version to get “Content Restriction” or “Post-Level” permissions.
  • The Full Stack Way: Using the map_meta_cap hook allows us to intercept the request at the exact moment WordPress asks, “Is this allowed?” and check the Context (the ID) rather than just the Role.

2. The “New Page” Maintenance Trap

This is the biggest reason standard plugins fail for “Directories” (like your Before-and-After section).

  • With a plugin, every time the client adds a new “child” page, you (the dev) usually have to log back in and manually check a box to give the Editor permission to that new ID.
  • Our script is dynamic. By checking for the post_parent or ancestors, the code automatically “adopts” any new pages the client creates. It’s a “set and forget” solution.

3. Performance & Technical Debt

Every plugin you install is another “cook in the kitchen.”

  • Database Bloat: Large permission plugins often create their own custom tables or add hundreds of rows to your wp_options table to track granular settings.
  • Loading Overhead: These plugins run complex logic checks on every page load, even for visitors on the front end who aren’t even logged in.
  • The Update Cycle: Plugins are a liability. Every time WordPress updates, a complex plugin has a chance of breaking. A 30-line PHP snippet using core WordPress hooks is virtually future-proof.

4. The “Hidden Page” UX Conflict

As you discovered, many plugins might stop someone from editing a page, but they are terrible at hiding the pages from the list. The client ends up seeing a list of 50 pages they “can’t touch,” which is confusing and makes the dashboard feel cluttered. By using pre_get_posts in our script, we aren’t just locking the door; we’re making the other houses on the street invisible. This creates a much cleaner “SaaS-like” experience for the client.

Many developers reach for plugins like “User Role Editor” for this task. The problem? Those plugins are designed to manage Capabilities (the what), not Context (the which).

With a plugin, you often have to manually check a box every time the client adds a new child page. With our code-first approach, the script automatically “adopts” any new children added to your directory ID. It’s cleaner, faster, and doesn’t add any extra weight to your database.


Happy WordPressing!

About the author

Kelly Barkhurst

Designer to Fullstack is my place to geek out and share tech solutions from my day-to-day as a graphic designer, programmer, and business owner (portfolio). I also write on Arts and Bricks, a parenting blog and decal shop that embraces my family’s love of Art and LEGO bricks!

By Kelly Barkhurst April 30, 2026

Recent Posts

Archives

Categories