PHPackages                             donbuche/layout\_builder\_import\_export - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. donbuche/layout\_builder\_import\_export

ActiveDrupal-module[Utility &amp; Helpers](/categories/utility)

donbuche/layout\_builder\_import\_export
========================================

Drupal module to export and quick-edit Layout Builder block content and nested paragraph text.

1.0.8(1mo ago)06↓85.7%MITPHPPHP ^8.4

Since Jun 5Pushed 1mo agoCompare

[ Source](https://github.com/donbuche/layout_builder_import_export)[ Packagist](https://packagist.org/packages/donbuche/layout_builder_import_export)[ RSS](/packages/donbuche-layout-builder-import-export/feed)WikiDiscussions main Synced 1w ago

READMEChangelogDependencies (2)Versions (11)Used By (0)

Layout Builder Import Export
============================

[](#layout-builder-import-export)

**Version 1.0.0**

A custom Drupal module for exporting and quick-editing the editorial text content of Layout Builder `block_content` entities and their paragraph trees.

---

Requirements
------------

[](#requirements)

RequirementVersionDrupal10.x or 11.xPHP8.1 or higherDrupal core: `layout_builder`enabledDrupal core: `block_content`enabledDrupal core: `content_translation`enabled (for translation workflow)The module traverses `entity_reference_revisions` fields to reach nested paragraph entities. The `paragraphs` contrib module is not declared as a dependency because the traversal is performed via Drupal's core field API and works with any entity that uses that field type.

---

Installation
------------

[](#installation)

```
drush en layout_builder_import_export -y
drush cr
```

---

Repository clean-up before committing
-------------------------------------

[](#repository-clean-up-before-committing)

Two files must be removed before pushing to the repository:

```
# Empty scaffold — replaced by LayoutBuilderExportController
git rm web/modules/custom/layout_builder_import_export/src/Controller/LayoutTextExportController.php

# Development artefacts — must never enter version control
git rm -r web/modules/custom/layout_builder_import_export/temp/
```

Add `temp/` to the module's `.gitignore` to prevent accidental future commits:

```
/temp/

```

---

Architecture
------------

[](#architecture)

```
layout_builder_import_export/
├── src/
│   ├── Service/
│   │   └── BlockTextExporter.php      # Single source of truth for field
│   │                                  # filtering and paragraph traversal
│   ├── Controller/
│   │   └── LayoutBuilderExportController.php  # JSON export + debug endpoints
│   └── Form/
│       └── BlockQuickEditForm.php     # Quick Edit tab (Fields / JSON / Text)
├── layout_builder_import_export.info.yml
├── layout_builder_import_export.routing.yml
├── layout_builder_import_export.links.task.yml
└── layout_builder_import_export.services.yml

```

### BlockTextExporter service

[](#blocktextexporter-service)

`layout_builder_import_export.block_text_exporter`

Injected into both the controller and the form. This is the **only** place that defines:

- Which field types are exportable (`string`, `text_long`, `link`, etc.)
- Which field names are excluded (CSS classes, HTML tags, icons, etc.)
- How the paragraph tree is traversed (up to `MAX_DEPTH` levels)

Any change to what gets exported must be made **only here**.

---

Usage
-----

[](#usage)

### 1. Quick Edit tab (primary workflow)

[](#1-quick-edit-tab-primary-workflow)

Navigate to `/admin/content/block`, open any block, and click the **Quick Edit**tab alongside Edit and Translate.

Three sub-modes are available as vertical tabs:

#### Fields mode (default)

[](#fields-mode-default)

One input per text field, grouped by paragraph entity. Formatted text fields (`text_long`, `text_with_summary`) render with the full CKEditor 5 editor, giving access to configured styles and image upload. Link URI fields for internal nodes use Drupal's native entity autocomplete. Plain string fields render as standard textfields.

#### Text mode (AI translation)

[](#text-mode-ai-translation)

Outputs a numbered plain-text format optimised for AI translation:

```
---1---
El procés pas a pas
---2---
No enviem un robot a escanejar la web...

```

A ready-to-use AI prompt is displayed above the textarea. Copy the content, send to an AI assistant with the prompt, paste the response back (the module strips markdown code fences automatically), and click **Save Text**.

#### JSON mode

[](#json-mode)

Full export document for scripting or batch processing. The structure includes item IDs, langcode, and `new_value` placeholders. See the endpoint section below for the document format.

---

### Language / translation

[](#language--translation)

There is no manual language selector. The active language is determined by Drupal's URL language negotiation:

- `/ca/block/34/quick-edit` → reads and writes in Catalan
- `/es/block/34/quick-edit` → reads and writes in Spanish

**Recommended translation workflow:**

1. Create the block translation via Drupal's native Translate tab.
2. Navigate to the block list in the target language (e.g. `/es/admin/content/block`).
3. Open **Quick Edit** — the form is now in Spanish context.
4. Edit fields or use the Text/JSON tab with an AI assistant.
5. Save. Paragraph translations are created automatically when they do not exist.

**Prerequisite:** paragraph text fields must be marked as **Translatable** in `/admin/config/regional/content-language`. The form warns before saving if it detects non-translatable fields.

---

### 2. JSON export endpoint (read-only)

[](#2-json-export-endpoint-read-only)

```
GET /admin/content/layout-builder-export/block/{block_content_id}

```

**Example response:**

```
{
  "meta": {
    "block_id": 61,
    "block_label": "Homepage | Hero block",
    "block_bundle": "layout_builder",
    "source_langcode": "ca",
    "exported_at": "2026-06-04T17:00:00+00:00"
  },
  "items": [
    {
      "id": "paragraph:264:264:field_plain_text:0",
      "field": "field_plain_text",
      "langcode": "ca",
      "original": "Current heading text",
      "new_value": ""
    },
    {
      "id": "paragraph:80:80:field_link:0:uri",
      "field": "field_link.uri",
      "langcode": "ca",
      "original": "entity:node/808",
      "new_value": ""
    },
    {
      "id": "paragraph:80:80:field_link:0:title",
      "field": "field_link.title",
      "langcode": "ca",
      "original": "See all services",
      "new_value": ""
    }
  ],
  "warnings": []
}
```

**Item ID formats:**

FormatUsed for`entity_type:id:rev:field:delta`All text fields`entity_type:id:rev:field:delta:property`Link fields (`uri` or `title`)---

### 3. Debug endpoint (development only)

[](#3-debug-endpoint-development-only)

```
GET /admin/content/layout-builder-export-debug/block/{block_content_id}

```

Returns the complete field structure of the block, including system fields, computed fields, and referenced entities one level deep. Use this to diagnose why a specific field is missing from the normal export. Remove or restrict access to this endpoint in production if sensitive field data is a concern.

---

Field filtering rules
---------------------

[](#field-filtering-rules)

Applied in order by `BlockTextExporter`:

1. **Field type** — Only `string`, `string_long`, `text`, `text_long`, `text_with_summary`, and `link` fields are considered.
2. **Naming convention** — Fields not prefixed with `field_` are always excluded (Drupal base fields: `langcode`, `status`, `parent_id`, etc.).
3. **Explicit exclusion list** — Fields excluded despite using a text type: `field_attribute_class`, `field_attribute_id`, `field_attribute_rel`, `field_attribute_target`, `field_html_tag`, `field_accordion_behavior`.
4. **Pattern exclusion** — Any field whose name contains `icon` is excluded.

`field_custom_attributes` is **not** excluded because it may contain accessibility strings (e.g. `aria-description="See all services"`) that are genuine editorial content. The AI prompt instructs the assistant to translate only attribute values, not attribute names, and to skip boolean values.

To add or remove exclusions, edit the constants in `src/Service/BlockTextExporter.php`.

---

Paragraph traversal depth
-------------------------

[](#paragraph-traversal-depth)

```
block_content
  └── field_content (depth 1) → paragraph
        └── field_list_items (depth 2) → list_item paragraph
              └── field_content (depth 3) → title paragraph
                    └── field_plain_text ← exported ✓

```

`MAX_DEPTH = 3` (defined in `BlockTextExporter`). Increasing it risks issues with circular references in unusual paragraph configurations.

---

Security
--------

[](#security)

- All routes require `administer site configuration`.
- `persistItems()` checks `$entity->access('update')` before writing, providing defence-in-depth even when the route permission is already restrictive.
- The debug endpoint checks `$entity->access('view')` before including referenced entities in the response.
- The Quick Edit form validates that every submitted item ID belongs to the block being edited. Submitting IDs from a different block is rejected.
- Entities are saved without creating a new revision (`setNewRevision(FALSE)`) to keep `entity_reference_revisions` pointers in the parent block valid.

---

Planned features
----------------

[](#planned-features)

- **Import via file upload** — Accept a JSON file at a dedicated import route.
- **Clone mode** — Duplicate a block and all its paragraphs with `new_value` overrides.

###  Health Score

42

—

FairBetter than 88% of packages

Maintenance91

Actively maintained with recent releases

Popularity4

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity57

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 72.7% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~1 days

Total

9

Last Release

44d ago

PHP version history (2 changes)1.0.1PHP ^8.1

1.0.4PHP ^8.4

### Community

Maintainers

![](https://www.gravatar.com/avatar/fb8425ef925315b596ae0d6d8cb619ea563ea01995287aa5c11cd77495808a0d?d=identicon)[donbuche](/maintainers/donbuche)

---

Top Contributors

[![joan-galtes](https://avatars.githubusercontent.com/u/237098830?v=4)](https://github.com/joan-galtes "joan-galtes (8 commits)")[![bertuuk](https://avatars.githubusercontent.com/u/22979999?v=4)](https://github.com/bertuuk "bertuuk (3 commits)")

### Embed Badge

![Health badge](/badges/donbuche-layout-builder-import-export/health.svg)

```
[![Health](https://phpackages.com/badges/donbuche-layout-builder-import-export/health.svg)](https://phpackages.com/packages/donbuche-layout-builder-import-export)
```

###  Alternatives

[farmos/farmos

A web-based farm record keeping application.

1.3k7.1k1](/packages/farmos-farmos)[emulsify-ds/emulsify-drupal

The official Drupal theme for Emulsify, with Storybook and a Vite-based build workflow for generated child themes

96556.4k2](/packages/emulsify-ds-emulsify-drupal)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
