Embedr

Embedr Module for ProcessWire

Author: Maxim Semenov
Website: smnv.org
Email: maxim@smnv.org

Embedr

If this project helps your work, consider supporting future development: GitHub Sponsors or smnv.org/sponsor.

License: MIT
ProcessWire: 3.0+
Changelog: CHANGELOG.md

Dynamic content embed management system with live preview, custom PHP templates, and visual card builder for ProcessWire CMS.


Features

Core Features

Advanced Features


Quick Start

Installation

  1. Upload module files to /site/modules/Embedr/:
    /site/modules/Embedr/
    β”œβ”€β”€ Embedr.module.php
    β”œβ”€β”€ ProcessEmbedr.module
    β”œβ”€β”€ TextformatterEmbedr.module
    β”œβ”€β”€ EmbedrItem.php
    β”œβ”€β”€ Embedrs.php
    β”œβ”€β”€ EmbedrType.php
    β”œβ”€β”€ EmbedrTypes.php
    └── EmbedrRenderer.php
    
  2. Install the module:
    Modules β†’ Refresh β†’ Embedr β†’ Install
    
  3. Add Textformatter to fields:
    Setup β†’ Fields β†’ body (or your field)
    Details β†’ Textformatters β†’ β˜‘ Embedr Text Formatter
    

Basic Usage

  1. Create an embed type:
    Setup β†’ Embedr β†’ Types β†’ Add New
    Name: articles
    Template: articles.php (optional)
    
  2. Create an embed:
    Setup β†’ Embedr β†’ Add New
    Name: latest-articles
    Title: Latest Articles
    Type: articles
    Selector: template=article, limit=6
    
  3. Use in templates:
    Body field: ((latest-articles))
    

Architecture

Component Structure

Embedr Ecosystem
β”œβ”€β”€ Embedr (Core API + Configuration)
β”œβ”€β”€ ProcessEmbedr (Admin Interface)
β”œβ”€β”€ TextformatterEmbedr (Parser)
β”œβ”€β”€ EmbedrItem (Single Embed Object)
β”œβ”€β”€ Embedrs (Embed Collection + Database)
β”œβ”€β”€ EmbedrType (Single Type Object)
β”œβ”€β”€ EmbedrTypes (Type Collection + Database)
└── EmbedrRenderer (Visual Card Builder)

Data Flow


1. Text Field with ((embed-name))
   ↓
2. TextformatterEmbedr (Textformatter)
   ↓
3. Embedr::getEmbed('embed-name')
   ↓
4. EmbedrItem::render()
   ↓
5. Check: PHP Template exists?
   β”œβ”€β†’ YES: Include custom PHP template
   └─→ NO:  Use EmbedrRenderer (visual cards)
   ↓
6. Return HTML


Configuration

Module Settings

Access via: Setup β†’ Modules β†’ Embedr β†’ Configure

Components Path (default: components/)

Opening Tag (default: (()

Closing Tag (default: )))

Auto-discover Types (default: unchecked)

Show Type Icons (default: checked)

Debug Mode (default: unchecked)


Usage Guide

Creating Embed Types

Types define reusable configurations for similar embeds.

Example: Article List Type

Name: articles
Title: Article Lists
Icon: file-text
Template: articles.php   ← optional; leave blank to use the visual renderer
Mode: array

Creating Embeds

Embeds are instances of types with specific selectors.

Example: Latest Articles Embed

Name: latest-articles
Title: Latest Articles
Type: articles
Selector: template=article, sort=-created, limit=6

Using Shortcodes

In any text field:


<h2>Recent Posts</h2>
((latest-articles))

<h2>Featured Products</h2>
((featured-products))

In PHP templates:

echo $page->body; // Textformatter processes ((tags)) automatically

Custom PHP Templates

Template Structure

Location: /site/templates/components/your-template.php

Available Variables:

$items      // PageArray - Found pages from selector
$page       // Page - Current page
$config     // Config - ProcessWire config
$input      // WireInput - Request data
$sanitizer  // Sanitizer - Sanitization methods
$embed      // EmbedrItem - The embed object
$embedContext // array - Optional context passed to Embedr::render()

Basic Template Example

<?php namespace ProcessWire;
/**
 * Articles List Template
 */

if(!$items->count()) {
    echo "<!-- No articles found -->";
    return;
}
?>
<div class="article-grid">
    <?php foreach($items as $article): ?>
        <article class="card">
            <?php if($article->images->count()): ?>
                <img src="<?= $article->images->first()->width(400)->url ?>" 
                     alt="<?= $article->title ?>">
            <?php endif; ?>
            
            <h3><?= $article->title ?></h3>
            
            <?php if($article->summary): ?>
                <p><?= $article->summary ?></p>
            <?php endif; ?>
            
            <a href="<?= $article->url ?>">Read more</a>
        </article>
    <?php endforeach; ?>
</div>

Guest-Safe Template

Always check field existence for guest users:

<?php namespace ProcessWire;

if(!$items->count()) return;

// Get current user
$user = $this->wire('user');
$isGuest = $user->isGuest();
?>
<div class="articles">
    <?php foreach($items as $article): ?>
        <article>
            <?php 
            // Safe image access
            if($article->hasField('images') && $article->images && $article->images->count()): 
                $img = $article->images->first();
                if($img):
            ?>
                <img src="<?= $img->width(400)->url ?>" alt="<?= $article->title ?>">
            <?php 
                endif;
            endif; 
            ?>
            
            <h3><?= $article->title ?></h3>
            
            <?php 
            // Safe summary access
            if($article->hasField('summary') && $article->summary): 
            ?>
                <p><?= $article->summary ?></p>
            <?php endif; ?>
            
            <a href="<?= $article->url ?>">Read more</a>
        </article>
    <?php endforeach; ?>
</div>

Visual Card Renderer

When no PHP template is specified, Embedr uses the built-in visual renderer powered by UIKit CSS classes.

Default settings

Setting Default Options
Layout grid grid, list, table
Columns 6 2, 3, 4, 6
Image size 192Γ—192px configured per type via config JSON
Links enabled β€”

The grid is fully responsive: 2 columns on small screens, scaling up to the configured maximum on large screens.

For custom image sizes, markup, or styling β€” create a PHP template instead (see Custom PHP Templates). The visual renderer is intended as a zero-config fallback.


Permissions

Permission Levels

embedr - View embeds

embedr-edit - Edit embeds

Assigning Permissions

Access β†’ Roles β†’ [Role Name]
Permissions β†’ β˜‘ embedr
Permissions β†’ β˜‘ embedr-edit (if needed)

Debug Mode

Enabling Debug Mode

Setup β†’ Modules β†’ Embedr β†’ Configure
β˜‘ Debug Mode
Save

Log Locations

embedr-debug - Full execution log

Setup β†’ Logs β†’ embedr-debug

Shows:

embedr-errors - Error log only

Setup β†’ Logs β†’ embedr-errors

Shows:

Log Example

[TextformatterEmbedr::formatValue] Called | Page=/news/hello-world/, User=guest
[TextformatterEmbedr::formatValue] Found 2 embed(s): latest-articles, featured
[TextformatterEmbedr::getReplacement] Looking for embed: latest-articles
[TextformatterEmbedr::getReplacement] Embed found | ID=3, Name=latest-articles, Type=articles
[Embedr::render] Starting | Embed=latest-articles (ID=3), Selector=template=53 | User=guest (guest=YES)
[Embedr::render] Type loaded | Name=articles, Template=articles.php, Mode=array
[Embedr::render] Executing selector: template=53
[Embedr::render] Selector found 6 items
[Embedr::render] Using PHP template: /site/templates/components/articles.php | Exists: YES
[Embedr::render] PHP template rendered (5089 chars)
[TextformatterEmbedr::getReplacement] Rendered (5089 chars): ...

Troubleshooting

Common Issues

1. Embed not found

<!-- Embedr: 'embed-name' not found -->

Causes:

Solutions:

2. Template not found

[Embedr::render] Using visual renderer (template file not found)

Causes:

Solutions:

3. Render error for guests

Cause:

Solution:

4. No items found

<!-- Embedr: No items found -->

Causes:

Solutions:

5. Wrong image sizes

Cause:

Solution:

Debugging Workflow

  1. Enable Debug Mode
    Setup β†’ Modules β†’ Embedr β†’ Configure β†’ β˜‘ Debug Mode
    
  2. Reproduce the issue Open the page where embed doesn’t work

  3. Check logs
    Setup β†’ Logs β†’ embedr-debug (full log)
    Setup β†’ Logs β†’ embedr-errors (errors only)
    
  4. Look for:
    • Embed NOT FOUND β†’ Name mismatch
    • Template ERROR β†’ PHP error in template
    • Selector found 0 items β†’ Permission or selector issue
    • Exists: NO β†’ File path problem
  5. Fix and test

  6. Disable Debug Mode (production)

API Reference

Embedr Module

$embedr = $modules->get('Embedr');

$embedr->render('latest-articles');
$embedr->getEmbed('latest-articles');
$embedr->embeds();
$embedr->types();

echo $embedr->renderField($page, 'content_blocks', [
    'template' => 'components/content-blocks.php',
    'cache' => 3600,
    'variables' => ['variant' => 'homepage'],
]);

Field renderer templates receive $page, $field, $value, $rows, $embedr, and any values supplied through variables. This makes the same API usable with ProFields Table, Repeater, PageTable, Page Reference, and custom iterable field values.

EmbedrItem Class

Properties:

$embed->id          // int - Database ID
$embed->name        // string - Unique name (slug)
$embed->title       // string - Human-readable title
$embed->type_id     // int - Type ID
$embed->selector    // string - ProcessWire selector
$embed->type        // EmbedrType - Type object

Methods:

$embed->render()           // string - Render to HTML
$embed->getType()          // EmbedrType|null - Get type object
$embed->getShortcode()     // string - Get ((name)) tag
$embed->getCount()         // int - Count results without rendering

Embedrs Class (Collection)

Methods:

$embedrs->get($name)              // EmbedrItem|null - Get by name
$embedrs->getById($id)            // EmbedrItem|null - Get by ID
$embedrs->getAll($refresh=false)  // WireArray - Get all embeds
$embedrs->save(EmbedrItem $embed) // int|false - Save embed
$embedrs->delete($id)             // bool - Delete embed

EmbedrType Class

Properties:

$type->id           // int - Database ID
$type->name         // string - Unique name
$type->title        // string - Display title
$type->icon         // string - FA icon name
$type->template     // string - PHP template filename
$type->mode         // string - 'array' or 'once'

Methods:

$type->getTemplatePath()     // string - Full path to template
$type->templateExists()      // bool - Check if file exists

EmbedrTypes Class (Collection)

Methods:

$types->get($name)               // EmbedrType|null - Get by name
$types->getById($id)             // EmbedrType|null - Get by ID
$types->getAll($refresh=false)   // WireArray - Get all types
$types->save(EmbedrType $type)   // int|false - Save type
$types->delete($id)              // bool - Delete type

Best Practices

1. Naming Convention

Embeds:

Types:

2. Selectors

Good:

template=article, sort=-created, limit=6
template=product, category=wine, limit=12
parent=/products/, limit=24

Avoid:

template=5314  // Use template name, not ID (both work, but name is clearer)
title%=test    // Avoid test data in production
limit=1000     // Too many results

3. Template Organization

/site/templates/
β”œβ”€β”€ components/           # Embedr templates
β”‚   β”œβ”€β”€ articles.php
β”‚   β”œβ”€β”€ products.php
β”‚   └── gallery.php
β”œβ”€β”€ layouts/              # Page layouts
└── partials/             # Includes

4. Performance

Do:

Don’t:

5. Security

Always:

Never:


Support

Author: Maxim Semenov
Email: maxim@smnv.org
GitHub: github.com/mxmsmnv/Embedr

Reporting Bugs

Please include:


License

MIT License β€” free to use in personal and commercial projects.