PluginProbe
Elementor Website Builder – more than just a page builder / 4.3.0
Elementor Website Builder – more than just a page builder v4.3.0
4.3.0 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 All 453 releases
elementor / modules / mcp / abilities / publish-document-ability.php

publish-document-ability.php in Elementor Website Builder – more than just a page builder 4.3.0, at modules/mcp/abilities/publish-document-ability.php

154 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\History\Revisions_Manager;
6 use Elementor\Modules\Mcp\Abilities\Utils\Document_Mutation_Links;
7 use Elementor\Plugin;
8
9 if ( ! defined( 'ABSPATH' ) ) {
10 exit;
11 }
12
13 class Publish_Document_Ability extends Abstract_Ability {
14
15 protected function get_ability_id(): string {
16 return 'elementor/publish-document';
17 }
18
19 public function is_exposed_via_proxy(): bool {
20 return false;
21 }
22
23 protected function get_definition(): Ability_Definition {
24 return new Ability_Definition(
25 __( 'Publish Elementor Document', 'elementor' ),
26 __( 'Transitions an Elementor document (page, post, theme template, popup) to `publish` so it appears on the front end. Call this AFTER all element edits are complete. Edits via manage-elements or build-composition on published pages are staged in an autosave; calling this promotes the staged autosave to the live document. When there are no pending edits on an already-published document, the call is a no-op success.', 'elementor' ),
27 'elementor',
28 [
29 'type' => 'object',
30 'properties' => [
31 'post_id' => [ 'type' => 'integer' ],
32 'status' => [ 'type' => 'string' ],
33 'previous_status' => [ 'type' => 'string' ],
34 'preview_url' => Document_Mutation_Links::preview_schema_property(),
35 'llm_instructions' => Document_Mutation_Links::llm_instructions_schema_property(),
36 ],
37 ],
38 [
39 'annotations' => [
40 'readonly' => false,
41 'idempotent' => true,
42 'destructive' => true,
43 ],
44 ],
45 function () {
46 return current_user_can( 'edit_posts' );
47 },
48 [
49 'type' => 'object',
50 'required' => [ 'post_id' ],
51 'properties' => [
52 'post_id' => [
53 'type' => 'integer',
54 'description' => 'WordPress post ID of the Elementor document to publish.',
55 ],
56 ],
57 ]
58 );
59 }
60
61 public function execute( $input = [] ) {
62 $post_id = isset( $input['post_id'] ) ? absint( $input['post_id'] ) : 0;
63
64 if ( ! $post_id ) {
65 return new \WP_Error(
66 'invalid_post_id',
67 __( 'A valid post_id is required.', 'elementor' ),
68 [ 'status' => \WP_Http::BAD_REQUEST ]
69 );
70 }
71
72 if ( wp_is_post_revision( $post_id ) ) {
73 return new \WP_Error(
74 'invalid_post_id',
75 __( 'Revision IDs cannot be published. Pass the parent document ID.', 'elementor' ),
76 [ 'status' => \WP_Http::BAD_REQUEST ]
77 );
78 }
79
80 $document = Plugin::$instance->documents->get( $post_id );
81
82 if ( ! $document ) {
83 return new \WP_Error(
84 'document_not_found',
85 __( 'Document not found.', 'elementor' ),
86 [ 'status' => \WP_Http::NOT_FOUND ]
87 );
88 }
89
90 $main_id = $document->get_main_id();
91
92 if ( ! current_user_can( 'publish_post', $main_id ) ) {
93 return new \WP_Error(
94 'rest_cannot_publish',
95 __( 'Sorry, you are not allowed to publish this document.', 'elementor' ),
96 [ 'status' => \WP_Http::FORBIDDEN ]
97 );
98 }
99
100 $previous_status = get_post_status( $main_id );
101
102 $this->promote_pending_autosave( $main_id );
103
104 if ( 'publish' !== $previous_status ) {
105 $updated = wp_update_post(
106 [
107 'ID' => $main_id,
108 'post_status' => 'publish',
109 ],
110 true
111 );
112
113 if ( is_wp_error( $updated ) ) {
114 return $updated;
115 }
116 }
117
118 return $this->build_success_response( $document, get_post_status( $main_id ), $previous_status );
119 }
120
121 /**
122 * Promote the current user's pending autosave (created by MCP element writes on live posts)
123 * onto the main document, then discard the autosave slot — mirroring what the editor's own
124 * publish flow does in `Page\Manager::save`.
125 *
126 * Reuses `Revisions_Manager::restore_revision` so ALL `_elementor*` meta (data, page settings,
127 * CSS cache, etc.) is copied consistently and Post CSS is regenerated. Running before the
128 * `wp_update_post` status transition means listeners on `transition_post_status` (Post CSS,
129 * CDN purges, sitemaps, etc.) see the promoted content on the very same request.
130 */
131 private function promote_pending_autosave( int $main_id ): void {
132 $autosave_post = wp_get_post_autosave( $main_id, get_current_user_id() );
133
134 if ( ! $autosave_post ) {
135 return;
136 }
137
138 Revisions_Manager::restore_revision( $main_id, $autosave_post->ID );
139
140 wp_delete_post_revision( $autosave_post->ID );
141 }
142
143 private function build_success_response( $document, string $status, string $previous_status ): array {
144 return [
145 'post_id' => (int) $document->get_main_id(),
146 'status' => $status,
147 'previous_status' => $previous_status,
148 ] + Document_Mutation_Links::for_document(
149 $document,
150 __( 'Document published.', 'elementor' )
151 );
152 }
153 }
154