Documentation

Bindery docs

Everything to install Bindery, decide what your client can edit, and wire it into any theme — no‑code or with the template API.

Introduction

Bindery lets a developer declare exactly what a client may change on a site, then gives the client a locked, edit‑in‑place experience over only those things. The theme keeps its hand‑written markup; the client edits text on the live page like a document.

It’s built entirely on native WordPress primitives — the Block Bindings API, block.json and the REST API — so it never owns your markup and adds no builder lock‑in.

The one rule: only what you declare editable can be changed. Layout, structure and everything unmarked stays untouchable.

Installation

  1. Install from Plugins → Add New → Upload Plugin, or search the directory for “Bindery”.
  2. Activate Bindery.
  3. Open Bindery in the admin menu, turn on inline editing and tick which elements are editable.
  4. Visit any page on the front end and click ✎ Edit page.

No build step or Composer is required to use the plugin — the compiled assets ship in the package. Requires WordPress 6.5+ and PHP 8.1+.

Core concepts

A Bindery field is one editable thing, identified by a key (hero_title), with a type (text, richtext, url, image, repeater…) and a scope:

  • Page scope — the value belongs to the post being viewed.
  • Global scope — one value shared site‑wide (an announcement bar, a footer line).

Where content is stored

Values live in a dedicated table (wp_bindery_values), one row per field / object / locale — never mixed into your post markup.

How a value resolves

The rule is simple and predictable:

stored override for the current locale   (any value the client saved — even "")
  └─ else: the default you passed in code

The default is never persisted, so improving it in code reaches every site that hasn’t overridden the field.

The settings page

Everything a site owner needs lives under wp‑admin → Bindery:

  • Editable Content — turn on inline editing and tick which elements (headings, paragraphs, lists, quotes…) are editable, and on which post types.
  • Editing Experience — show/hide the floating button, auto‑enter edit mode, strict mode, and the accent colour.
  • Permissions — which roles may edit (Administrators always can).
  • History & Data — keep a revision history, set how many versions per field, and Export / Import all values as JSON.

With auto content editing on, that’s the entire setup — no code at all.

The live overlay

For any user with the editing capability, Bindery adds a floating ✎ Edit page button on the front end of singular pages. Clicking it:

  • outlines every editable region;
  • makes them editable in place;
  • saves each on blur, for the current language;
  • shows a language switcher when more than one locale exists.

Everything not declared editable is left completely alone. Visitors never receive the overlay or the editing markers — they’re emitted only for capable, logged‑in users.

Auto content editing

The fastest path: make a page’s existing text editable with no code. Enable it on the settings page and pick which tags qualify. Bindery walks the page body and marks each pure‑text element (headings, paragraphs, list items…) with a stable key derived from its position.

  • A stored override replaces the element’s text for every visitor; editors get the inline‑edit markers.
  • Edits are scoped per page, with revision history.
  • Declared regions (blocks / bindery_attrs()) always take precedence and are never re‑marked.

Disable globally or per post with the bindery/auto_editable filter.

Attribute helper

The cleanest path for a developer who owns the theme. You write the markup; Bindery prints the hooks and resolves the value.

<h1 <?php bindery_attrs( 'hero_title', array( 'type' => 'h1' ) ); ?>><?php
    echo esc_html( (string) bindery_value( 'hero_title' ) );
?></h1>
  • bindery_attrs( $key, $args ) prints the data-bindery-* hooks — only for users who can edit, and only when the field isn’t locked.
  • bindery_value( $key ) returns the resolved value (override ?? default). You own the tag, so escape it yourself.

A site‑wide field is identical with 'scope' => 'global' — edit it once on any page and it updates everywhere.

// A guarded, site-wide editable line (e.g. in footer.php):
if ( function_exists( 'bindery_attrs' ) ) :
    $args = array( 'type' => 'span', 'scope' => 'global', 'default' => '© Acme' );
    ?>
    <span <?php bindery_attrs( 'footer_note', $args ); ?>><?php
        echo esc_html( (string) bindery_value( 'footer_note' ) );
    ?></span>
<?php endif;

Template tags

Render a declared field anywhere in PHP.

// Echo a field rendered + escaped by its type:
bindery_field( 'phone', array( 'type' => 'text', 'default' => '+1 555 0100' ) );

// Get the raw resolved value:
$tagline = bindery_value( 'tagline', array( 'default' => 'Boutique stays.' ) );

// Loop a repeater (a list of features, slides, etc.):
foreach ( bindery_rows( 'features' ) as $row ) {
    echo '<h3>' . esc_html( $row['title'] ) . '</h3>';
    echo '<p>'  . esc_html( $row['body']  ) . '</p>';
}
FunctionPurpose
bindery_value()Resolved value (override ?? default).
bindery_field()Echo the value rendered + escaped by its type.
bindery_get_field()Same, returned as a string.
bindery_rows()Repeater rows for looping.
bindery_attrs()Print the overlay hooks onto your own tag.
bindery_register_field()Declare a field explicitly (e.g. in functions.php).

Common $args: type (h1h6, p, span, text, richtext, link, image, repeater), default, scope, locked, capability, label.

Blocks

Bindery ships eight self‑contained blocks that store their content in the Bindery store (per locale) instead of in the post markup:

editable‑text · cards · slider · image · button · icon · form · section.

Their colours adapt to the active theme via --bindery-* CSS variables, so they look native anywhere. There are also ready‑made block patterns (Hero, Features, Testimonials, Contact, full Landing page) under the “Bindery” category.

Multilingual

Every field is locale‑aware by default. The overlay’s language switcher reloads the page in a locale, and edits store a value per locale; unedited locales fall back to your code default.

Plug in WPML/Polylang via the bindery/locale_provider filter, or use the built‑in provider with a ?lang= parameter.

Filters & hooks

FilterControls
bindery/settingsOverride any resolved setting in code (wins over the UI).
bindery/auto_editableEnable/disable auto content editing per post.
bindery/strict_overlayOverlay edits only hand‑coded regions, not blocks.
bindery/storage_adapterSwap the storage backend (table, meta, custom).
bindery/locale_providerProvide locales (WPML / Polylang adapter).
bindery/record_history · bindery/history_capHistory on/off and version cap.

Actions: bindery/register (register custom field types/sources), bindery/booted, bindery/activated.

History & migration

Every edit is recorded with who changed it and when (capped per field, configurable). Restore any past value with one click, or move all values between sites.

From the settings page

History tab → Export values (JSON) to download a full snapshot, or pick a file to Import.

From WP‑CLI

wp bindery export --file=values.json                      # export all values
wp bindery import --file=values.json                      # import (history-suppressed)
wp bindery history hero_title --object=9 --locale=en_US   # list versions
wp bindery restore 42                                     # restore to version #42

Imports are sanitised (wp_kses_post) and bounded, so a hand‑edited file can’t inject scripts or exhaust storage.

Security model

  • Capability‑gated. Editing requires bindery_edit_content; settings require manage_options. Administrators always retain the editing capability.
  • Whitelisted writes. The editor endpoint accepts writes only for fields present on the page, rejects locked fields, and re‑checks the per‑field capability.
  • Sanitised in, escaped out. Each field type sanitises on save and escapes on render (esc_html, wp_kses_post, esc_url…).
  • Visitors get clean markup. The editing hooks and overlay assets are emitted only for capable, logged‑in users.

FAQ

Does Bindery change my theme’s markup?

No. It resolves a value and outputs your own clean markup. Editable regions are marked with data-* attributes emitted only for logged‑in editors.

Do I have to write code?

No. With auto content editing enabled, your existing page text becomes editable with zero code. The template API exists for developers who want precise, per‑region control.

Can a client break the layout?

No. Only the regions you declared editable can change. Everything else is untouchable.

Can I move content between sites?

Yes — export/import all values as JSON from the settings page or with wp bindery export / import.

Ready to try it?

Install Bindery, tick what’s editable, and hand your client a site they can update.

Download v0.1.0

Pre‑release v0.1.0 · pending review on WordPress.org