PluginProbe
Templately – Elementor & Gutenberg Template Library: 6500+ Free & Pro Ready Templates And Cloud! / 3.8.0
Templately – Elementor & Gutenberg Template Library: 6500+ Free & Pro Ready Templates And Cloud! v3.8.0
3.8.0 3.7.5 3.7.4 3.7.3 3.7.2 1-final 3.7.1 3.7.0 3.6.8 3.6.7 3.6.6 3.6.5 3.6.4 3.6.3 3.6.2 3.6.1 3.0.3 3.0.4 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.1 All 112 releases
templately / modules / gutenberg-integration / Utils / GutenbergHelper.php

GutenbergHelper.php in Templately – Elementor & Gutenberg Template Library: 6500+ Free & Pro Ready Templates And Cloud! 3.8.0, at modules/gutenberg-integration/Utils/GutenbergHelper.php

481 lines 15.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Templately\Modules\GutenbergIntegration\Utils;
4
5 use Templately\Modules\FullSiteImport\Utils\ImportHelper;
6 use Templately\Modules\FullSiteImport\Utils\Utils;
7 use Templately\Modules\FullSiteImport\WPImport;
8 use Templately\Utils\Helper;
9
10 class GutenbergHelper extends ImportHelper {
11 const IMAGE_URL_PATTERN = '/(https?:\/\/[^\s<>"\']+\.(jpg|jpeg|gif|png|svg|webp|ico|tiff|tif)(?:\?[^\s<>"\']*)?)/i';
12
13 private $template_settings = [];
14 private $forms = [];
15 private $attachment_options = [];
16 /**
17 * @var WPImport
18 */
19 private $wp_importer;
20
21 public $shouldLog = true; // This is the class property to check
22
23 protected $content;
24
25 protected $post_id;
26
27 protected static $attachment_ids = [];
28
29
30 /**
31 * @param $template_json
32 * @param $template_settings
33 * @param $extra_content
34 *
35 * @return GutenbergHelper
36 */
37 public function prepare( $template_json, $template_settings, $extra_content = [], $request_params = [] ) {
38 $this->template_settings = $template_settings;
39 $this->post_id = $this->map_post_ids[ $template_settings['post_id'] ];
40 $this->wp_importer = new WPImport( null, array_merge( [
41 'session_id' => $this->session_id,
42 'fetch_attachments' => true,
43 ], $this->attachment_options ) );
44
45 $parsed_blocks = parse_blocks( $template_json['content'] );
46 if ( ! empty( $extra_content ) ) {
47 $this->prepare_form_data( $extra_content, $template_settings );
48 }
49 if ( isset($this->template_settings['__attachments']) ) {
50 $this->process_images();
51 // Make sure we do the longest urls first, in case one is a substring of another.
52 }
53 if(!empty($this->wp_importer->url_remap)){
54 uksort( $this->wp_importer->url_remap, function ( $a, $b ) {
55 // Return the difference in length between two strings.
56 return strlen( $b ) - strlen( $a );
57 } );
58 }
59 if(!empty($template_settings["page_settings"]["fluent_cart_store_settings"])){
60 $this->replace_fluent_cart_store_settings($template_settings["page_settings"]["fluent_cart_store_settings"]);
61 }
62 $this->replace( $parsed_blocks, $request_params );
63 $this->content = wp_slash( serialize_blocks( $parsed_blocks ) );
64
65 return $this;
66 }
67
68 /**
69 * Configure optional limits for best-effort attachment imports.
70 *
71 * @param array $options Attachment request timeout, retry count, and deadline.
72 * @return self
73 */
74 public function set_attachment_options( array $options ): self {
75 $this->attachment_options = $options;
76
77 return $this;
78 }
79
80 public function update() {
81 $this->sse_log('update', 'Updating prepared data, just a moment...', 1, 'eventLog');
82 wp_update_post( [
83 'ID' => $this->post_id,
84 'post_content' => $this->content
85 ] );
86 }
87
88 private function prepare_form_data( $extra_content, $template_settings ) {
89 foreach ( $extra_content as $type => $content ) {
90 foreach ( $content as $block_id => $value ) {
91 foreach ( $template_settings['data']['form'][ $type ] as $setting ) {
92 if ( isset( $setting['id'] ) && $setting['id'] === $block_id ) {
93 $this->forms[ $block_id ] = [
94 'value' => $value,
95 'attr' => $setting['identifier']
96 ];
97 }
98 }
99
100 }
101 }
102 }
103
104 private function replace( &$blocks, $request_params = [] ) {
105 foreach ( $blocks as &$block ) {
106 $this->sse_log('prepare', 'Preparing output for finalize, just a moment...', 1, 'eventLog');
107 if ( $block['blockName'] === 'core/navigation' ) {
108 if ( ! empty( $block['attrs']['ref'] ) && array_key_exists( $block['attrs']['ref'], $this->map_post_ids ) ) {
109 $block['attrs']['ref'] = $this->map_post_ids[ $block['attrs']['ref'] ];
110 $this->replace_archive_id( $block['attrs']['ref'] );
111 }
112 }
113 if ( isset( $block['attrs']['blockId'] ) && array_key_exists( $block['attrs']['blockId'], $this->forms ) ) {
114 $blockId = $block['attrs']['blockId'];
115 $form = $this->forms[$blockId];
116 $attr = $form['attr'];
117 $value = (string) $form['value'];
118
119 $block['attrs'][$attr] = $value;
120 }
121
122 if ( ! empty( $block['attrs']['queryData'] ) ) {
123 $this->replace_query_data( $block );
124 }
125
126 if ( isset($this->template_settings['__attachments']) ) {
127 $block = $this->replace_attachment_url( $block );
128 }
129
130 if ( ! empty( $block['innerBlocks'] ) ) {
131 $this->replace( $block['innerBlocks'], $request_params );
132 }
133 else if(!empty($request_params['logo']) && isset($request_params['logo_size']) && $request_params['logo_size'] && $block['blockName'] === "essential-blocks/advanced-image" && $block["attrs"]["imgSource"] === "site-logo"){
134 $block["attrs"]["widthRange"] = $request_params['logo_size'];
135 unset($block["attrs"]["widthUnit"]);
136 if (isset($block['attrs']['blockMeta']['desktop']) && is_string($block['attrs']['blockMeta']['desktop'])) {
137 $meta = $block['attrs']['blockMeta']['desktop'];
138 $size = $request_params['logo_size'];
139
140 // Update width inside .image-wrapper { ... } (old EB format)
141 // and .image-wrapper img { ... } (new EB format) — both must be handled
142 $meta = preg_replace(
143 '/(\.image-wrapper(?:\s+img)?\s*\{[^}]*)width\s*:\s*\d+px\s*;/',
144 '${1}width:' . $size . 'px;',
145 $meta
146 );
147
148 // Update width inside .eb-image-wrapper-inner { ... }
149 $meta = preg_replace(
150 '/(\.eb-image-wrapper-inner\s*\{[^}]*)width\s*:\s*\d+px\s*;/',
151 '${1}width:' . $size . 'px;',
152 $meta
153 );
154
155 $block['attrs']['blockMeta']['desktop'] = $meta;
156 }
157
158 $this->sse_log('prepare', 'Updated Site Logo', 1, 'eventLog');
159 }
160 }
161 }
162
163 private function replace_fluent_cart_store_settings($settings) {
164 $map_post_ids = $this->map_post_ids;
165 $saved_options = $settings;
166 $mapped_keys = [
167 'checkout_page_id',
168 'custom_payment_page_id',
169 'registration_page_id',
170 'login_page_id',
171 'cart_page_id',
172 'receipt_page_id',
173 'shop_page_id',
174 'customer_profile_page_id',
175 ];
176
177 foreach ($mapped_keys as $key) {
178 $old_id = $saved_options[$key] ?? null;
179 if (!empty($old_id) && isset($map_post_ids[$old_id])) {
180 $saved_options[$key] = $map_post_ids[$old_id];
181 }
182 else if(isset($saved_options[$key])){
183 $saved_options[$key] = 0;
184 }
185 }
186
187 update_option('fluent_cart_store_settings', $saved_options);
188 }
189
190 private function replace_archive_id( $menu_id ) {
191 if ( ! empty( $this->imported_data['archive_settings'] ) ) {
192 $post = get_post( $menu_id );
193 $blocks = parse_blocks( $post->post_content );
194 $changed = false;
195 foreach ( $blocks as &$block ) {
196 $this->sse_log('query', 'Finalizing archive settings, just a moment...', 1, 'eventLog');
197
198 if (isset($block['attrs']['id'])) {
199 $blockId = $block['attrs']['id'];
200 $archiveSettings = $this->imported_data['archive_settings'];
201
202 $archiveIds = $archiveSettings[$blockId] ?? false;
203
204 if ($archiveIds) {
205 $block['attrs']['id'] = $archiveIds['page_id'];
206 $block['attrs']['url'] = get_the_permalink($archiveIds['page_id']);
207 $changed = true;
208 }
209 }
210 }
211 if ( $changed ) {
212 wp_update_post( [
213 'ID' => $menu_id,
214 'post_content' => wp_slash( serialize_blocks( $blocks ) )
215 ] );
216 }
217 }
218 }
219
220 /**
221 * @param $block
222 *
223 * @return void
224 */
225 private function replace_query_data( &$block ) {
226 if ( ! empty( $block['attrs']['queryData']['taxonomies'] ) ) {
227 foreach ( $block['attrs']['queryData']['taxonomies'] as &$tax ) {
228 $this->sse_log('query', 'Finalizing query data, just a moment...', 1, 'eventLog');
229 $tax['value'] = json_decode( $tax['value'], true );
230 if ( ! empty( $tax['value'] ) ) {
231 foreach ( $tax['value'] as &$val ) {
232 if ( array_key_exists( $val['value'], $this->map_term_ids ) ) {
233 $val['value'] = $this->map_term_ids[ $val['value'] ];
234 }
235 }
236 }
237 $tax['value'] = json_encode( $tax['value'] );
238 }
239 }
240 $this->replace_raw_taxonomies($block);
241 if(!empty( $block['attrs']['queryData']['author'])){
242 $user = wp_get_current_user();
243 $block['attrs']['queryData']['author'] = json_encode([['label' => $user->display_name, 'value' => $user->ID]]);
244 }
245 }
246
247 /**
248 * @param $block
249 *
250 * @return void
251 */
252 private function replace_raw_taxonomies( &$block ) {
253 $types = ['category', 'tag'];
254 foreach ( $types as $type){
255 if(!empty($block['attrs']['queryData'][$type])){
256 $block['attrs']['queryData'][$type] = json_decode($block['attrs']['queryData'][$type], true);
257 foreach ($block['attrs']['queryData'][$type] as &$term){
258 $this->sse_log('prepare', 'Finalizing taxonomies, just a moment...', 1, 'eventLog');
259 if ( isset($term['value']) && array_key_exists( $term['value'], $this->map_term_ids ) ) {
260 $term['value'] = $this->map_term_ids[ $term['value'] ];
261 }
262 }
263 $block['attrs']['queryData'][$type] = json_encode($block['attrs']['queryData'][$type]);
264 }
265 }
266 }
267
268 public function replace_attachment_url($attrs) {
269 if ( !empty($attrs['blockName'] ) ) {
270 $attrs = $this->replace_attachment_ids($attrs);
271 }
272
273 if (is_string($attrs)) {
274 if ( ! empty( $this->wp_importer->url_remap ) ) {
275 $attrs = str_replace(
276 array_keys( $this->wp_importer->url_remap ),
277 array_values( $this->wp_importer->url_remap ),
278 $attrs
279 );
280 }
281 }
282 else if (is_array($attrs)) {
283 foreach ($attrs as $key => $attr) {
284 $attrs[$key] = $this->replace_attachment_url($attr);
285 }
286 }
287
288 return $attrs;
289 }
290
291 protected function replace_attachment_ids($attrs){
292 switch ($attrs['blockName']) {
293 case 'essential-blocks/slider':
294 $attrs = $this->processImages($attrs, 'images', 'imageId', 'url');
295 break;
296 case 'essential-blocks/advanced-image':
297 $attrs = $this->processSingleImage($attrs, 'image');
298 break;
299 case 'essential-blocks/parallax-slider':
300 $attrs = $this->processImages($attrs, 'sliderData', 'id', 'src');
301 break;
302 case 'essential-blocks/image-gallery':
303 $attrs = $this->processImages($attrs, 'images', 'id', 'url');
304 $attrs = $this->processImages($attrs, 'sources', 'id', 'url');
305 break;
306 case 'core/image':
307 $attrs = $this->processCoreImage($attrs, 'id');
308 break;
309 case 'core/media-text':
310 $attrs = $this->processCoreImage($attrs, 'mediaId');
311 break;
312 case 'core/cover':
313 $attrs = $this->processSingleImage($attrs, 'url');
314 break;
315 }
316 return $attrs;
317 }
318
319 private function processImages($attrs, $imageKey, $idKey, $urlKey) {
320 if (!empty($attrs['attrs'][$imageKey])) {
321 foreach ($attrs['attrs'][$imageKey] as $key => &$image) {
322 $imageUrl = $image[$urlKey];
323 if (!empty(self::$attachment_ids[$imageUrl])) {
324 $oldId = $image[$idKey];
325 $newId = (int) self::$attachment_ids[$imageUrl];
326 $image[$idKey] = $newId;
327
328 // Update innerHTML and innerContent for 'essential-blocks/slider'
329 if ($attrs['blockName'] === 'essential-blocks/slider') {
330 $attrs = $this->updateInnerHTMLAndContent($attrs, "imageId&quot;:$oldId,&quot;", "imageId&quot;:$newId,&quot;");
331 }
332 }
333 }
334 }
335 return $attrs;
336 }
337
338 private function processSingleImage($attrs, $imageKey) {
339 $image = $attrs['attrs'][$imageKey] ?? null;
340 if ( is_array( $image ) && ! empty( $image['url'] ) && ! empty( self::$attachment_ids[ $image['url'] ] ) ) {
341 $attrs['attrs'][$imageKey]['id'] = (int) self::$attachment_ids[ $image['url'] ];
342 }
343 return $attrs;
344 }
345
346 private function processCoreImage($attrs, $idKey) {
347 preg_match(self::IMAGE_URL_PATTERN, $attrs['innerHTML'], $matches);
348 if (!empty($matches[0])) {
349 $url = $matches[0];
350 if (!empty(self::$attachment_ids[$url])) {
351 $oldId = $attrs['attrs'][$idKey];
352 $newId = (int) self::$attachment_ids[$url];
353 $attrs['attrs'][$idKey] = $newId;
354
355 // Replace old ID with new ID in innerHTML and innerContent
356 $attrs = $this->updateInnerHTMLAndContent($attrs, "wp-image-$oldId", "wp-image-$newId");
357 }
358 }
359 return $attrs;
360 }
361
362 private function updateInnerHTMLAndContent($attrs, $oldValue, $newValue) {
363 $attrs['innerHTML'] = str_replace($oldValue, $newValue, $attrs['innerHTML']);
364 if (is_array($attrs['innerContent'])) {
365 foreach ($attrs['innerContent'] as $i => $content) {
366 $attrs['innerContent'][$i] = str_replace($oldValue, $newValue, $content);
367 }
368 } else {
369 $attrs['innerContent'] = str_replace($oldValue, $newValue, $attrs['innerContent']);
370 }
371 return $attrs;
372 }
373
374 /**
375 * Parses the images from the post content, processes them as attachments, and updates the post with the new attachment URL.
376 * @todo: Parse using parse_blocks instead of regex
377 *
378 * @param int $post_id The ID of the post.
379 * @param string $post_content The content of the post.
380 */
381 public function parse_images($post_content) {
382 // Find all image URLs in the post content
383 preg_match_all(self::IMAGE_URL_PATTERN, $post_content, $matches);
384
385 $urls = $matches[0];
386 $organizedUrls = [];
387
388 foreach ($urls as $url) {
389 // Remove the size suffix from the URL
390 $base_url = preg_replace('/-\d+x\d+(?=\.[a-zA-Z]+$)/', '', $url);
391
392 // Check if the URL already exists in the array
393 if (!isset($organizedUrls[$base_url]) || !in_array($url, $organizedUrls[$base_url])) {
394 // Add the URL to the array under the base URL key
395 $organizedUrls[$base_url][] = $url;
396 }
397 }
398
399 return $organizedUrls;
400 }
401
402 public function process_images(){
403 // Time to run the import!
404 set_time_limit( 0 );
405
406 $organizedUrls = $this->template_settings['__attachments'];
407 $deadline = ! empty( $this->attachment_options['attachment_deadline'] )
408 ? (float) $this->attachment_options['attachment_deadline']
409 : null;
410 // Tell the importer what is coming, so it can fetch a few at a time in parallel rather
411 // than one by one. Optional on its side: an importer without the method imports the
412 // old way.
413 if ( $this->wp_importer && method_exists( $this->wp_importer, 'prefetch_attachments' ) ) {
414 $this->wp_importer->prefetch_attachments( array_keys( (array) $organizedUrls ) );
415 }
416
417 // For each base image URL...
418 foreach ($organizedUrls as $base_url => $sizes) {
419 if ( $deadline && microtime( true ) >= $deadline ) {
420 $this->sse_log( 'warning', 'Skipping remaining attachments after the import time limit.', -1, 'eventLog' );
421 break;
422 }
423
424 // Prepare the post data for the attachment
425 $post_data = $this->prepare_post_data($this->post_id, $base_url);
426
427 // If prepare_post_data returned null, skip this iteration
428 if ($post_data === null) {
429 continue;
430 }
431
432 foreach ($sizes as $key => $size) {
433 if ($base_url == $size) {
434 unset($sizes[$key]);
435 continue;
436 }
437
438 // $size url string; get width height from the image url
439 preg_match('/-(\d+)x(\d+)\.[a-zA-Z]+$/', $size, $matches);
440 if (isset($matches[1]) && isset($matches[2])) {
441 $sizes[$key] = [
442 'file' => basename($size),
443 'width' => $matches[1],
444 'height' => $matches[2]
445 ];
446 } else {
447 unset($sizes[$key]);
448 }
449 }
450
451 // Check if the attachment already exists
452 $attachment_id = $this->wp_importer->process_attachment($post_data, $base_url, $sizes);
453 // If there was an error, handle it here
454 if (is_wp_error($attachment_id)) {
455 $this->sse_log('error', $attachment_id->get_error_message(), -1, 'eventLog');
456 } else {
457 $this->sse_log('success', "Imported attachment: $attachment_id", -1, 'eventLog');
458 self::$attachment_ids[$base_url] = $attachment_id;
459 }
460 }
461 }
462
463 private function prepare_post_data($post_id, $image_url) {
464 return Utils::prepare_post_data($image_url, $post_id, [$this, 'sse_log']);
465 }
466
467 public function sse_log( $type, $message, $progress = 1, $action = 'updateLog', $status = null ) {
468 if ($this->shouldLog) {
469 parent::sse_log($type, $message, $progress, $action, $status);
470 }
471 else{
472 Helper::log(func_get_args());
473 }
474 }
475
476 public function get_content(){
477 return $this->content;
478 }
479
480 }
481