Skip to main content

Custom Renderers

You can create custom renderers to control exactly how forms are displayed.

Implementing the Interface

Create a class that implements the Renderer interface:

use Tangible\Renderer\Renderer;
use Tangible\DataObject\DataSet;
use Tangible\EditorLayout\Layout;

class MyCustomRenderer implements Renderer {

public function render_editor(Layout $layout, array $data = []): string {
// Render the edit/create form
}

public function render_list(DataSet $dataset, array $entities): string {
// Render the list view
}
}

Using Your Renderer

$view = new DataView([...]);
$view->set_renderer(new MyCustomRenderer());
$view->register();

Accessing Layout Structure

The layout provides its structure for rendering:

public function render_editor(Layout $layout, array $data = []): string {
$structure = $layout->get_structure();
$dataset = $layout->get_dataset();

// Structure format:
// [
// 'items' => [
// ['type' => 'section', 'label' => 'General', 'fields' => [...]],
// ['type' => 'tabs', 'tabs' => [...]],
// ],
// 'sidebar' => [
// 'fields' => [...],
// 'actions' => ['save', 'delete'],
// ],
// ]

$html = '<form method="post" class="my-custom-form">';

foreach ($structure['items'] as $item) {
$html .= $this->render_item($item, $data, $dataset);
}

if (!empty($structure['sidebar'])) {
$html .= $this->render_sidebar($structure['sidebar'], $data, $dataset);
}

$html .= '</form>';

return $html;
}

Rendering Items

Handle different item types:

protected function render_item(array $item, array $data, DataSet $dataset): string {
switch ($item['type']) {
case 'section':
return $this->render_section($item, $data, $dataset);
case 'tabs':
return $this->render_tabs($item, $data, $dataset);
case 'field':
return $this->render_field($item, $data, $dataset);
default:
return '';
}
}

protected function render_section(array $section, array $data, DataSet $dataset): string {
$html = '<div class="section">';
$html .= '<h2>' . esc_html($section['label']) . '</h2>';

foreach ($section['items'] ?? [] as $item) {
$html .= $this->render_item($item, $data, $dataset);
}

foreach ($section['fields'] ?? [] as $field) {
$html .= $this->render_field($field, $data, $dataset);
}

$html .= '</div>';
return $html;
}

Rendering Fields

Get field info from the dataset:

protected function render_field(array $field, array $data, DataSet $dataset): string {
$slug = $field['slug'];
$value = $data[$slug] ?? '';
$type = $dataset->get_type($slug);

$html = '<div class="field">';
$html .= '<label for="' . esc_attr($slug) . '">';
$html .= esc_html($field['label'] ?? ucfirst($slug));
$html .= '</label>';

// Render input based on type
switch ($type) {
case DataSet::TYPE_BOOLEAN:
$checked = $value ? 'checked' : '';
$html .= '<input type="checkbox" id="' . esc_attr($slug) . '" ';
$html .= 'name="' . esc_attr($slug) . '" value="1" ' . $checked . '>';
break;

case DataSet::TYPE_INTEGER:
$html .= '<input type="number" id="' . esc_attr($slug) . '" ';
$html .= 'name="' . esc_attr($slug) . '" ';
$html .= 'value="' . esc_attr($value) . '">';
break;

default:
$html .= '<input type="text" id="' . esc_attr($slug) . '" ';
$html .= 'name="' . esc_attr($slug) . '" ';
$html .= 'value="' . esc_attr($value) . '">';
}

if (!empty($field['help'])) {
$html .= '<p class="help">' . esc_html($field['help']) . '</p>';
}

$html .= '</div>';
return $html;
}

Complete Example

A Bootstrap-styled renderer:

class BootstrapRenderer implements Renderer {

public function render_editor(Layout $layout, array $data = []): string {
$structure = $layout->get_structure();
$dataset = $layout->get_dataset();

$html = '<form method="post" class="needs-validation">';

foreach ($structure['items'] as $item) {
$html .= $this->render_item($item, $data, $dataset);
}

$html .= '<div class="mt-4">';
$html .= '<button type="submit" name="action" value="save" ';
$html .= 'class="btn btn-primary">Save</button>';
$html .= '</div>';

$html .= '</form>';
return $html;
}

public function render_list(DataSet $dataset, array $entities): string {
$html = '<table class="table table-striped">';
$html .= '<thead><tr>';

foreach ($dataset->get_fields() as $name => $type) {
$html .= '<th>' . esc_html(ucfirst($name)) . '</th>';
}
$html .= '<th>Actions</th>';
$html .= '</tr></thead>';

$html .= '<tbody>';
foreach ($entities as $entity) {
$html .= '<tr>';
foreach ($dataset->get_fields() as $name => $type) {
$html .= '<td>' . esc_html($entity->get($name)) . '</td>';
}
$html .= '<td><a href="?action=edit&id=' . $entity->get_id() . '">Edit</a></td>';
$html .= '</tr>';
}
$html .= '</tbody></table>';

return $html;
}

// ... implement render_item, render_section, render_field, etc.
}