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 / mcp-abilities / Editor / ElementorHeadlessInsert.php

ElementorHeadlessInsert.php in Templately – Elementor & Gutenberg Template Library: 6500+ Free & Pro Ready Templates And Cloud! 3.8.0, at modules/mcp-abilities/Editor/ElementorHeadlessInsert.php

83 lines 2.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Headless (browser-free) Elementor content insertion into an EXISTING post
4 * (FR-006, FR-009, FR-014) — the new capability this feature introduces.
5 * Modeled on this environment's own proven sandbox-abilities technique
6 * (research.md §3), reimplemented fresh here.
7 *
8 * @package Templately\Modules\McpAbilities\Editor
9 */
10
11 namespace Templately\Modules\McpAbilities\Editor;
12
13 use Elementor\Core\Files\CSS\Post as ElementorPostCSS;
14 use Elementor\Plugin as ElementorPlugin;
15 use WP_Error;
16
17 class ElementorHeadlessInsert {
18
19 /**
20 * @param int $post_id
21 * @param array $elements Processed Elementor element nodes to append (from the
22 * `/import/insert` route's response `content`, research.md §3).
23 * @param string $base_hash md5 of `_elementor_data` as last read by the caller (FR-014).
24 * @return array|WP_Error
25 */
26 public static function insert( int $post_id, array $elements, string $base_hash ) {
27 if ( ! class_exists( ElementorPlugin::class ) ) {
28 return new WP_Error( 'platform_mismatch', __( 'Elementor is not active on this site.', 'templately' ) );
29 }
30
31 // Conflict-checking only reads post meta, so it is verified before the
32 // (more expensive) document-validity check — a caller's stale read is
33 // reported as a conflict regardless of the post's editor type.
34 $current_hash = self::hash( $post_id );
35
36 if ( $current_hash !== $base_hash ) {
37 return new WP_Error(
38 'conflict',
39 __( 'The post changed since it was last read. Re-read it and retry.', 'templately' ),
40 [ 'current_state_hash' => $current_hash ]
41 );
42 }
43
44 $document = ElementorPlugin::$instance->documents->get( $post_id );
45
46 if ( ! $document ) {
47 return new WP_Error( 'platform_mismatch', __( 'The target post is not an Elementor document.', 'templately' ) );
48 }
49
50 $tree = array_merge( $document->get_elements_data(), $elements );
51 $saved = $document->save( [ 'elements' => $tree ] );
52
53 if ( ! $saved ) {
54 return new WP_Error( 'import_failed', __( 'Failed to save Elementor content into the target post.', 'templately' ) );
55 }
56
57 update_post_meta( $post_id, '_elementor_edit_mode', 'builder' );
58 self::regenerate_css( $post_id );
59
60 return [
61 'target' => 'post',
62 'status' => 'success',
63 'post_id' => $post_id,
64 ];
65 }
66
67 /**
68 * @param int $post_id
69 * @return string
70 */
71 public static function hash( int $post_id ): string {
72 return md5( (string) get_post_meta( $post_id, '_elementor_data', true ) );
73 }
74
75 private static function regenerate_css( int $post_id ): void {
76 delete_post_meta( $post_id, '_elementor_css' );
77
78 if ( class_exists( ElementorPostCSS::class ) ) {
79 ElementorPostCSS::create( $post_id )->update();
80 }
81 }
82 }
83