---
tags:
  - wordpress
  - fse
  - php
  - governance
  - templates
  - locking
title: Governance: Enforcing Block Templates for Custom Post Types
---

# Governance: Enforcing Block Templates for Custom Post Types

In a Block Theme, the global site layout (Header, Footer, Sidebar) is controlled by HTML files in the `templates/` folder.

However, you often want to control the **Content Area** itself. For example, ensuring every "Case Study" starts with a specific Cover Image and Heading structure, and preventing the client from deleting them, effectively turning the Block Editor into a structured data form.

This is done via PHP when registering the Custom Post Type (CPT).

## 1. The `template` Argument

When you register a CPT using `register_post_type()`, you can pass a `template` array. This defines the initial blocks that appear when a user clicks "Add New".

```php
'template' => array(
    array( 'core/cover', array( 'overlayColor' => 'black' ) ),
    array( 'core/heading', array( 'placeholder' => 'Case Study Title' ) ),
    array( 'core/paragraph', array( 'placeholder' => 'Write the summary here...' ) ),
),
```

## 2. The `template_lock` Argument

By default, the template just provides a starting point. Users can delete the blocks. To enforce structure, use `template_lock`.

*   **`'all'`**: Strict. Users cannot add new blocks, remove blocks, or reorder blocks. They can *only* edit the content/attributes of the existing blocks.
*   **`'insert'`**: Users cannot add *new* blocks or remove existing ones, but they can move them (rarely used).
*   **`false`**: (Default) No locking.

## 3. Real World Example: "Team Member" CPT

Let's create a "Team Member" CPT where the layout is strictly locked:
1.  **Image:** (Locked)
2.  **Name:** (Heading, Locked)
3.  **Bio:** (Paragraph, Locked)
4.  **Social Links:** (Social Icons, Locked)

```php
function my_register_team_cpt() {
    $args = array(
        'label'        => 'Team',
        'public'       => true,
        'show_in_rest' => true, // Required for Block Editor
        'supports'     => array( 'title', 'editor', 'thumbnail' ), // 'editor' is required
        
        // Define the fixed block structure
        'template' => array(
            array( 'core/image', array(
                'align' => 'center',
            ) ),
            array( 'core/heading', array( 
                'placeholder' => 'Full Name',
                'level'       => 2,
                'textAlign'   => 'center'
            ) ),
            array( 'core/paragraph', array( 
                'placeholder' => 'Job Title & Bio...',
                'align'       => 'center'
            ) ),
            array( 'core/social-links', array( 'layout' => array( 'type' => 'flex', 'justifyContent' => 'center' ) ), array(
                array( 'core/social-link', array( 'service' => 'linkedin' ) ),
                array( 'core/social-link', array( 'service' => 'twitter' ) ),
            ) ),
        ),
        
        // Lock the entire container
        'template_lock' => 'all', 
    );
    register_post_type( 'team_member', $args );
}
add_action( 'init', 'my_register_team_cpt' );
```

## 4. Nested Templates (The "Container" Strategy)

If you want a locked "Hero" section at the top, but want to allow free-form editing below it, you cannot use `template_lock => 'all'` on the CPT itself, as that locks the entire post.

**The Solution:** Use a **Group** block as a container in your template, and lock *that specific block* using nested locking logic.

```php
'template' => array(
    // 1. Locked Hero Section (Group Block)
    array( 'core/group', array( 
        'tagName' => 'section',
        'templateLock' => 'all', // Locks children inside this group
        'lock' => array( 'remove' => true, 'move' => true ) // Prevents deleting this group
    ), array(
        array( 'core/heading', array( 'content' => 'Mandatory Header' ) ),
    ) ),

    // 2. Free editing area (A paragraph to start)
    array( 'core/paragraph', array( 'placeholder' => 'Add free-form content here...' ) ),
),
'template_lock' => false, // Allow adding blocks at the root level (below the hero)
```