PluginProbe
Extendify / 3.2.1
Extendify v3.2.1
3.2.1 3.2.0 3.1.6 3.1.5 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 3.0.6 3.0.5 3.0.4 trunk 0.1.0 0.10.0 0.10.1 0.10.2 0.11.0 0.11.1 0.2.0 0.3.0 0.3.1 0.4.0 0.5.0 0.6.0 All 127 releases
extendify / app / QuickEdit / Schemas / Cover.php

Cover.php in Extendify 3.2.1, at app/QuickEdit/Schemas/Cover.php

125 lines 4.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Extendify\QuickEdit\Schemas;
4
5 defined('ABSPATH') || die('No direct access.');
6
7 class Cover implements Schema
8 {
9 public function fields(): array
10 {
11 return [
12 [
13 'key' => 'background',
14 'control' => 'image',
15 'label' => __('Background image', 'extendify-local'),
16 ],
17 ];
18 }
19
20 public function apply(array $block, string $fieldKey, $value): array
21 {
22 if ($fieldKey !== 'background' || !is_array($value)) {
23 return $block;
24 }
25
26 $id = isset($value['id']) ? (int) $value['id'] : null;
27
28 // Mirror of Image::apply — a positive id must be a real image
29 // attachment, and the server-derived URL wins over the client's.
30 if ($id !== null && $id > 0) {
31 if (!wp_attachment_is_image($id)) {
32 return $block;
33 }
34 $url = wp_get_attachment_image_url($id, 'full') ?: null;
35 } else {
36 $url = isset($value['url']) ? esc_url_raw((string) $value['url']) : null;
37 }
38 if (!$url) {
39 return $block;
40 }
41
42 $attrs = $block['attrs'] ?? [];
43 $attrs['url'] = $url;
44 if ($id !== null && $id > 0) {
45 $attrs['id'] = $id;
46 } else {
47 unset($attrs['id']);
48 }
49 unset($attrs['hasParallax']);
50 $block['attrs'] = $attrs;
51
52 // Patch the string chunks in innerContent — NOT innerHTML. innerContent
53 // for a cover with inner blocks is `[wrapper_open, null, wrapper_close]`;
54 // those nulls map to innerBlocks at serialize time. Stuffing innerHTML
55 // into [0] closes the wrapper early and the inner blocks land outside
56 // the cover, vanishing from __inner-container.
57 // Color-only / video covers don't have an image-background <img>;
58 // skip rather than synthesizing one.
59 $innerContent = $block['innerContent'] ?? [];
60 foreach ($innerContent as $i => $chunk) {
61 if (!is_string($chunk)) {
62 continue;
63 }
64 $tp = new \WP_HTML_Tag_Processor($chunk);
65 $patched = false;
66 while ($tp->next_tag('img')) {
67 $cls = (string) ($tp->get_attribute('class') ?? '');
68 if (str_contains($cls, 'wp-block-cover__image-background')) {
69 $tp->set_attribute('src', $url);
70 if ($id === null || $id <= 0) {
71 $tp->remove_attribute('srcset');
72 $tp->remove_attribute('sizes');
73 }
74
75 // Gutenberg's core/cover save() derives the wp-image-{id}
76 // class from attrs.id; mismatch trips the block validator.
77 $newCls = trim((string) preg_replace(
78 '/\bwp-image-\d+\b/',
79 '',
80 $cls
81 ));
82 if ($id !== null && $id > 0) {
83 $newCls = trim($newCls . ' wp-image-' . $id);
84 }
85 $newCls = (string) preg_replace('/\s{2,}/', ' ', $newCls);
86 $tp->set_attribute('class', $newCls);
87
88 $patched = true;
89 break;
90 }
91 }
92 if ($patched) {
93 $patchedChunk = $tp->get_updated_html();
94 $patchedChunk = $this->stripImportMarker($patchedChunk, 'div');
95 $innerContent[$i] = $patchedChunk;
96 $block['innerContent'] = $innerContent;
97 // Inspection-only; the serializer rebuilds innerHTML from innerContent.
98 $block['innerHTML'] = implode('', array_map(
99 static function ($c) {
100 return is_string($c) ? $c : '';
101 },
102 $innerContent
103 ));
104 break;
105 }
106 }
107
108 return $block;
109 }
110
111 // Mirror of Image::stripImportMarker.
112 private function stripImportMarker(string $html, string $tagName): string
113 {
114 $tp = new \WP_HTML_Tag_Processor($html);
115 if (!$tp->next_tag($tagName)) {
116 return $html;
117 }
118 if (!$tp->has_class('extendify-image-import')) {
119 return $html;
120 }
121 $tp->remove_class('extendify-image-import');
122 return $tp->get_updated_html();
123 }
124 }
125