Frontend Course Builder for Instructors

The Instructor Frontend Builder is for sites that want instructors creating and managing course content from the frontend instead of working inside wp-admin. It gives you a dedicated instructor dashboard, a scope manager page, and an editor page, all built with Bricks, while BricksMembers still enforces the structure, permissions, and publishing rules behind the scenes.

This guide is intentionally detailed. The feature works very well, but only when the setup is done in the right order. If you skip the structure rules, assign the wrong pages, or build the Bricks pages without understanding what each page is supposed to do, the frontend experience will feel broken. The goal here is to help you set it up correctly the first time.

What the Feature Actually Does

The runtime is built around three frontend page roles:

  • Dashboard page for listing the top-level scopes an instructor is allowed to manage, such as courses, programs, or cohorts
  • Manager page for opening one validated scope and managing the items inside that structure tree
  • Editor page for creating or editing a single structure item through frontend forms

BricksMembers does not just expose raw WordPress editing on the frontend. It validates the current instructor, validates the selected structure, validates the current scope, and then feeds Bricks the correct request context, dynamic tags, query loops, and form actions for that page.

Before You Start

Before you touch the Frontend Course Builder page or the Bricks pages, make sure these basics are already in place:

  • You are using Bricks and can edit normal WordPress pages with it.
  • You already created the BRM structure you want instructors to manage.
  • Every level in that structure is a post type. The frontend builder does not support mixed structures here.
  • If you enable more than one structure, they must not share the same first-level post type.
  • The WordPress role you want to use for instructors has the normal edit_posts capability.

That last point matters more than many people expect. The allowed role list on the admin page can still show roles that do not have edit_posts, but those roles are blocked by the runtime. So if you want a custom Instructor role to work here, make sure it can edit posts.

How Access Works

The Instructor Frontend Builder uses two access checks at the same time.

  • The user must have one of the allowed WordPress roles from the Frontend Course Builder settings.
  • The user must also be allowed to manage the specific top-level scope they are trying to open.

Per-scope access is controlled on the top-level scope post itself through the Instructor Frontend Access meta box. If you leave that box empty, the original author of the top-level scope is the default frontend manager. If you assign one or more users there, only those selected users can manage that scope from the frontend.

This is what makes the feature suitable for multi-instructor sites. One instructor can manage Course A, another can manage Course B, and neither needs broad access to the whole backend.

Step 1: Enable the Module

  1. Go to BricksMembers → Modules.
  2. Enable Instructor Frontend Builder.
  3. Confirm the change.
  4. Open BricksMembers → Frontend Course Builder.

The current admin page label is Frontend Course Builder. If you are following older notes that mention a Settings submenu or an older Instructor Builder location, ignore them.

Step 2: Prepare the Structure You Want Instructors to Manage

The frontend builder does not invent a structure for you. It sits on top of your existing BRM structures. Before moving forward, confirm the structure is already correct.

  • The first level is the top-level scope, usually something like a course or program.
  • The child levels are the items instructors will manage inside that scope, such as modules, lessons, or chapters.
  • Every level is backed by a real WordPress post type.
  • If you enable more than one structure, each enabled structure starts with a different first-level post type.

If the first level or any child level is not a post type, or if two enabled structures both start with the same top-level post type, the settings save will reject the selection.

Step 3: Create the Three WordPress Pages First

Before you start importing Bricks JSON, create the pages that will host the frontend runtime. You need three normal WordPress pages:

  • Instructor Dashboard
  • Instructor Manager
  • Instructor Editor

You can use different page names if you want, but keeping them obvious makes the setup easier. Publish or save those pages first. After that, BricksMembers can assign them from the Frontend Course Builder settings.

Step 4: Configure the Frontend Course Builder Page

Now go to BricksMembers → Frontend Course Builder. This page has three important sections: Page Setup, Runtime Configuration, and Template Exports.

Page Setup

Assign the three WordPress pages you created:

  • Dashboard Page lists the top-level scopes the current instructor can manage.
  • Manager Page opens one validated scope tree and shows row-level actions for that scope.
  • Editor Page handles both create and edit requests for one item at a time.

These page assignments are not cosmetic. The runtime gate looks at the current page ID and decides whether the request is a dashboard, manager, or editor request. If the wrong page is assigned here, the Bricks layout may load but the runtime context will be wrong.

Runtime Configuration

  • Allow instructors to publish content from the frontend controls whether instructors may publish, move back to draft, or otherwise change publish state from the frontend.
  • Allowed Roles defines which WordPress roles may use the frontend builder at all.
  • Enabled Structures defines which BRM structures the frontend builder may expose.

If direct publishing is disabled, instructors can still create, edit, and reorder content, but new items stay in draft and publish-level status changes are blocked. This is ideal when instructors prepare content and an admin reviews the final publish step.

Page Roles

The Instructor Frontend Builder setup uses three Bricks page roles. Current production builds do not ship ready-made Bricks JSON exports, so build these pages directly in Bricks:

  • Dashboard page — lists enabled structures and manageable scopes
  • Manager page — shows the structure tree and row actions
  • Editor page — contains the create/edit form

The main setup path is to understand what each page must do, then wire the query loops, dynamic tags, conditions, and form actions yourself in Bricks Builder.

After assigning the pages and runtime settings, click Save Settings.

Step 5: Assign Which Instructor Can Manage Which Scope

This is the step many people miss. Enabling the module and choosing allowed roles is not enough. You still have to define who can manage each top-level scope.

  1. Edit a top-level scope post for one of the enabled structures. In a course-style setup, this is usually the course post itself.
  2. Open the Instructor Frontend Access meta box.
  3. Leave it empty if the scope author should be the default frontend manager.
  4. Or select one or more users if you want explicit frontend managers for that scope.
  5. Update the post.

As soon as you assign one or more users there, only those selected users can manage that scope from the frontend. Everyone else is blocked, even if their role is allowed globally.

Step 6: Build the Three Bricks Pages

Now move into Bricks and build the three assigned pages intentionally. The important thing is not whether you use a template. The important thing is that each page contains the right BRM query loops, links, dynamic tags, conditions, and forms for its job in the runtime.

  1. Open the Dashboard page in Bricks.
  2. Build a layout for enabled-structure cards and manageable scopes.
  3. Open the Manager page in Bricks.
  4. Build a layout for one validated scope header plus the structure item rows and row actions.
  5. Open the Editor page in Bricks.
  6. Build a create/edit page with the correct BRM form actions and hidden field mappings.

Do not think of this as “design three normal pages and hope BRM picks them up.” These pages are runtime surfaces. The dashboard must expose the correct scope and structure links, the manager page must work from a valid brm_scope request, and the editor page must work from a valid create or edit request context.

Optional Shortcut: Import the Exported Templates

If you want a faster starting point, you can import the optional JSON exports after creating the pages:

  • instructor-dashboard.json for the Dashboard page
  • instructor-manager.json for the Manager page
  • instructor-editor.json for the Editor page

The import is only a shortcut. It does not assign the pages automatically. The actual page assignment still comes from BricksMembers → Frontend Course Builder.

Step 7: Understand the Dashboard Page

The dashboard page does two jobs:

  • It shows enabled structure cards so instructors can start new top-level scopes when they are allowed to create them.
  • It shows the list of existing scopes the current instructor is allowed to manage.

If you build the dashboard manually, these are the two BRM Query Loop types you need:

  • BRM: Instructor Enabled Structures
  • BRM: Instructor Scopes

The most important dynamic tags on the dashboard are:

  • {brm_instructor:enabled_structure_name}
  • {brm_instructor:enabled_structure_scope_label}
  • {brm_instructor:enabled_structure_levels_label}
  • {brm_instructor:enabled_structure_create_url}
  • {brm_instructor:scope_structure_name}
  • {brm_instructor:scope_status_label}
  • {brm_instructor:scope_item_count}
  • {brm_instructor:scope_draft_count}
  • {brm_instructor:manager_url}
  • {brm_instructor:row_manager_url}

Your dashboard links must send the instructor to the manager page with the correct scope context. The important part is that the link has to be built inside the BRM: Instructor Scopes query loop, because that is where Bricks knows which scope card it is currently rendering.

  1. Add your scope cards inside a BRM: Instructor Scopes query loop.
  2. Inside that same loop item, add a Button, Text, or Link element for “Open manager”.
  3. Set its URL to {brm_instructor:row_manager_url} if you want the simplest setup.
  4. If you are writing a custom HTML link instead, you can also use {brm_instructor:manager_url}?brm_scope=4239.

Here is what those values mean:

  • {brm_instructor:row_manager_url} is the fully prepared manager URL for the current scope row, already including the correct brm_scope value.
  • {brm_instructor:manager_url} is only the base manager page URL.
  • 4239 inside that query loop is the current scope post ID.

So the safest recommendation is: if you are building the dashboard yourself, put the “Open manager” link inside the scope loop and use {brm_instructor:row_manager_url}. Do not place one static manager button outside the loop, because it will not know which scope to open.

Step 8: Understand the Manager Page

The manager page is where instructors spend most of their time. It opens one validated top-level scope and exposes the child items in that structure tree.

The manager page needs a header area for scope-level actions and a query loop for the actual structure rows. If you build it manually, the required query type is BRM: Instructor Structure Items.

The important scope-level dynamic tags are:

  • {brm_instructor:scope_title}
  • {brm_instructor:scope_structure_name}
  • {brm_instructor:scope_status_label}
  • {brm_instructor:scope_item_count}
  • {brm_instructor:scope_draft_count}
  • {brm_instructor:scope_edit_url}
  • {brm_instructor:scope_top_level_label}
  • {brm_instructor:scope_top_level_create_url}
  • {brm_instructor:scope_child_level_label}
  • {brm_instructor:scope_child_create_url}
  • {brm_instructor:dashboard_url}

The important row-level dynamic tags are:

  • {brm_instructor:item_id}
  • {brm_instructor:item_title}
  • {brm_instructor:item_excerpt}
  • {brm_instructor:item_content}
  • {brm_instructor:item_video_url}
  • {brm_instructor:item_video_duration}
  • {brm_instructor:item_level_label}
  • {brm_instructor:item_status_label}
  • {brm_instructor:item_children_count}
  • {brm_instructor:item_depth}
  • {brm_instructor:row_edit_url}
  • {brm_instructor:row_child_create_url}
  • {brm_instructor:child_level_label}
  • {brm_instructor:child_level_index}

The manager page also uses BRM conditions in Bricks to show or hide controls. The most important ones are:

  • Instructor can publish
  • Instructor scope has child level
  • Instructor can create top-level item
  • Instructor scope is published
  • Instructor scope is draft
  • Instructor item can have children
  • Instructor item is first sibling
  • Instructor item is last sibling
  • Instructor item is published
  • Instructor item is draft

Use those conditions to hide impossible actions. For example, hide “move up” on the first sibling, hide “move down” on the last sibling, and hide publish controls when instructor publishing is disabled.

How to Build the Manager Row Actions

This is the part that usually confuses people: the action buttons in the manager rows are not all built the same way.

  • Edit and Add child are normal links.
  • Move up, Move down, Publish, Move to draft, and Trash are best built as small Bricks Form elements.

That means a “button” like Move Up is really a form with only hidden fields plus its submit button. The form submits the hidden values to the BRM action handler, and the submit button is what the instructor clicks.

Also, these row actions must be placed inside the BRM: Instructor Structure Items query loop. If they sit outside the loop, they do not know which item row they belong to.

In Bricks, select the Form element first, then choose the BRM action in the form actions setting. Only after you do that will the extra BRM mapping controls appear for that form. If you do not see fields like Post ID Hidden Field ID or Direction Hidden Field ID, the BRM action has not been selected yet.

Another important behavior: Move Up and Move Down now behave differently from the status actions. When an instructor clicks a reorder form, BricksMembers swaps the rows in place, animates that movement, and then refreshes the manager query loop behind the scenes so the correct first-row and last-row controls appear. The instructor stays on the same manager URL for that scope.

Publish, Move to draft, and Trash still use the redirect flow back to the same manager scope after the form is processed. So you still do not need to build your own refresh logic for any of these actions. You only need the correct BRM form action, hidden fields, and conditions.

How to Build the Edit and Add Child Links

  1. Inside the BRM: Instructor Structure Items query loop, add a Button, Text, or Link element for Edit.
  2. Set its URL to {brm_instructor:row_edit_url}.
  3. If you only want it visible when editing is allowed, add conditions that match your authoring rules: show it when the item is draft, or when the item is published and Instructor can publish is true.
  4. Add another Button, Text, or Link element for Add child.
  5. Set its URL to {brm_instructor:row_child_create_url}.
  6. Add the Bricks condition Instructor item can have children equals Yes so it only appears when a deeper level actually exists.

How to Build the Move Up Button

  1. Inside the structure item loop, add a Form element where the Move Up button should appear.
  2. In the form settings, set the action to Instructor Reorder Item (BRM).
  3. In the BRM Instructor Reorder mapping controls, set Post ID Hidden Field ID to post_id.
  4. Set Direction Hidden Field ID to direction.
  5. In the form fields list, add a hidden field with ID post_id and value {brm_instructor:item_id}.
  6. Add a second hidden field with ID direction and value up.
  7. Style the form submit button so it looks like your Move Up button.
  8. Add a Bricks condition so the form only shows when Instructor item is first sibling equals No.

That last condition is what prevents the first row from showing a useless Move Up button.

How to Build the Move Down Button

Build it exactly like Move Up, but change two things:

  • Set the hidden direction field value to down.
  • Show the form only when Instructor item is last sibling equals No.

So the up and down buttons are not one shared form. They are two separate small forms, each with its own fixed direction value.

How to Build the Publish, Draft, and Trash Buttons for Each Item

These also live inside the structure item loop, and each button is its own Bricks Form element.

  1. Add a Form element for the action you want, for example Publish.
  2. Set the action to Instructor Change Status (BRM).
  3. In the BRM Instructor Status mapping controls, set Post ID Hidden Field ID to post_id.
  4. Set Action Hidden Field ID to status_action.
  5. Add a hidden field with ID post_id and value {brm_instructor:item_id}.
  6. Add a hidden field with ID status_action and set its value to publish, draft, or trash, depending on that form.
  7. Style the submit button so it looks like the action button you want the instructor to click.

Then control visibility with conditions:

  • Publish: show only when Instructor item is draft is yes and Instructor can publish is yes.
  • Move to draft: show only when Instructor item is published is yes and Instructor can publish is yes.
  • Trash: show when the item is draft, or when the item is published and Instructor can publish is yes.

If you skip those conditions, the forms may still exist technically, but the instructor will see buttons that do not make sense in the current state.

How to Build the Scope-Level Publish Buttons

The top-level scope controls in the manager header work the same way as the row status controls, but they do not live inside the row query loop.

  1. Add a Form element in the manager page header area for Publish Scope, Move Scope to Draft, or Trash Scope.
  2. Set the action to Instructor Change Status (BRM).
  3. Map Post ID Hidden Field ID to post_id and Action Hidden Field ID to status_action.
  4. Use {brm_instructor:scope_id} as the hidden post_id value.
  5. Set the hidden status_action value to publish, draft, or trash.
  6. Apply the matching scope conditions such as Instructor scope is draft, Instructor scope is published, and Instructor can publish.

The only real difference is which dynamic tag you use for the hidden post ID field. For scope-level actions it is {brm_instructor:scope_id}. For row-level item actions it is {brm_instructor:item_id}.

Step 9: Understand the Editor Page

The editor page handles both create and edit flows on one page. The runtime decides which mode the page is in based on the validated query parameters.

The editor page should contain separate create and update forms, with the correct BRM form actions and field mappings. If you build the page by hand, these are the pieces that must be correct.

Important Bricks detail: the extra BRM field-mapping controls only appear after you select the BRM action on the Form element. So pick Instructor Create Item (BRM) or Instructor Update Item (BRM) first, then look for the BRM mapping section in that form’s settings.

Create vs Edit Mode

Use the Bricks condition Instructor request mode to show the right form for the current request:

  • Show the create form when the request mode is Create.
  • Show the update form when the request mode is Edit.

The editor request uses these runtime query variables: brm_mode, brm_structure, brm_level, brm_scope, brm_parent, and, for edits, brm_item. You usually do not type those manually because the dashboard and manager links generate them for you.

The Create Form

Create a Bricks Form using the Form element. The form action must be Instructor Create Item (BRM). A clean manual setup usually maps these field IDs:

  • title
  • content
  • excerpt
  • video_url
  • video_duration
  • structure_id as a hidden field
  • scope_id as a hidden field
  • parent_id as a hidden field
  • level_index as a hidden field

Those hidden fields should be filled from the instructor dynamic tags:

  • {brm_instructor:structure_id}
  • {brm_instructor:scope_id}
  • {brm_instructor:parent_id}
  • {brm_instructor:level_index}

For non-top-level creates, the parent, scope, structure, and level must all match the validated runtime context. If they do not, the create request is rejected.

If you build a child-create form directly inside a manager row popup or bottom panel, use {brm_instructor:item_id} for the hidden parent_id field and {brm_instructor:child_level_index} for the hidden level_index field. The row action should only be visible when Instructor item can have children is true.

How to Build the Create Form Step by Step

  1. Add a Form element to the Editor page.
  2. Set the form action to Instructor Create Item (BRM).
  3. Add normal visible fields for title, excerpt, content, video URL, and video duration.
  4. Give those visible fields the IDs title, excerpt, content, video_url, and video_duration.
  5. Add hidden fields with the IDs structure_id, scope_id, parent_id, and level_index.
  6. Fill those hidden fields with {brm_instructor:structure_id}, {brm_instructor:scope_id}, {brm_instructor:parent_id}, and {brm_instructor:level_index}.
  7. In the BRM Instructor Create mapping controls, point each mapping to the field ID you used.
  8. Set a clear submit button label such as “Create lesson”, “Create module”, or “Create item”.
  9. Add a Bricks condition so this form only shows when Instructor request mode equals Create.

That is the full pattern. Visible fields collect the content. Hidden fields tell BRM exactly where in the structure the new item belongs.

If you extend the editor form with media fields, the BRM create action also supports field mappings for a featured image and a video image.

The Update Form

The form action must be Instructor Update Item (BRM). A clean manual setup usually maps these field IDs:

  • title
  • content
  • excerpt
  • video_url
  • video_duration
  • post_id as a hidden field

The editor page update form pre-fills its fields from the runtime dynamic tags, including:

  • {brm_instructor:editor_title}
  • {brm_instructor:editor_excerpt}
  • {brm_instructor:editor_content}
  • {brm_instructor:editor_video_url}
  • {brm_instructor:editor_video_duration}
  • {brm_instructor:item_id}

If you build the update form inside a manager row popup instead of on the editor page, prefill the visible fields with the row item tags: {brm_instructor:item_title}, {brm_instructor:item_excerpt}, {brm_instructor:item_content}, {brm_instructor:item_video_url}, and {brm_instructor:item_video_duration}. Keep the hidden post_id field set to {brm_instructor:item_id}.

If publishing is disabled globally, already published items cannot be edited from this page. That block happens server-side, even if you expose the form visually.

How to Build the Update Form Step by Step

  1. Add a second Form element to the Editor page.
  2. Set its action to Instructor Update Item (BRM).
  3. Add visible fields for title, excerpt, content, video URL, and video duration.
  4. Give them the IDs title, excerpt, content, video_url, and video_duration.
  5. Prefill those fields with {brm_instructor:editor_title}, {brm_instructor:editor_excerpt}, {brm_instructor:editor_content}, {brm_instructor:editor_video_url}, and {brm_instructor:editor_video_duration}.
  6. Add one hidden field with ID post_id and value {brm_instructor:item_id}.
  7. In the BRM Instructor Update mapping controls, point the mappings to those same field IDs.
  8. Add a Bricks condition so this form only shows when Instructor request mode equals Edit.

So the create form tells BRM where to make a new item, while the update form tells BRM which existing item ID to update.

The update action can also map optional featured image and video image fields if you add them to your custom Bricks form.

Step 10: Understand the Row Action Forms on the Manager Page

The manager page needs working forms for status changes and reordering. If you build or redesign that page, make sure you preserve the BRM form actions and hidden field mappings.

The easiest mental model is this:

  • Every reorder button is its own tiny form.
  • Every publish, draft, or trash button is its own tiny form.
  • The hidden fields carry the item ID and the action value.
  • The form submit button is the visible button the instructor clicks.

For status changes, use the action Instructor Change Status (BRM) and map:

  • post_id as the post ID hidden field
  • status_action as the action hidden field

The allowed values for the status action are publish, draft, and trash.

For reordering, use the action Instructor Reorder Item (BRM) and map:

  • post_id as the post ID hidden field
  • direction as the direction hidden field

The allowed direction values are up and down.

The setup works as long as the form actions, hidden field IDs, query loops, links, and conditions are configured correctly.

If a button “looks right” but does nothing useful, the problem is almost always one of these:

  • the form is outside the correct query loop
  • the hidden field ID does not match the BRM mapping field
  • the hidden field value is wrong or empty
  • the wrong BRM action was selected
  • the visibility condition hides or shows the action at the wrong time

What Happens on the Frontend

Once the setup is finished, the runtime handles the page protection for you.

  • If a visitor is not logged in and opens one of the assigned instructor pages, they are redirected to the login screen with a return URL.
  • If a logged-in user does not have an allowed role, the page returns a forbidden response.
  • If the user has an allowed role but tries to open a scope they are not allowed to manage, the manager request is blocked.
  • If the editor request does not contain a valid create or edit context, the editor page is blocked.

This is why the feature is safe to expose publicly as part of your site navigation. The pages themselves can exist like normal pages, but the runtime only resolves valid instructor requests.

Recommended Test Flow

After setup, test the whole flow with a real instructor account, not your admin account.

  1. Log in as a user with one of the allowed instructor roles.
  2. Open the Dashboard page and confirm you can see the correct scopes and create-entry cards.
  3. Open one scope in the Manager page and confirm the correct tree loads.
  4. Create a new child item from the Manager page.
  5. Edit an existing draft item from the Editor page.
  6. Reorder one item up or down from the Manager page.
  7. If publishing is enabled, test publish and move-to-draft actions.
  8. If publishing is disabled, confirm new items stay in draft and publish controls are not available.
  9. Test a second instructor account and confirm they only see the scopes assigned to them.

Common Mistakes

  • The page loads but shows nothing: the assigned page may be wrong, the structure may not be enabled, or the current user may not manage any scopes.
  • An instructor can log in but still gets blocked: their role may lack edit_posts, or they are not assigned to that top-level scope.
  • The manager page opens but actions fail: the Bricks forms may have lost their BRM action mapping or hidden field IDs during customization.
  • Create links go to the editor page but the request is rejected: the request is missing required context such as structure, level, scope, or parent.
  • Two structures cannot be enabled together: they probably share the same first-level post type, which the frontend builder does not allow.
  • Published content cannot be edited: direct instructor publishing is disabled, so published items are locked from frontend editing.

The Best Way to Customize It

The most reliable way to customize the Instructor Frontend Builder is to understand the runtime first, then design around it. Build the three pages so they use the correct BRM queries, tags, conditions, and actions.

If you understand the query types, dynamic tags, conditions, and form actions described in this guide, you can build the full instructor experience yourself in Bricks.

Early Bird Deal

Start Building Your Membership Site Today

Create, sell, and manage your content without limits. BricksMembers gives you everything you need to build membership and LMS sites with Bricks Builder.

Lifetime updates & bug fixes • Premium support • 0% transaction fees • 60-day money-back guarantee