PluginProbe ʕ •ᴥ•ʔ
Elementor Website Builder – more than just a page builder / 3.6.8
Elementor Website Builder – more than just a page builder v3.6.8
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 4.0.7 4.0.6 4.0.5 4.0.4 4.0.3 3.22.0-dev1 4.0.0-beta3 3.22.0-dev2 4.0.0-beta4 3.22.0-dev3 4.0.0-beta5 3.22.0-dev4 4.0.0-dev1 3.22.0-dev5 4.0.0-dev2 3.22.0-dev6 4.0.0-dev3 3.22.1 4.0.0-dev4 3.22.2 4.0.0-dev5 3.22.3 4.0.1 3.23.0 4.0.2 3.23.0-beta1 3.23.0-beta2 3.23.0-beta3 3.23.0-beta4 3.23.0-beta5 3.23.0-beta6 3.23.0-dev1 3.23.0-dev2 3.23.0-dev3 3.23.0-dev4 3.23.0-dev5 3.23.0-dev6 3.23.1 3.23.2 3.23.3 3.23.4 3.24.0 3.24.0-beta1 3.24.0-beta2 3.24.0-beta3 3.24.0-dev1 3.24.0-dev2 3.24.0-dev3 3.24.1 3.24.2 3.24.3 3.24.4 3.24.5 3.24.6 3.24.7 3.24.8 3.25.0 3.25.0-beta1 3.25.0-beta2 3.25.0-beta3 3.25.0-dev1 3.25.0-dev2 3.25.0-dev3 3.25.1 3.25.10 3.25.11 3.25.2 3.25.3 3.25.4 3.25.5 3.25.6 3.25.7 3.25.8 3.25.9 3.26.0 3.26.0-beta1 3.26.0-beta2 3.26.0-beta3 3.26.0-beta4 3.26.0-beta5 3.26.0-dev1 3.26.0-dev2 3.26.0-dev3 3.26.0-dev4 3.26.0-dev5 3.26.1 3.26.2 3.26.3 3.26.4 3.26.5 3.27.0 3.27.0-beta1 3.27.0-beta2 3.27.0-dev1 3.27.0-dev2 3.27.1 3.27.2 3.27.3 3.27.4 3.27.5 3.27.6 3.27.7 3.28.0 3.28.0-beta1 3.28.0-beta2 3.28.0-beta3 3.28.0-dev1 3.28.0-dev2 3.28.0-dev3 3.28.1 3.28.2 3.28.3 3.28.4 3.29.0 3.29.0-beta1 trunk 3.29.0-beta2 3.0.0 3.29.0-beta3 3.0.1 3.29.0-beta4 3.0.10 3.29.0-dev1 3.0.11 3.29.0-dev2 3.0.12 3.29.0-dev3 3.0.13 3.29.0-dev4 3.0.14 3.29.1 3.0.15 3.29.2 3.0.16 3.3.0 3.0.2 3.3.1 3.0.3 3.30.0 3.0.4 3.30.0-beta1 3.0.5 3.30.0-beta2 3.0.6 3.30.0-beta3 3.0.7 3.30.0-dev1 3.0.8 3.30.0-dev2 3.0.8.1 3.30.0-dev3 3.0.9 3.30.1 3.1.0 3.30.2 3.1.0-beta1 3.30.3 3.1.0-beta2 3.30.4 3.1.0-beta3 3.31.0 3.1.0-beta4 3.31.0-beta1 3.1.0-dev1 3.31.0-beta2 3.1.0-dev2 3.31.0-dev1 3.1.0-dev3 3.31.0-dev2 3.1.1 3.31.1 3.1.2 3.31.2 3.1.3 3.31.3 3.1.4 3.31.4 3.10.0 3.31.5 3.10.0-dev1 3.32.0 3.10.1 3.32.0-beta1 3.10.2 3.32.0-beta2 3.11.0 3.32.0-beta3 3.11.0-beta1 3.32.0-dev1 3.11.0-beta2 3.32.0-dev2 3.11.0-beta3 3.32.0-dev3 3.11.0-dev1 3.32.1 3.11.0-dev2 3.32.2 3.11.0-dev3 3.32.3 3.11.1 3.32.4 3.11.2 3.32.5 3.11.3 3.33.0 3.11.4 3.33.0-beta1 3.11.5 3.33.0-beta2 3.12.0 3.33.0-beta3 3.12.1 3.33.0-beta4 3.12.2 3.33.0-dev1 3.13.0 3.33.0-dev2 3.13.0-beta1 3.33.0-dev3 3.13.0-beta2 3.33.0-dev4 3.13.0-beta3 3.33.1 3.13.0-dev3 3.33.2 3.13.0-dev4 3.33.3 3.13.1 3.33.4 3.13.2 3.33.5 3.13.3 3.33.6 3.13.4 3.34.0 3.14.0 3.34.0-beta1 3.14.0-beta1 3.34.0-beta2 3.14.0-beta2 3.34.0-beta3 3.14.0-beta3 3.34.0-dev1 3.14.0-beta4 3.34.0-dev2 3.14.0-beta5 3.34.1 3.14.1 3.34.2 3.15.0 3.34.3 3.15.1 3.34.4 3.15.2 3.35.0 3.15.3 3.35.0-beta1 3.16.0 3.35.0-beta2 3.16.0-beta3 3.35.0-beta3 3.16.0-beta4 3.35.0-beta4 3.16.0-dev1 3.35.0-dev1 3.16.0-dev2 3.35.0-dev2 3.16.1 3.35.0-dev3 3.16.2 3.35.0-dev4 3.16.3 3.35.1 3.16.4 3.35.2 3.16.5 3.35.3 3.16.6 3.35.4 3.17.0 3.35.5 3.17.0-dev2 3.35.6 3.17.0-dev3 3.35.7 3.17.0-dev4 3.35.8 3.17.1 3.35.9 3.17.2 3.4.0 3.17.3 3.4.0-dev7 3.18.0 3.4.0-dev8 3.18.0-beta1 3.4.0-dev9 3.18.0-beta2 3.4.1 3.18.0-beta3 3.4.2 3.18.0-beta4 3.4.3 3.18.0-dev1 3.4.4 3.18.1 3.4.5 3.18.2 3.4.6 3.18.3 3.4.7 3.19.0 3.4.8 3.19.0-beta1 3.5.0 3.19.0-beta2 3.5.0-beta1 3.19.0-beta3 3.5.0-beta2 3.19.0-beta4 3.5.0-beta3 3.19.0-beta5 3.5.0-beta4 3.19.0-beta6 3.5.0-beta5 3.19.0-dev1 3.5.0-beta7 3.19.0-dev2 3.5.0-beta8 3.19.0-dev3 3.5.0-dev8 3.19.0-dev4 3.5.0-dev9 3.19.0-dev5 3.5.1 3.19.0-dev6 3.5.2 3.19.1 3.5.3 3.19.2 3.5.4 3.19.3 3.5.5 3.19.4 3.5.6 3.2.0 3.6.0 3.2.1 3.6.0-beta1 3.2.2 3.6.0-beta2 3.2.3 3.6.0-beta3 3.2.4 3.6.0-beta4 3.2.5 3.6.0-beta5 3.20.0 3.6.0-dev1 3.20.0-beta1 3.6.0-dev10 3.20.0-beta2 3.6.1 3.20.0-beta3 3.6.2 3.20.0-beta4 3.6.3 3.20.0-dev1 3.6.4 3.20.0-dev2 3.6.5 3.20.0-dev3 3.6.6 3.20.0-dev4 3.6.7 3.20.1 3.6.8 3.20.2 3.7.0 3.20.3 3.7.0-beta1 3.20.4 3.7.0-beta2 3.21.0 3.7.0-beta3 3.21.0-beta1 3.7.0-beta4 3.21.0-beta2 3.7.0-dev1 3.21.0-beta3 3.7.1 3.21.0-dev1 3.7.2 3.21.0-dev2 3.7.3 3.21.0-dev3 3.7.4 3.21.1 3.7.5 3.21.2 3.7.6 3.21.3 3.7.7 3.21.4 3.7.8 3.21.5 3.8.0 3.21.6 3.8.0-beta1 3.21.7 3.8.0-beta2 3.21.8 3.8.0-beta3 3.22.0 3.8.1 3.22.0-beta1 3.9.0 3.22.0-beta2 3.9.1 3.22.0-beta3 3.9.2 3.22.0-beta4 4.0.0 3.22.0-beta5 4.0.0-beta1 3.22.0-beta6 4.0.0-beta2
elementor / modules / history / revisions-manager.php
elementor / modules / history Last commit date
views 4 years ago module.php 5 years ago revisions-manager.php 4 years ago
revisions-manager.php
422 lines
1 <?php
2 namespace Elementor\Modules\History;
3
4 use Elementor\Core\Base\Document;
5 use Elementor\Core\Common\Modules\Ajax\Module as Ajax;
6 use Elementor\Core\Files\CSS\Post as Post_CSS;
7 use Elementor\Plugin;
8 use Elementor\Utils;
9
10 if ( ! defined( 'ABSPATH' ) ) {
11 exit; // Exit if accessed directly.
12 }
13
14 /**
15 * Elementor history revisions manager.
16 *
17 * Elementor history revisions manager handler class is responsible for
18 * registering and managing Elementor revisions manager.
19 *
20 * @since 1.7.0
21 */
22 class Revisions_Manager {
23
24 /**
25 * Maximum number of revisions to display.
26 */
27 const MAX_REVISIONS_TO_DISPLAY = 100;
28
29 /**
30 * Authors list.
31 *
32 * Holds all the authors.
33 *
34 * @access private
35 *
36 * @var array
37 */
38 private static $authors = [];
39
40 /**
41 * History revisions manager constructor.
42 *
43 * Initializing Elementor history revisions manager.
44 *
45 * @since 1.7.0
46 * @access public
47 */
48 public function __construct() {
49 self::register_actions();
50 }
51
52 /**
53 * @since 1.7.0
54 * @access public
55 * @static
56 */
57 public static function handle_revision() {
58 add_filter( 'wp_save_post_revision_check_for_changes', '__return_false' );
59 }
60
61 /**
62 * @since 2.0.0
63 * @access public
64 * @static
65 *
66 * @param $post_content
67 * @param $post_id
68 *
69 * @return string
70 */
71 public static function avoid_delete_auto_save( $post_content, $post_id ) {
72 // Add a temporary string in order the $post will not be equal to the $autosave
73 // in edit-form-advanced.php:210
74 $document = Plugin::$instance->documents->get( $post_id );
75
76 if ( $document && $document->is_built_with_elementor() ) {
77 $post_content .= '<!-- Created with Elementor -->';
78 }
79
80 return $post_content;
81 }
82
83 /**
84 * @since 2.0.0
85 * @access public
86 * @static
87 */
88 public static function remove_temp_post_content() {
89 global $post;
90
91 $document = Plugin::$instance->documents->get( $post->ID );
92
93 if ( ! $document || ! $document->is_built_with_elementor() ) {
94 return;
95 }
96
97 $post->post_content = str_replace( '<!-- Created with Elementor -->', '', $post->post_content );
98 }
99
100 /**
101 * @since 1.7.0
102 * @access public
103 * @static
104 *
105 * @param int $post_id
106 * @param array $query_args
107 * @param bool $parse_result
108 *
109 * @return array
110 */
111 public static function get_revisions( $post_id = 0, $query_args = [], $parse_result = true ) {
112 $post = get_post( $post_id );
113
114 if ( ! $post || empty( $post->ID ) ) {
115 return [];
116 }
117
118 $revisions = [];
119
120 $default_query_args = [
121 'posts_per_page' => self::MAX_REVISIONS_TO_DISPLAY,
122 'meta_key' => '_elementor_data',
123 ];
124
125 $query_args = array_merge( $default_query_args, $query_args );
126
127 $posts = wp_get_post_revisions( $post->ID, $query_args );
128
129 if ( ! wp_revisions_enabled( $post ) ) {
130 $autosave = Utils::get_post_autosave( $post->ID );
131 if ( $autosave ) {
132 if ( $parse_result ) {
133 array_unshift( $posts, $autosave );
134 } else {
135 array_unshift( $posts, $autosave->ID );
136 }
137 }
138 }
139
140 if ( $parse_result ) {
141 array_unshift( $posts, $post );
142 } else {
143 array_unshift( $posts, $post->ID );
144 return $posts;
145 }
146
147 $current_time = current_time( 'timestamp' );
148
149 /** @var \WP_Post $revision */
150 foreach ( $posts as $revision ) {
151 $date = date_i18n( _x( 'M j @ H:i', 'revision date format', 'elementor' ), strtotime( $revision->post_modified ) );
152
153 $human_time = human_time_diff( strtotime( $revision->post_modified ), $current_time );
154
155 if ( $revision->ID === $post->ID ) {
156 $type = 'current';
157 $type_label = esc_html__( 'Current Version', 'elementor' );
158 } elseif ( false !== strpos( $revision->post_name, 'autosave' ) ) {
159 $type = 'autosave';
160 $type_label = esc_html__( 'Autosave', 'elementor' );
161 } else {
162 $type = 'revision';
163 $type_label = esc_html__( 'Revision', 'elementor' );
164 }
165
166 if ( ! isset( self::$authors[ $revision->post_author ] ) ) {
167 self::$authors[ $revision->post_author ] = [
168 'avatar' => get_avatar( $revision->post_author, 22 ),
169 'display_name' => get_the_author_meta( 'display_name', $revision->post_author ),
170 ];
171 }
172
173 $revisions[] = [
174 'id' => $revision->ID,
175 'author' => self::$authors[ $revision->post_author ]['display_name'],
176 'timestamp' => strtotime( $revision->post_modified ),
177 'date' => sprintf(
178 /* translators: 1: Human readable time difference, 2: Date. */
179 __( '%1$s ago (%2$s)', 'elementor' ),
180 $human_time,
181 $date
182 ),
183 'type' => $type,
184 'typeLabel' => $type_label,
185 'gravatar' => self::$authors[ $revision->post_author ]['avatar'],
186 ];
187 }
188
189 return $revisions;
190 }
191
192 /**
193 * @since 1.9.2
194 * @access public
195 * @static
196 */
197 public static function update_autosave( $autosave_data ) {
198 self::save_revision( $autosave_data['ID'] );
199 }
200
201 /**
202 * @since 1.7.0
203 * @access public
204 * @static
205 */
206 public static function save_revision( $revision_id ) {
207 $parent_id = wp_is_post_revision( $revision_id );
208
209 if ( $parent_id ) {
210 Plugin::$instance->db->safe_copy_elementor_meta( $parent_id, $revision_id );
211 }
212 }
213
214 /**
215 * @since 1.7.0
216 * @access public
217 * @static
218 */
219 public static function restore_revision( $parent_id, $revision_id ) {
220 $parent = Plugin::$instance->documents->get( $parent_id );
221 $revision = Plugin::$instance->documents->get( $revision_id );
222
223 if ( ! $parent || ! $revision ) {
224 return;
225 }
226
227 $is_built_with_elementor = $revision->is_built_with_elementor();
228
229 $parent->set_is_built_with_elementor( $is_built_with_elementor );
230
231 if ( ! $is_built_with_elementor ) {
232 return;
233 }
234
235 Plugin::$instance->db->copy_elementor_meta( $revision_id, $parent_id );
236
237 $post_css = Post_CSS::create( $parent_id );
238
239 $post_css->update();
240 }
241
242 /**
243 * @since 2.3.0
244 * @access public
245 * @static
246 *
247 * @param $data
248 *
249 * @return array
250 * @throws \Exception
251 */
252 public static function ajax_get_revision_data( array $data ) {
253 if ( ! isset( $data['id'] ) ) {
254 throw new \Exception( 'You must set the revision ID.' );
255 }
256
257 $revision = Plugin::$instance->documents->get( $data['id'] );
258
259 if ( ! $revision ) {
260 throw new \Exception( 'Invalid revision.' );
261 }
262
263 if ( ! current_user_can( 'edit_post', $revision->get_id() ) ) {
264 throw new \Exception( esc_html__( 'Access denied.', 'elementor' ) );
265 }
266
267 $revision_data = [
268 'settings' => $revision->get_settings(),
269 'elements' => $revision->get_elements_data(),
270 ];
271
272 return $revision_data;
273 }
274
275 /**
276 * @since 1.7.0
277 * @access public
278 * @static
279 */
280 public static function add_revision_support_for_all_post_types() {
281 $post_types = get_post_types_by_support( 'elementor' );
282 foreach ( $post_types as $post_type ) {
283 add_post_type_support( $post_type, 'revisions' );
284 }
285 }
286
287 /**
288 * @since 2.0.0
289 * @access public
290 * @static
291 * @param array $return_data
292 * @param Document $document
293 *
294 * @return array
295 */
296 public static function on_ajax_save_builder_data( $return_data, $document ) {
297 $post_id = $document->get_main_id();
298
299 $latest_revisions = self::get_revisions(
300 $post_id, [
301 'posts_per_page' => 1,
302 ]
303 );
304
305 $all_revision_ids = self::get_revisions(
306 $post_id, [
307 'fields' => 'ids',
308 ], false
309 );
310
311 // Send revisions data only if has revisions.
312 if ( ! empty( $latest_revisions ) ) {
313 $current_revision_id = self::current_revision_id( $post_id );
314
315 $return_data = array_replace_recursive( $return_data, [
316 'config' => [
317 'document' => [
318 'revisions' => [
319 'current_id' => $current_revision_id,
320 ],
321 ],
322 ],
323 'latest_revisions' => $latest_revisions,
324 'revisions_ids' => $all_revision_ids,
325 ] );
326 }
327
328 return $return_data;
329 }
330
331 /**
332 * @since 1.7.0
333 * @access public
334 * @static
335 */
336 public static function db_before_save( $status, $has_changes ) {
337 if ( $has_changes ) {
338 self::handle_revision();
339 }
340 }
341
342 public static function document_config( $settings, $post_id ) {
343 $settings['revisions'] = [
344 'enabled' => ( $post_id && wp_revisions_enabled( get_post( $post_id ) ) ),
345 'current_id' => self::current_revision_id( $post_id ),
346 ];
347
348 return $settings;
349 }
350
351 /**
352 * Localize settings.
353 *
354 * Add new localized settings for the revisions manager.
355 *
356 * Fired by `elementor/editor/editor_settings` filter.
357 *
358 * @since 1.7.0
359 * @access public
360 * @static
361 * @deprecated 3.1.0
362 */
363 public static function editor_settings() {
364 Plugin::$instance->modules_manager->get_modules( 'dev-tools' )->deprecation->deprecated_function( __METHOD__, '3.1.0' );
365
366 return [];
367 }
368
369 public static function ajax_get_revisions() {
370 return self::get_revisions();
371 }
372
373 /**
374 * @since 2.3.0
375 * @access public
376 * @static
377 */
378 public static function register_ajax_actions( Ajax $ajax ) {
379 $ajax->register_ajax_action( 'get_revisions', [ __CLASS__, 'ajax_get_revisions' ] );
380 $ajax->register_ajax_action( 'get_revision_data', [ __CLASS__, 'ajax_get_revision_data' ] );
381 }
382
383 /**
384 * @since 1.7.0
385 * @access private
386 * @static
387 */
388 private static function register_actions() {
389 add_action( 'wp_restore_post_revision', [ __CLASS__, 'restore_revision' ], 10, 2 );
390 add_action( 'init', [ __CLASS__, 'add_revision_support_for_all_post_types' ], 9999 );
391 add_filter( 'elementor/document/config', [ __CLASS__, 'document_config' ], 10, 2 );
392 add_action( 'elementor/db/before_save', [ __CLASS__, 'db_before_save' ], 10, 2 );
393 add_action( '_wp_put_post_revision', [ __CLASS__, 'save_revision' ] );
394 add_action( 'wp_creating_autosave', [ __CLASS__, 'update_autosave' ] );
395 add_action( 'elementor/ajax/register_actions', [ __CLASS__, 'register_ajax_actions' ] );
396
397 // Hack to avoid delete the auto-save revision in WP editor.
398 add_filter( 'edit_post_content', [ __CLASS__, 'avoid_delete_auto_save' ], 10, 2 );
399 add_action( 'edit_form_after_title', [ __CLASS__, 'remove_temp_post_content' ] );
400
401 if ( wp_doing_ajax() ) {
402 add_filter( 'elementor/documents/ajax_save/return_data', [ __CLASS__, 'on_ajax_save_builder_data' ], 10, 2 );
403 }
404 }
405
406 /**
407 * @since 1.9.0
408 * @access private
409 * @static
410 */
411 private static function current_revision_id( $post_id ) {
412 $current_revision_id = $post_id;
413 $autosave = Utils::get_post_autosave( $post_id );
414
415 if ( is_object( $autosave ) ) {
416 $current_revision_id = $autosave->ID;
417 }
418
419 return $current_revision_id;
420 }
421 }
422