PluginProbe
Elementor Website Builder – more than just a page builder / 4.3.0-beta3
Elementor Website Builder – more than just a page builder v4.3.0-beta3
4.3.0-beta3 4.3.0-beta2 4.3.0-beta1 4.2.4 4.2.3 4.2.2 4.2.1 4.2.0 4.1.5 4.2.0-beta2 4.2.0-dev2 4.2.0-beta1 4.1.4 4.1.3 4.1.2 4.1.1 4.1.0 4.1.0-beta3 4.1.0-dev3 4.0.9 4.1.0-beta2 4.1.0-dev2 4.0.8 4.1.0-beta1 4.1.0-dev1 All 452 releases
elementor / modules / mcp / abilities / create-preview-link-ability.php

create-preview-link-ability.php in Elementor Website Builder – more than just a page builder 4.3.0-beta3, at modules/mcp/abilities/create-preview-link-ability.php

173 lines 4.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Elementor\Modules\Mcp\Abilities;
4
5 use Elementor\Modules\Mcp\Abilities\Utils\Prompt_Loader;
6 use Elementor\Modules\Mcp\Preview\Preview_Token;
7 use Elementor\Plugin;
8
9 if ( ! defined( 'ABSPATH' ) ) {
10 exit;
11 }
12
13 class Create_Preview_Link_Ability extends Abstract_Ability {
14
15 const TTL_MINUTES = 5;
16
17 protected function get_ability_id(): string {
18 return 'elementor/create-preview-link';
19 }
20
21 public function is_exposed_via_proxy(): bool {
22 return false;
23 }
24
25 protected function get_definition(): Ability_Definition {
26 return new Ability_Definition(
27 __( 'Create Elementor Public Preview Link', 'elementor' ),
28 Prompt_Loader::load( 'create-preview-link' ),
29 'elementor',
30 [
31 'type' => 'object',
32 'properties' => [
33 'url' => [
34 'type' => 'string',
35 'format' => 'uri',
36 'description' => 'Anonymous, time-limited preview URL. For the agent to self-validate rendering. DO NOT share with the user.',
37 ],
38 'edit_url' => [
39 'type' => 'string',
40 'format' => 'uri',
41 'description' => 'Elementor editor URL for the post. Share THIS with the user when they need a link (they must be logged into WordPress as an editor).',
42 ],
43 'post_id' => [ 'type' => 'integer' ],
44 'revision_id' => [ 'type' => 'integer' ],
45 'expires_at' => [
46 'type' => 'string',
47 'format' => 'date-time',
48 ],
49 'expires_at_unix' => [ 'type' => 'integer' ],
50 ],
51 ],
52 [
53 'annotations' => [
54 'readonly' => false,
55 'idempotent' => false,
56 'destructive' => false,
57 ],
58 ],
59 function ( $input = [] ) {
60 $post_id = is_array( $input ) && isset( $input['post_id'] ) ? (int) $input['post_id'] : 0;
61
62 return $post_id > 0 && current_user_can( 'edit_post', $post_id );
63 },
64 [
65 'type' => 'object',
66 'required' => [ 'post_id' ],
67 'properties' => [
68 'post_id' => [
69 'type' => 'integer',
70 'description' => 'Post ID to snapshot and share.',
71 ],
72 ],
73 ]
74 );
75 }
76
77 public function execute( $input = [] ) {
78 $input = is_array( $input ) ? $input : [];
79
80 $post_id = isset( $input['post_id'] ) ? (int) $input['post_id'] : 0;
81
82 $post_error = $this->validate_post( $post_id );
83 if ( $post_error ) {
84 return $post_error;
85 }
86
87 $permission_error = $this->check_edit_permission( $post_id );
88 if ( $permission_error ) {
89 return $permission_error;
90 }
91
92 $revision_id = $this->snapshot_revision( $post_id );
93 if ( is_wp_error( $revision_id ) ) {
94 return $revision_id;
95 }
96
97 $expires_at = time() + self::TTL_MINUTES * MINUTE_IN_SECONDS;
98 $token = Preview_Token::encode( $post_id, $revision_id, $expires_at, Preview_Token::secret() );
99 $document = Plugin::$instance->documents->get( $post_id );
100
101 return [
102 'url' => add_query_arg( Preview_Token::QUERY_ARG, $token, home_url( '/' ) ),
103 'edit_url' => $document ? $document->get_edit_url() : '',
104 'post_id' => $post_id,
105 'revision_id' => $revision_id,
106 'expires_at' => gmdate( 'c', $expires_at ),
107 'expires_at_unix' => $expires_at,
108 ];
109 }
110
111 private function validate_post( int $post_id ): ?\WP_Error {
112 if ( $post_id <= 0 || ! get_post( $post_id ) ) {
113 return new \WP_Error(
114 'invalid_post',
115 __( 'Post not found.', 'elementor' ),
116 [ 'status' => \WP_Http::NOT_FOUND ]
117 );
118 }
119
120 $document = Plugin::$instance->documents->get( $post_id );
121
122 if ( ! $document || ! $document->is_built_with_elementor() ) {
123 return new \WP_Error(
124 'not_elementor_post',
125 __( 'This post is not built with Elementor.', 'elementor' ),
126 [ 'status' => \WP_Http::BAD_REQUEST ]
127 );
128 }
129
130 return null;
131 }
132
133 private function check_edit_permission( int $post_id ): ?\WP_Error {
134 if ( ! current_user_can( 'edit_post', $post_id ) ) {
135 return new \WP_Error(
136 'rest_cannot_edit',
137 __( 'Sorry, you are not allowed to share a preview of this post.', 'elementor' ),
138 [ 'status' => \WP_Http::FORBIDDEN ]
139 );
140 }
141
142 return null;
143 }
144
145 private function snapshot_revision( int $post_id ) {
146 $revision_id = wp_save_post_revision( $post_id );
147
148 if ( is_wp_error( $revision_id ) ) {
149 return $revision_id;
150 }
151
152 if ( ! $revision_id ) {
153 $latest = wp_get_post_revisions( $post_id, [
154 'posts_per_page' => 1,
155 'orderby' => 'ID',
156 'order' => 'DESC',
157 ] );
158
159 $revision_id = $latest ? (int) array_key_first( $latest ) : 0;
160 }
161
162 if ( ! $revision_id ) {
163 return new \WP_Error(
164 'revision_failed',
165 __( 'Could not create a revision snapshot for this post.', 'elementor' ),
166 [ 'status' => \WP_Http::INTERNAL_SERVER_ERROR ]
167 );
168 }
169
170 return (int) $revision_id;
171 }
172 }
173