PluginProbe
Elementor Website Builder – more than just a page builder / 4.1.0-beta3
Elementor Website Builder – more than just a page builder v4.1.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 4.0.7 All 451 releases
elementor / modules / global-classes / global-class-post.php

global-class-post.php in Elementor Website Builder – more than just a page builder 4.1.0-beta3, at modules/global-classes/global-class-post.php

262 lines 6.4 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\GlobalClasses;
4
5 use Elementor\Modules\AtomicWidgets\PropTypeMigrations\Migrations_Orchestrator;
6 use Elementor\Modules\GlobalClasses\Concerns\Has_Preview_Context;
7 use Elementor\Modules\GlobalClasses\Utils\Global_Class_Data_Normalizer;
8 use WP_Post;
9
10 if ( ! defined( 'ABSPATH' ) ) {
11 exit; // Exit if accessed directly.
12 }
13
14 class Global_Class_Post {
15 use Has_Preview_Context;
16
17 const META_KEY_VERSION = '_elementor_version';
18 const META_KEY_ID = '_elementor_global_class_id';
19 const META_KEY_DATA = '_elementor_global_class_data';
20 const META_KEY_DATA_PREVIEW = '_elementor_global_class_data_preview';
21 const META_KEY_EDITED = '_elementor_global_class_edited';
22
23 protected array $context_keys = [
24 'data' => [
25 'frontend' => self::META_KEY_DATA,
26 'preview' => self::META_KEY_DATA_PREVIEW,
27 ],
28 ];
29
30 private WP_Post $post;
31
32 private function __construct( WP_Post $post ) {
33 $this->post = $post;
34 }
35
36 public static function from_post( WP_Post $post, bool $is_preview = false ): self {
37 return ( new static( $post ) )->set_preview( $is_preview );
38 }
39
40 public static function from_post_id( int $post_id, bool $is_preview = false ): ?self {
41 $post = get_post( $post_id );
42
43 if ( ! $post || Global_Class_Post_Type::CPT !== $post->post_type ) {
44 return null;
45 }
46
47 return ( new static( $post ) )->set_preview( $is_preview );
48 }
49
50 public static function find_by_class_id( string $class_id, bool $is_preview = false ): ?self {
51 $posts = get_posts( [
52 'post_type' => Global_Class_Post_Type::CPT,
53 'post_status' => 'publish',
54 'posts_per_page' => 1,
55 'meta_key' => self::META_KEY_ID,
56 'meta_value' => $class_id,
57 ] );
58
59 if ( empty( $posts ) ) {
60 return null;
61 }
62
63 return ( new self( $posts[0] ) )->set_preview( $is_preview );
64 }
65
66 public function get_post_id(): int {
67 return $this->post->ID;
68 }
69
70 public function get_class_id(): string {
71 $class_id = get_post_meta( $this->post->ID, self::META_KEY_ID, true );
72
73 if ( ! $class_id ) {
74 return '';
75 }
76
77 return $class_id;
78 }
79
80 public function get_label(): string {
81 return $this->post->post_title;
82 }
83
84 public function get_order(): int {
85 return (int) $this->post->menu_order;
86 }
87
88 public function get_data( bool $skip_migration = false ): array {
89 $data = $this->get_context_data();
90 $meta_key = $this->get_context_key( 'data' );
91
92 // Empty preview (draft) - use frontend (published) data
93 if ( empty( $data ) && $this->is_preview() ) {
94 $data = $this->get_frontend_data();
95 $meta_key = self::META_KEY_DATA;
96 }
97
98 if ( ! empty( $data ) && ( ! $skip_migration ) ) {
99 $this->migrate_data( $data, $meta_key );
100 }
101
102 return $data;
103 }
104
105 private function migrate_data( array &$data, string $meta_key ): void {
106 if ( ! Migrations_Orchestrator::is_active() ) {
107 return;
108 }
109
110 $post_id = $this->post->ID;
111
112 Migrations_Orchestrator::make()->migrate(
113 $data,
114 $post_id,
115 $meta_key,
116 function ( $migrated ) use ( $post_id, $meta_key ) {
117 update_post_meta( $post_id, $meta_key, $migrated );
118 clean_post_cache( $post_id );
119 }
120 );
121 }
122
123 public function to_array( bool $skip_migration = false ): array {
124 $data = $this->get_data( $skip_migration );
125
126 $class_id = $this->get_class_id();
127
128 return Global_Class_Data_Normalizer::normalize_style(
129 $class_id,
130 array_merge( $data, [ 'label' => $this->get_label() ] )
131 );
132 }
133
134 public function was_edited(): bool {
135 $last_edited = $this->get_last_edited_timestamp();
136 $creation = $this->get_creation_timestamp();
137
138 return $last_edited > $creation;
139 }
140
141 public function has_edit_timestamp(): bool {
142 return $this->get_last_edited_timestamp() > 0;
143 }
144
145 private function get_creation_timestamp(): int {
146 $dt = get_post_datetime( $this->post, 'date', 'gmt' );
147
148 if ( $dt ) {
149 return (int) $dt->format( 'U' );
150 }
151
152 return (int) strtotime( (string) $this->post->post_date );
153 }
154
155 private function get_last_edited_timestamp(): int {
156 $raw = get_post_meta( $this->post->ID, self::META_KEY_EDITED, true );
157
158 if ( self::is_timestamp( $raw ) ) {
159 return (int) $raw;
160 }
161
162 return 0;
163 }
164
165 private static function is_timestamp( $value ): bool {
166 if ( ! is_numeric( $value ) ) {
167 return false;
168 }
169
170 return (int) $value > 0;
171 }
172
173 protected function get_current_timestamp(): int {
174 return (int) time();
175 }
176
177 public function update_label( string $label ): bool {
178 $result = wp_update_post( [
179 'ID' => $this->post->ID,
180 'post_title' => $label,
181 ] );
182
183 if ( ! is_wp_error( $result ) && ! $this->is_preview() ) {
184 update_post_meta( $this->post->ID, self::META_KEY_EDITED, $this->get_current_timestamp() );
185 }
186
187 return ! is_wp_error( $result );
188 }
189
190 private function get_context_data(): array {
191 $data = get_post_meta( $this->post->ID, $this->get_context_key( 'data' ), true );
192
193 return is_array( $data ) ? $data : [];
194 }
195
196 private function get_frontend_data(): array {
197 $data = get_post_meta( $this->post->ID, self::META_KEY_DATA, true );
198
199 return is_array( $data ) ? $data : [];
200 }
201
202 public function update_data(
203 array $data,
204 string $version = ELEMENTOR_VERSION
205 ): bool {
206 $meta_key = $this->get_context_key( 'data' );
207
208 $result = update_post_meta( $this->post->ID, $meta_key, $data );
209
210 if ( ! $this->is_preview() ) {
211 delete_post_meta( $this->post->ID, self::META_KEY_DATA_PREVIEW );
212 }
213
214 update_post_meta( $this->post->ID, self::META_KEY_VERSION, $version );
215
216 if ( ! $this->is_preview() ) {
217 update_post_meta( $this->post->ID, self::META_KEY_EDITED, $this->get_current_timestamp() );
218 }
219
220 return false !== $result;
221 }
222
223 public static function create(
224 string $class_id,
225 string $label,
226 array $data,
227 int $order = 0,
228 string $version = ELEMENTOR_VERSION
229 ): ?self {
230 $post_id = wp_insert_post( [
231 'post_type' => Global_Class_Post_Type::CPT,
232 'post_title' => $label,
233 'post_status' => 'publish',
234 'menu_order' => $order,
235 ] );
236
237 if ( is_wp_error( $post_id ) || ! $post_id ) {
238 return null;
239 }
240
241 $normalized_data = Global_Class_Data_Normalizer::normalize_style_fields( $data );
242
243 update_post_meta( $post_id, self::META_KEY_ID, $class_id );
244 update_post_meta( $post_id, self::META_KEY_DATA, $normalized_data );
245 update_post_meta( $post_id, self::META_KEY_VERSION, $version );
246
247 $instance = self::from_post_id( $post_id );
248
249 if ( $instance ) {
250 update_post_meta( $post_id, self::META_KEY_EDITED, $instance->get_creation_timestamp() );
251 }
252
253 return $instance;
254 }
255
256 public function delete(): bool {
257 $result = wp_delete_post( $this->post->ID, true );
258
259 return false !== $result;
260 }
261 }
262