/**
* Proto-Blocks Templates Knowledge Module
* Complete documentation for PHP template patterns
*/
export function getTemplatesKnowledge() {
return `# Proto-Blocks Template Patterns: Complete Guide
PHP templates are the heart of Proto-Blocks. They define how your block renders both in the editor and on the frontend.
---
## Template Variables
Your template receives three variables:
| Variable | Type | Description |
|----------|------|-------------|
| \`$attributes\` | array | All field and control values (camelCase keys) |
| \`$content\` | string | Inner blocks HTML (if using inner blocks) |
| \`$block\` | WP_Block\\|null | Block instance (null during editor preview) |
---
## Basic Template Structure
\`\`\`php
<?php
/**
* Block Template: My Block
*
* @var array $attributes Block attributes
* @var string $content Inner blocks content
* @var WP_Block $block Block instance
*/
// 1. Extract attributes with defaults
$title = $attributes['title'] ?? 'Default Title';
$content = $attributes['content'] ?? '';
$layout = $attributes['layout'] ?? 'default';
// 2. Detect preview mode (optional)
$is_preview = !isset($block) || $block === null;
// 3. Build wrapper attributes
$wrapper_attributes = get_block_wrapper_attributes([
'class' => 'my-block my-block--' . $layout,
]);
?>
<!-- 4. Render HTML with data attributes -->
<div <?php echo $wrapper_attributes; ?>>
<h2 class="my-block__title" data-proto-field="title">
<?php echo esc_html($title); ?>
</h2>
<div class="my-block__content" data-proto-field="content">
<?php echo wp_kses_post($content); ?>
</div>
</div>
\`\`\`
---
## The get_block_wrapper_attributes() Function
This WordPress function is essential for Proto-Blocks. It:
1. Applies WordPress block supports (colors, spacing, typography)
2. Adds the block's unique class name
3. Handles alignment classes
4. Applies custom class names from the block settings
### Basic Usage
\`\`\`php
<?php
$wrapper_attributes = get_block_wrapper_attributes();
?>
<div <?php echo $wrapper_attributes; ?>>
Content
</div>
\`\`\`
### With Custom Classes
\`\`\`php
<?php
$layout = $attributes['layout'] ?? 'default';
$wrapper_attributes = get_block_wrapper_attributes([
'class' => 'my-block my-block--' . esc_attr($layout),
]);
?>
<section <?php echo $wrapper_attributes; ?>>
Content
</section>
\`\`\`
### With Inline Styles
\`\`\`php
<?php
$min_height = $attributes['minHeight'] ?? 400;
$bg_color = $attributes['backgroundColor'] ?? '';
$styles = [];
if ($min_height) {
$styles[] = "min-height: {$min_height}px";
}
if ($bg_color) {
$styles[] = "background-color: {$bg_color}";
}
$wrapper_attributes = get_block_wrapper_attributes([
'class' => 'hero-section',
'style' => implode('; ', $styles),
]);
?>
<section <?php echo $wrapper_attributes; ?>>
Content
</section>
\`\`\`
---
## Data Binding Attributes
Proto-Blocks uses \`data-proto-*\` attributes to create editable regions.
### Field Binding
\`\`\`php
<!-- Text field -->
<h2 data-proto-field="title"><?php echo esc_html($title); ?></h2>
<!-- WYSIWYG field -->
<div data-proto-field="content"><?php echo wp_kses_post($content); ?></div>
<!-- Image field -->
<img data-proto-field="image" src="<?php echo esc_url($image['url']); ?>" />
<!-- Link field -->
<a data-proto-field="link" href="<?php echo esc_url($link['url']); ?>">
<?php echo esc_html($link['text']); ?>
</a>
\`\`\`
### Repeater Binding
\`\`\`php
<!-- Container with data-proto-repeater -->
<ul data-proto-repeater="items">
<?php foreach ($items as $item) : ?>
<!-- Each item with data-proto-repeater-item -->
<li data-proto-repeater-item>
<!-- Nested fields with data-proto-field -->
<h3 data-proto-field="title"><?php echo esc_html($item['title']); ?></h3>
<p data-proto-field="description"><?php echo wp_kses_post($item['description']); ?></p>
</li>
<?php endforeach; ?>
</ul>
\`\`\`
### Inner Blocks Binding
\`\`\`php
<!-- Container with data-proto-inner-blocks -->
<div class="content-area" data-proto-inner-blocks>
<?php echo $content; ?>
</div>
\`\`\`
---
## Escaping Output
Always escape output based on the content type:
| Function | Use For | Example |
|----------|---------|---------|
| \`esc_html()\` | Plain text | Titles, labels |
| \`esc_attr()\` | HTML attributes | Classes, IDs |
| \`esc_url()\` | URLs | Links, images |
| \`wp_kses_post()\` | Rich HTML content | WYSIWYG output |
| \`wp_kses()\` | Custom allowed HTML | Filtered content |
### Examples
\`\`\`php
<?php
// Plain text
echo esc_html($attributes['title']);
// Attribute values
echo '<div class="' . esc_attr($class) . '">';
// URLs
echo '<a href="' . esc_url($link['url']) . '">';
// Rich content
echo wp_kses_post($attributes['content']);
// Image with multiple escaping
?>
<img
src="<?php echo esc_url($image['url']); ?>"
alt="<?php echo esc_attr($image['alt']); ?>"
class="<?php echo esc_attr($class); ?>"
/>
\`\`\`
---
## Handling Empty Values
Always provide defaults and handle empty states:
### Null Coalescing
\`\`\`php
<?php
// Simple defaults
$title = $attributes['title'] ?? 'Default Title';
$count = $attributes['count'] ?? 0;
$items = $attributes['items'] ?? [];
// Nested defaults for objects
$image_url = $attributes['image']['url'] ?? '';
$link_text = $attributes['link']['text'] ?? 'Read More';
\`\`\`
### Conditional Rendering
\`\`\`php
<?php
$subtitle = $attributes['subtitle'] ?? '';
?>
<?php if ($subtitle) : ?>
<p class="subtitle"><?php echo esc_html($subtitle); ?></p>
<?php endif; ?>
\`\`\`
### Empty State in Editor
Keep elements visible for clicking even when empty:
\`\`\`php
<?php
$title = $attributes['title'] ?? '';
?>
<!-- Always render, even if empty -->
<h2 class="block__title" data-proto-field="title">
<?php echo esc_html($title); ?>
</h2>
\`\`\`
\`\`\`css
/* Ensure empty elements are visible */
.block__title:empty::before {
content: 'Click to add title';
color: #999;
}
\`\`\`
---
## Preview Mode Detection
Detect whether rendering in editor preview or frontend:
\`\`\`php
<?php
$is_preview = !isset($block) || $block === null;
if ($is_preview) {
// Editor preview - maybe show placeholder content
$items = $items ?: [
['title' => 'Example Item 1', 'content' => ''],
['title' => 'Example Item 2', 'content' => ''],
];
}
?>
\`\`\`
### Use Cases
- Show placeholder items when content is empty
- Add editor-specific classes
- Skip certain logic that requires full page context
- Display helpful messages in editor
---
## Image Handling Patterns
### Basic Image
\`\`\`php
<?php
$image = $attributes['image'] ?? null;
?>
<?php if ($image && !empty($image['url'])) : ?>
<img
src="<?php echo esc_url($image['url']); ?>"
alt="<?php echo esc_attr($image['alt'] ?? ''); ?>"
loading="lazy"
data-proto-field="image"
/>
<?php else : ?>
<div class="image-placeholder" data-proto-field="image">
<span>Click to add image</span>
</div>
<?php endif; ?>
\`\`\`
### Background Image
\`\`\`php
<?php
$bg = $attributes['backgroundImage'] ?? null;
$bg_style = '';
if ($bg && !empty($bg['url'])) {
$bg_style = "background-image: url('" . esc_url($bg['url']) . "');";
}
$wrapper_attributes = get_block_wrapper_attributes([
'class' => 'hero',
'style' => $bg_style,
]);
?>
<section <?php echo $wrapper_attributes; ?> data-proto-field="backgroundImage">
<div class="hero__content">
<!-- Content -->
</div>
</section>
\`\`\`
### Responsive Images
\`\`\`php
<?php
$image = $attributes['image'] ?? null;
if ($image && $image['id']) {
// Get responsive image data
$srcset = wp_get_attachment_image_srcset($image['id'], $image['size'] ?? 'large');
$sizes = wp_get_attachment_image_sizes($image['id'], $image['size'] ?? 'large');
}
?>
<?php if ($image && !empty($image['url'])) : ?>
<img
src="<?php echo esc_url($image['url']); ?>"
<?php if (!empty($srcset)) : ?>
srcset="<?php echo esc_attr($srcset); ?>"
sizes="<?php echo esc_attr($sizes); ?>"
<?php endif; ?>
alt="<?php echo esc_attr($image['alt'] ?? ''); ?>"
loading="lazy"
decoding="async"
data-proto-field="image"
/>
<?php endif; ?>
\`\`\`
---
## Link Handling Patterns
### Basic Link
\`\`\`php
<?php
$link = $attributes['link'] ?? null;
$has_link = $link && !empty($link['url']);
?>
<?php if ($has_link) : ?>
<a
href="<?php echo esc_url($link['url']); ?>"
<?php if (!empty($link['target'])) : ?>
target="<?php echo esc_attr($link['target']); ?>"
<?php endif; ?>
<?php if (!empty($link['rel'])) : ?>
rel="<?php echo esc_attr($link['rel']); ?>"
<?php endif; ?>
data-proto-field="link"
>
<?php echo esc_html($link['text'] ?? 'Read More'); ?>
</a>
<?php else : ?>
<a href="#" class="link--placeholder" data-proto-field="link">
Add link
</a>
<?php endif; ?>
\`\`\`
### Link as Button
\`\`\`php
<?php
$button = $attributes['buttonLink'] ?? null;
$button_text = $button['text'] ?? $attributes['buttonText'] ?? 'Click Here';
?>
<a
href="<?php echo esc_url($button['url'] ?? '#'); ?>"
class="button button--primary"
<?php echo !empty($button['target']) ? 'target="' . esc_attr($button['target']) . '"' : ''; ?>
<?php echo !empty($button['rel']) ? 'rel="' . esc_attr($button['rel']) . '"' : ''; ?>
data-proto-field="buttonLink"
>
<?php echo esc_html($button_text); ?>
</a>
\`\`\`
---
## Repeater Patterns
### Basic List
\`\`\`php
<?php
$items = $attributes['items'] ?? [];
?>
<ul class="item-list" data-proto-repeater="items">
<?php foreach ($items as $item) : ?>
<li data-proto-repeater-item>
<span data-proto-field="text"><?php echo esc_html($item['text'] ?? ''); ?></span>
</li>
<?php endforeach; ?>
</ul>
\`\`\`
### Card Grid
\`\`\`php
<?php
$cards = $attributes['cards'] ?? [];
$columns = $attributes['columns'] ?? 3;
if (empty($cards)) {
$cards = [
['title' => 'Card 1', 'content' => '', 'image' => null],
['title' => 'Card 2', 'content' => '', 'image' => null],
['title' => 'Card 3', 'content' => '', 'image' => null],
];
}
?>
<div
class="card-grid"
style="--columns: <?php echo esc_attr($columns); ?>;"
data-proto-repeater="cards"
>
<?php foreach ($cards as $card) : ?>
<article class="card" data-proto-repeater-item>
<?php if (!empty($card['image']['url'])) : ?>
<img
src="<?php echo esc_url($card['image']['url']); ?>"
alt="<?php echo esc_attr($card['image']['alt'] ?? ''); ?>"
class="card__image"
data-proto-field="image"
/>
<?php else : ?>
<div class="card__image-placeholder" data-proto-field="image">
<span>+</span>
</div>
<?php endif; ?>
<div class="card__body">
<h3 class="card__title" data-proto-field="title">
<?php echo esc_html($card['title'] ?? ''); ?>
</h3>
<div class="card__content" data-proto-field="content">
<?php echo wp_kses_post($card['content'] ?? ''); ?>
</div>
</div>
</article>
<?php endforeach; ?>
</div>
\`\`\`
### Nested Repeaters (FAQ)
\`\`\`php
<?php
$categories = $attributes['faqCategories'] ?? [];
?>
<div class="faq" data-proto-repeater="faqCategories">
<?php foreach ($categories as $category) : ?>
<section class="faq__category" data-proto-repeater-item>
<h2 class="faq__category-title" data-proto-field="name">
<?php echo esc_html($category['name'] ?? ''); ?>
</h2>
<dl class="faq__list" data-proto-repeater="questions">
<?php foreach ($category['questions'] ?? [] as $qa) : ?>
<div class="faq__item" data-proto-repeater-item>
<dt class="faq__question" data-proto-field="question">
<?php echo esc_html($qa['question'] ?? ''); ?>
</dt>
<dd class="faq__answer" data-proto-field="answer">
<?php echo wp_kses_post($qa['answer'] ?? ''); ?>
</dd>
</div>
<?php endforeach; ?>
</dl>
</section>
<?php endforeach; ?>
</div>
\`\`\`
---
## Layout Variations
### Using Control for Layouts
\`\`\`php
<?php
$layout = $attributes['layout'] ?? 'vertical';
$layout_classes = [
'vertical' => 'card--vertical',
'horizontal' => 'card--horizontal',
'overlay' => 'card--overlay',
];
$class = 'card ' . ($layout_classes[$layout] ?? 'card--vertical');
?>
<article class="<?php echo esc_attr($class); ?>">
<!-- Content -->
</article>
\`\`\`
### Conditional Content
\`\`\`php
<?php
$show_image = $attributes['showImage'] ?? true;
$show_meta = $attributes['showMeta'] ?? true;
?>
<article class="post-card">
<?php if ($show_image && $image) : ?>
<img src="<?php echo esc_url($image['url']); ?>" />
<?php endif; ?>
<div class="post-card__content">
<h2><?php echo esc_html($title); ?></h2>
<?php if ($show_meta) : ?>
<div class="post-card__meta">
<span><?php echo get_the_date(); ?></span>
</div>
<?php endif; ?>
</div>
</article>
\`\`\`
---
## Best Practices Summary
1. **Always use \`get_block_wrapper_attributes()\`** for the root element
2. **Escape all output** using the appropriate function
3. **Provide sensible defaults** with null coalescing
4. **Keep elements visible** even when empty (for editor clicking)
5. **Use semantic HTML** appropriate for your content
6. **Handle empty states** gracefully
7. **Detect preview mode** when needed for placeholder content
8. **Add loading="lazy"** to images for performance
9. **Use CSS for empty state styling** with \`:empty\` or \`::before\`
10. **Document your templates** with PHPDoc blocks
`;
}