PluginProbe
Elementor Website Builder – more than just a page builder / 4.1.4
Elementor Website Builder – more than just a page builder v4.1.4
4.3.2 4.3.1 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 All 455 releases
← All changes | modules/global-classes/global-classes-post-ids.php +106 -13 4.2.0-beta2 → 4.1.4 View file →
@@ -1,11 +1,13 @@
1 1 <?php
2 2
3 3 namespace Elementor\Modules\GlobalClasses;
4 4
5 +use Elementor\Core\Base\Document;
5 6 use Elementor\Core\Kits\Documents\Kit;
6 7 use Elementor\Modules\GlobalClasses\Concerns\Has_Kit_Dependency;
7 -use Elementor\Modules\GlobalClasses\Utils\Kit_Utils;
8 +use Elementor\Plugin;
9 +use Elementor\TemplateLibrary\Source_Local;
8 10 use WP_Post;
9 11
10 12 if ( ! defined( 'ABSPATH' ) ) {
11 13 exit;
@@ -15,8 +17,10 @@
15 17 use Has_Kit_Dependency;
16 18
17 19 const META_KEY = '_elementor_global_classes_post_ids';
18 20
21 + const BACKFILL_BATCH_SIZE = 100;
22 +
19 23 private ?array $cache = null;
20 24
21 25 public static function make( ?Kit $kit = null ): self {
22 26 $instance = new self();
@@ -36,10 +40,29 @@
36 40 if ( Global_Class_Post_Type::CPT !== $post->post_type ) {
37 41 return;
38 42 }
39 43
40 - foreach ( Kit_Utils::get_all_kit_documents() as $kit ) {
41 - self::make( $kit )->remove_post_id( $post_id );
44 + $kit_ids = get_posts( [
45 + 'post_type' => Source_Local::CPT,
46 + 'post_status' => 'any',
47 + 'fields' => 'ids',
48 + 'posts_per_page' => -1,
49 + 'no_found_rows' => true,
50 + 'update_post_meta_cache' => false,
51 + 'meta_query' => [
52 + [
53 + 'key' => Document::TYPE_META_KEY,
54 + 'value' => 'kit',
55 + ],
56 + ],
57 + ] );
58 +
59 + foreach ( $kit_ids as $kit_id ) {
60 + $kit = Plugin::$instance->kits_manager->get_kit( $kit_id );
61 +
62 + if ( $kit ) {
63 + self::make( $kit )->remove_post_id( $post_id );
64 + }
42 65 }
43 66 }
44 67
45 68 public function get_post_id( string $class_id ): ?int {
@@ -44,21 +67,21 @@
44 67
45 68 public function get_post_id( string $class_id ): ?int {
46 69 $map = $this->read_map();
47 70
48 - if ( ! isset( $map[ $class_id ] ) ) {
49 - return null;
50 - }
71 + if ( isset( $map[ $class_id ] ) ) {
72 + $post_id = (int) $map[ $class_id ];
51 73
52 - $post_id = (int) $map[ $class_id ];
74 + if ( get_post( $post_id ) ) {
75 + return $post_id;
76 + }
53 77
54 - if ( get_post( $post_id ) ) {
55 - return $post_id;
78 + $this->remove_post_id( $post_id );
56 79 }
57 80
58 - $this->remove_post_id( $post_id );
81 + $resolved = $this->backfill( [ $class_id ] );
59 82
60 - return null;
83 + return $resolved[ $class_id ] ?? null;
61 84 }
62 85
63 86 public function get_post_ids( array $class_ids ): array {
64 87 if ( empty( $class_ids ) ) {
@@ -64,13 +87,15 @@
64 87 if ( empty( $class_ids ) ) {
65 88 return [];
66 89 }
67 90
68 - $map = $this->read_map();
91 + $map = $this->read_map();
69 92 $resolved = [];
93 + $missing = [];
70 94
71 95 foreach ( $class_ids as $class_id ) {
72 96 if ( ! isset( $map[ $class_id ] ) ) {
97 + $missing[] = $class_id;
73 98 continue;
74 99 }
75 100
76 101 $post_id = (int) $map[ $class_id ];
@@ -77,12 +102,16 @@
77 102
78 103 if ( get_post( $post_id ) ) {
79 104 $resolved[ $class_id ] = $post_id;
80 105 } else {
81 - $this->remove_post_id( $post_id );
106 + $missing[] = $class_id;
82 107 }
83 108 }
84 109
110 + if ( ! empty( $missing ) ) {
111 + $resolved += $this->backfill( $missing );
112 + }
113 +
85 114 return $resolved;
86 115 }
87 116
88 117 public function set( string $class_id, int $post_id ): void {
@@ -134,8 +163,72 @@
134 163 return;
135 164 }
136 165
137 166 $this->write_map( $filtered );
167 + }
168 +
169 + private function backfill( array $class_ids ): array {
170 + $resolved = [];
171 +
172 + foreach ( array_chunk( array_values( array_unique( $class_ids ) ), self::BACKFILL_BATCH_SIZE ) as $chunk ) {
173 + $resolved += $this->resolve_via_query( $chunk );
174 + }
175 +
176 + if ( ! empty( $resolved ) ) {
177 + $this->set_many( $resolved );
178 + }
179 +
180 + return $resolved;
181 + }
182 +
183 + private function resolve_via_query( array $class_ids ): array {
184 + if ( empty( $class_ids ) ) {
185 + return [];
186 + }
187 +
188 + global $wpdb;
189 +
190 + $placeholders = implode( ',', array_fill( 0, count( $class_ids ), '%s' ) );
191 +
192 + // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
193 + $sql = $wpdb->prepare(
194 + "SELECT pm.post_id, pm.meta_value
195 + FROM {$wpdb->postmeta} pm
196 + INNER JOIN {$wpdb->posts} p ON p.ID = pm.post_id
197 + WHERE pm.meta_key = %s
198 + AND pm.meta_value IN ($placeholders)
199 + AND p.post_type = %s
200 + AND p.post_status = %s",
201 + array_merge(
202 + [ Global_Class_Post::META_KEY_ID ],
203 + $class_ids,
204 + [ Global_Class_Post_Type::CPT, 'publish' ]
205 + )
206 + );
207 + // phpcs:enable
208 +
209 + // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- $sql is already prepared via $wpdb->prepare() above.
210 + $rows = $wpdb->get_results( $sql );
211 +
212 + $candidates = [];
213 +
214 + foreach ( $rows as $row ) {
215 + $candidates[ (string) $row->meta_value ][] = (int) $row->post_id;
216 + }
217 +
218 + $resolved = [];
219 +
220 + foreach ( $candidates as $class_id => $post_ids ) {
221 + sort( $post_ids );
222 + $resolved[ $class_id ] = $post_ids[0];
223 + $duplicates = array_slice( $post_ids, 1 );
224 +
225 + foreach ( $duplicates as $duplicate_id ) {
226 + wp_delete_post( $duplicate_id, true );
227 + }
228 + }
229 +
230 + return $resolved;
138 231 }
139 232
140 233 private function read_map(): array {
141 234 if ( null !== $this->cache ) {