PATH:
home
/
bnathsfovv
/
marcopaolini.info
/
wp-content
/
plugins
/
extendify
/
app
/
QuickEdit
/
Schemas
<?php namespace Extendify\QuickEdit\Schemas; defined('ABSPATH') || die('No direct access.'); // Mirrors the media-* attrs and the inner <figure>/<img> markup so the // parsed-block tree stays internally consistent across re-renders. The // editable target is the image on the media side; the synthetic client // blockType `core/media-text:image` resolves to the real `core/media-text` // before it reaches SaveController, which is why this is keyed on the real // block name in the Registry. class MediaText implements Schema { public function fields(): array { return [ [ 'key' => 'media', 'control' => 'image', 'label' => __('Image', 'extendify-local'), ], ]; } public function apply(array $block, string $fieldKey, $value): array { if ($fieldKey !== 'media' || !is_array($value)) { return $block; } $id = isset($value['id']) ? (int) $value['id'] : null; $alt = isset($value['alt']) ? wp_strip_all_tags((string) $value['alt']) : null; // A positive id must resolve to a real image attachment; trust the // server's URL when it does. The raw client URL is only honored for // the id-less external-image case (mirror of Image::apply). if ($id !== null && $id > 0) { if (!wp_attachment_is_image($id)) { return $block; } $url = wp_get_attachment_image_url($id, 'full') ?: null; } else { $url = isset($value['url']) ? esc_url_raw((string) $value['url']) : null; } if (!$url) { return $block; } $attrs = $block['attrs'] ?? []; $attrs['mediaUrl'] = $url; $attrs['mediaLink'] = $url; $attrs['mediaType'] = 'image'; if ($id !== null && $id > 0) { $attrs['mediaId'] = $id; } else { unset($attrs['mediaId']); } if ($alt !== null) { $attrs['mediaAlt'] = $alt; } $attrs = $this->dropImportClass($attrs); $block['attrs'] = $attrs; // Static block: serialize_blocks emits the stored innerContent verbatim, // so the rendered <img>/background must be patched here — there's no // save() re-run from attrs. The media <figure> + <img> live in the // leading string chunk (the content side is inner blocks → nulls), so // find that chunk and patch in place. NOT innerHTML, whose nulls would // collapse and drop the content-side inner blocks (see Cover::apply). $innerContent = $block['innerContent'] ?? []; foreach ($innerContent as $i => $chunk) { if (!is_string($chunk) || strpos($chunk, 'wp-block-media-text__media') === false) { continue; } $tp = new \WP_HTML_Tag_Processor($chunk); $inMedia = false; $patched = false; while ($tp->next_tag()) { $tag = $tp->get_tag(); if ($tag === 'FIGURE') { $inMedia = $tp->has_class('wp-block-media-text__media'); if ($inMedia) { // imageFill renders the media as the figure's CSS // background; keep that url in sync with the <img>. $style = $tp->get_attribute('style'); if (is_string($style) && stripos($style, 'background-image') !== false) { $tp->set_attribute('style', preg_replace_callback( '/background-image\s*:\s*url\([^)]*\)/i', static fn () => 'background-image:url(' . $url . ')', $style )); $patched = true; } } continue; } if ($tag === 'IMG' && $inMedia) { $tp->set_attribute('src', $url); if ($alt !== null) { $tp->set_attribute('alt', $alt); } // Gutenberg's media-text save() derives wp-image-{id} from // attrs.mediaId; a mismatch trips the validator. Strip any // pre-existing first so re-edits don't stack. $cls = (string) ($tp->get_attribute('class') ?? ''); $cls = trim((string) preg_replace('/\bwp-image-\d+\b/', '', $cls)); if ($id !== null && $id > 0) { $cls = trim($cls . ' wp-image-' . $id); } $cls = (string) preg_replace('/\s{2,}/', ' ', $cls); if ($cls === '') { $tp->remove_attribute('class'); } else { $tp->set_attribute('class', $cls); } if ($id === null || $id <= 0) { $tp->remove_attribute('srcset'); $tp->remove_attribute('sizes'); } $patched = true; break; } } if ($patched) { $patchedChunk = $this->stripImportMarker($tp->get_updated_html(), 'div'); $innerContent[$i] = $patchedChunk; $block['innerContent'] = $innerContent; // Inspection-only; the serializer rebuilds innerHTML from innerContent. $block['innerHTML'] = implode('', array_map( static fn ($c) => is_string($c) ? $c : '', $innerContent )); break; } } return $block; } // The Launch-import marker lives in attrs.className for media-text (it // renders into the wrapper div); strip it so a Quick Edit replace claims // the image the same way the agent's change-image flow does. private function dropImportClass(array $attrs): array { if (!isset($attrs['className']) || !is_string($attrs['className'])) { return $attrs; } $classes = array_filter( preg_split('/\s+/', $attrs['className']) ?: [], static fn ($c) => $c !== '' && $c !== 'extendify-image-import' ); if ($classes) { $attrs['className'] = implode(' ', $classes); } else { unset($attrs['className']); } return $attrs; } // Mirror of Image::stripImportMarker — drop the marker class that survives // in the rendered wrapper but not in attrs after the className edit above. private function stripImportMarker(string $html, string $tagName): string { $tp = new \WP_HTML_Tag_Processor($html); if (!$tp->next_tag($tagName)) { return $html; } if (!$tp->has_class('extendify-image-import')) { return $html; } $tp->remove_class('extendify-image-import'); return $tp->get_updated_html(); } }
[-] Heading.php
[edit]
[-] Button.php
[edit]
[-] SocialLink.php
[edit]
[-] MediaText.php
[edit]
[-] Image.php
[edit]
[-] NavigationLink.php
[edit]
[-] Cover.php
[edit]
[-] Schema.php
[edit]
[-] Paragraph.php
[edit]
[+]
..
[-] Registry.php
[edit]