PluginProbe ʕ •ᴥ•ʔ
Advanced Ads – Ad Manager & AdSense / 2.0.24
Advanced Ads – Ad Manager & AdSense v2.0.24
2.0.25 2.0.24 2.0.23 2.0.22 2.0.21 1.38.0 1.39.0 1.39.1 1.39.2 1.39.3 1.39.4 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.4.9 1.40.0 1.40.1 1.40.2 1.41.0 1.42.0 1.42.1 1.42.2 1.43.0 1.44.0 1.44.1 1.45.0 1.45.1 1.46.0 1.47.0 1.47.1 1.47.2 1.47.3 1.47.4 1.47.5 1.48.0 1.48.1 1.49.0 1.5.0 1.5.0.1 1.5.1 1.5.2 1.5.2.1 1.5.4 1.5.4.1 1.5.5 1.50.0 1.51.0 1.51.1 1.51.2 1.51.3 1.52.0 1.52.1 1.52.2 1.52.3 1.52.4 1.53.0 1.53.1 1.53.2 1.54.0 1.54.1 1.55.0 1.56.0 1.56.1 1.56.2 1.56.3 1.56.4 1.6 1.6.1 1.6.10 1.6.10.1 1.6.10.2 1.6.11 1.6.11.1 1.6.12 1.6.13 1.6.14 1.6.15 1.6.16 1.6.17 1.6.17.1 1.6.17.2 1.6.2 1.6.2.1 1.6.3 1.6.4 1.6.4.1 1.6.5 1.6.6 1.6.6.1 1.6.7 1.6.7.1 1.6.8 1.6.8.1 1.6.8.2 1.6.8.3 1.6.9 1.6.9.1 1.6.9.2 1.6.9.3 1.6.9.4 1.7 1.7.0.1 1.7.0.2 1.7.0.3 1.7.1 1.7.1.1 1.7.1.2 1.7.1.3 1.7.1.4 1.7.1.5 1.7.10 trunk 1.7.11 1.0.1 1.7.12 1.0.2 1.7.13 1.0.3 1.7.14 1.1.0 1.7.15 1.1.1 1.7.16 1.1.2 1.7.17 1.1.3 1.7.18 1.10 1.7.19 1.10.1 1.7.2 1.10.10 1.7.2.1 1.10.11 1.7.20 1.10.12 1.7.21 1.10.2 1.7.22 1.10.3 1.7.23 1.10.4 1.7.24 1.10.5 1.7.25 1.10.6 1.7.3 1.10.7 1.7.4 1.10.8 1.7.4.1 1.10.9 1.7.4.2 1.11 1.7.4.3 1.11.1 1.7.4.4 1.11.2 1.7.4.5 1.12 1.7.5 1.13 1.7.5.1 1.13.1 1.7.6 1.13.2 1.7.7 1.13.3 1.7.8 1.13.4 1.7.9 1.13.5 1.7.9.1 1.13.6 1.7.9.2 1.13.7 1.7.9.3 1.13.8 1.8 1.14 1.8.1 1.14.1 1.8.10 1.14.10 1.8.11 1.14.11 1.8.12 1.14.2 1.8.13 1.14.3 1.8.14 1.14.4 1.8.15 1.14.5 1.8.16 1.14.6 1.8.17 1.14.7 1.8.18 1.14.8 1.8.19 1.14.9 1.8.2 1.15 1.8.20 1.16 1.8.21 1.16.1 1.8.22 1.17 1.8.23 1.17.1 1.8.24 1.17.10 1.8.25 1.17.10-rc.1 1.8.26 1.17.11 1.8.27 1.17.12 1.8.28 1.17.12-rc.1 1.8.29 1.17.2 1.8.3 1.17.3 1.8.30 1.17.4 1.8.4 1.17.5 1.8.5 1.17.6 1.8.6 1.17.7 1.8.7 1.17.8 1.8.8 1.17.9 1.8.9 1.17.9-beta.1 1.9 1.18.0 2.0.0 1.19.0 2.0.1 1.19.1 2.0.10 1.2 2.0.11 1.2.1 2.0.12 1.2.2 2.0.13 1.2.3 2.0.14 1.2.4 2.0.15 1.2.5 2.0.16 1.2.6 2.0.17 1.2.7 2.0.18 1.20.0 2.0.19 1.20.0-rc.1 2.0.2 1.20.0-rc.2 2.0.20 1.20.1 2.0.3 1.20.2 2.0.4 1.20.3 2.0.5 1.21.0 2.0.6 1.21.1 2.0.7 1.22.0 2.0.8 1.22.1 2.0.9 1.22.2 1.23.0 1.23.1 1.23.2 1.24.0 1.24.1 1.24.2 1.25.0 1.25.1 1.26.0 1.27.0 1.28.0 1.29.0 1.29.1 1.3 1.3.1 1.3.10 1.3.11 1.3.12 1.3.13 1.3.14 1.3.15 1.3.16 1.3.17 1.3.18 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.30.0 1.30.1 1.30.2 1.30.2-rc.1 1.30.3 1.30.4 1.30.4-rc.1 1.30.5 1.31.0 1.31.1 1.32.0 1.32.0-rc.1 1.33.0 1.33.1 1.33.2 1.34.0 1.35.0 1.35.1 1.36.0 1.36.1 1.36.2 1.36.3 1.37.0 1.37.1 1.37.2
advanced-ads / includes / groups / class-group-repository.php
advanced-ads / includes / groups Last commit date
types 3 months ago class-group-ad-relation.php 6 days ago class-group-factory.php 6 days ago class-group-ordered.php 1 year ago class-group-repository.php 6 days ago class-group-slider.php 5 months ago class-group-standard.php 1 year ago class-group-types.php 1 year ago class-groups.php 1 year ago index.php 1 year ago
class-group-repository.php
508 lines
1 <?php
2 /**
3 * Group Repository.
4 *
5 * @package AdvancedAds
6 * @author Advanced Ads <info@wpadvancedads.com>
7 * @since 1.48.0
8 */
9
10 namespace AdvancedAds\Groups;
11
12 use AdvancedAds\Abstracts\Group;
13 use AdvancedAds\Constants;
14 use AdvancedAds\Framework\Utilities\Formatting;
15 use AdvancedAds\Cache_Invalidator;
16 use AdvancedAds\Utilities\Cache;
17 use Exception;
18
19 defined( 'ABSPATH' ) || exit;
20
21 /**
22 * Group Repository.
23 */
24 class Group_Repository {
25
26 /**
27 * Group options metakey
28 *
29 * @var string
30 */
31 const OPTION_METAKEY = 'advanced_ads_group_options';
32
33 /**
34 * Group type metakey
35 *
36 * @var string
37 */
38 const TYPE_METAKEY = '_advads_group_type';
39
40 /* CRUD Methods ------------------- */
41
42 /**
43 * Create a new group in the database.
44 *
45 * @param Group $group Group object.
46 *
47 * @return Group
48 */
49 public function create( &$group ): Group {
50 apply_filters( 'advanced-ads-group-pre-save', $group );
51
52 $ids = wp_insert_term(
53 $group->get_title(),
54 Constants::TAXONOMY_GROUP,
55 [
56 'description' => $group->get_content(),
57 'slug' => $group->get_slug(),
58 ]
59 );
60
61 if ( $ids && ! is_wp_error( $ids ) ) {
62 $group->set_id( $ids['term_id'] );
63 $this->update_term_meta( $group );
64 $group->apply_changes();
65 }
66
67 return $group;
68 }
69
70 /**
71 * Read an group from the database.
72 *
73 * @param Group $group Group object.
74 * @throws Exception If invalid group.
75 *
76 * @return void
77 */
78 public function read( &$group ): void {
79 $group->set_defaults();
80 $term_object = get_term( $group->get_id(), Constants::TAXONOMY_GROUP );
81
82 if ( null === $term_object || is_wp_error( $term_object ) ) {
83 throw new Exception( esc_html__( 'Invalid group.', 'advanced-ads' ) );
84 }
85
86 $group->set_title( $term_object->name );
87 $group->set_slug( $term_object->slug );
88 $group->set_content( $term_object->description );
89
90 $this->read_group_data( $group );
91 $group->set_object_read( true );
92 }
93
94 /**
95 * Update an existing group in the database.
96 *
97 * @param Group $group Group object.
98 *
99 * @return void
100 */
101 public function update( &$group ): void {
102 apply_filters( 'advanced-ads-group-pre-save', $group );
103
104 $changed = array_keys( $group->get_changes() );
105
106 $term_args = [];
107
108 if ( in_array( 'title', $changed, true ) ) {
109 $term_args['name'] = $group->get_title( 'edit' );
110 }
111
112 if ( in_array( 'slug', $changed, true ) ) {
113 $term_args['slug'] = $group->get_slug( 'edit' );
114 }
115
116 if ( in_array( 'content', $changed, true ) ) {
117 $term_args['description'] = $group->get_content( 'edit' );
118 }
119
120 if ( ! empty( $term_args ) ) {
121 wp_update_term( $group->get_id(), Constants::TAXONOMY_GROUP, $term_args );
122 }
123
124 // Only update weights when there is a change.
125 if ( in_array( 'ad_weights', $changed, true ) ) {
126 ( new Group_Ad_Relation() )->relate( $group );
127 }
128
129 $this->update_term_meta( $group );
130 $group->apply_changes();
131
132 if ( empty( $term_args ) ) {
133 Cache_Invalidator::invalidate_groups();
134 }
135 }
136
137 /**
138 * Delete an group from the database.
139 *
140 * @param Group $group Group object or Id.
141 * @param bool $force_delete Unused; taxonomy terms are always deleted permanently.
142 *
143 * @return void
144 */
145 public function delete( &$group, $force_delete = false ): void {
146 // Early bail!!
147 if ( ! $group || ! $group->get_id() ) {
148 return;
149 }
150
151 wp_delete_term( $group->get_id(), Constants::TAXONOMY_GROUP );
152
153 $group->set_id( 0 );
154 $group->set_status( 'trash' );
155 }
156
157 /* Finder Methods ------------------- */
158
159 /**
160 * Get all groups object.
161 *
162 * @deprecated 2.0.24 Use get_group_summaries() or get_groups_by_ids() instead.
163 *
164 * @return Group[]
165 */
166 public function get_all_groups(): array {
167 return $this->hydrate_groups( array_keys( $this->get_group_summaries() ) );
168 }
169
170 /**
171 * Get lightweight group summaries for list UIs (cached cross-request).
172 *
173 * @return array<int, array{id: int, title: string, slug: string, type: string, ad_weights: array<int, int>, publish_date: string, modified_date: string}>
174 */
175 public function get_group_summaries(): array {
176 $summaries = Cache::get( Cache::PREFIX_GROUPS, Cache::KEY_SUMMARIES );
177
178 if ( null === $summaries ) {
179 $summaries = $this->query_group_summaries();
180 Cache::set( Cache::PREFIX_GROUPS, Cache::KEY_SUMMARIES, $summaries );
181 }
182
183 return $summaries;
184 }
185
186 /**
187 * Get all group as dropdown (ID => title), derived from cached summaries.
188 *
189 * @return array<int, string>
190 */
191 public function get_groups_dropdown(): array {
192 $summaries = $this->get_group_summaries();
193
194 if ( empty( $summaries ) ) {
195 return [];
196 }
197
198 return wp_list_pluck( $summaries, 'title', 'id' );
199 }
200
201 /**
202 * Get ads belonging to a group in the requested shape.
203 *
204 * @param int $group_id Group term ID.
205 * @param string $output OBJECT for hydrated ads, 'ids' for ad IDs, 'summaries' for cached ad rows.
206 *
207 * @return Ad[]|int[]|array<int, array{id: int, title: string, type: string, status: string, author_id: int, expiry_date: int}>
208 */
209 public function get_ads_by_group_id( int $group_id, $output = OBJECT ): array {
210 $ad_weights = $this->get_ad_weights_by_group_id( $group_id );
211
212 if ( empty( $ad_weights ) ) {
213 return [];
214 }
215
216 $ad_ids = array_map( 'absint', array_keys( $ad_weights ) );
217
218 if ( 'ids' === $output ) {
219 return $ad_ids;
220 }
221
222 if ( 'summaries' === $output ) {
223 return array_intersect_key( wp_advads_get_ad_summaries(), array_flip( $ad_ids ) );
224 }
225
226 $ads = wp_advads_get_ads_by_ids( $ad_ids );
227
228 foreach ( $ads as $ad_id => $ad ) {
229 $ad->set_prop( 'weight', $ad_weights[ $ad_id ] );
230 }
231
232 return $ads;
233 }
234
235 /**
236 * Get ad IDs assigned to a group from cached summaries.
237 *
238 * @param int $group_id Group term ID.
239 *
240 * @return int[]
241 */
242 private function get_ad_ids_by_group_id( int $group_id ): array {
243 return array_map( 'absint', array_keys( $this->get_ad_weights_by_group_id( $group_id ) ) );
244 }
245
246 /**
247 * Get ad weights for a group from cached summaries.
248 *
249 * @param int $group_id Group term ID.
250 *
251 * @return array<int, int>
252 */
253 private function get_ad_weights_by_group_id( int $group_id ): array {
254 $summaries = $this->get_group_summaries();
255
256 if ( ! isset( $summaries[ $group_id ] ) ) {
257 return [];
258 }
259
260 return $summaries[ $group_id ]['ad_weights'] ?? [];
261 }
262
263 /**
264 * Query lightweight group summaries without hydrating Group objects.
265 *
266 * @return array<int, array{id: int, title: string, slug: string, type: string, ad_weights: array<int, int>, publish_date: string, modified_date: string}>
267 */
268 private function query_group_summaries(): array {
269 $terms = get_terms(
270 [
271 'taxonomy' => Constants::TAXONOMY_GROUP,
272 'hide_empty' => false,
273 'number' => 0,
274 'orderby' => 'name',
275 'update_term_meta_cache' => false,
276 'suppress_filters' => defined( 'ICL_SITEPRESS_VERSION' ) ? true : false, // Suppress filters if WPML is present.
277 ]
278 );
279
280 if ( empty( $terms ) || is_wp_error( $terms ) ) {
281 return [];
282 }
283
284 $term_ids = wp_list_pluck( $terms, 'term_id' );
285 update_termmeta_cache( $term_ids );
286
287 $summaries = [];
288 foreach ( $terms as $term ) {
289 $type = get_term_meta( $term->term_id, self::TYPE_METAKEY, true );
290 $meta_values = get_term_meta( $term->term_id, self::OPTION_METAKEY, true );
291
292 if ( ! $type ) {
293 $type = is_array( $meta_values ) ? ( $meta_values['type'] ?? 'default' ) : 'default';
294 }
295
296 $type = $this->normalize_group_type( $type );
297
298 $summaries[ (int) $term->term_id ] = [
299 'id' => (int) $term->term_id,
300 'title' => $term->name,
301 'slug' => $term->slug,
302 'type' => $type,
303 'ad_weights' => $this->extract_ad_weights_from_meta( $meta_values, $type ),
304 'publish_date' => (string) get_term_meta( $term->term_id, 'publish_date', true ),
305 'modified_date' => (string) get_term_meta( $term->term_id, 'modified_date', true ),
306 ];
307 }
308
309 return $summaries;
310 }
311
312 /**
313 * Extract ad weights from stored group term meta.
314 *
315 * @param mixed $meta_values Group option meta values.
316 * @param string $type Resolved group type.
317 *
318 * @return array<int, int>
319 */
320 private function extract_ad_weights_from_meta( $meta_values, $type ): array {
321 if ( ! is_array( $meta_values ) ) {
322 return [];
323 }
324
325 $meta_values = $this->merge_group_options_meta( $meta_values, $type );
326
327 $ad_weights = $meta_values['ad_weights'] ?? [];
328
329 return is_array( $ad_weights ) ? $ad_weights : [];
330 }
331
332 /**
333 * Hydrate group objects for the given term IDs.
334 *
335 * @param int[] $term_ids Group term IDs.
336 *
337 * @return Group[]
338 */
339 private function hydrate_groups( array $term_ids ): array {
340 $term_ids = array_values( array_filter( array_map( 'absint', $term_ids ) ) );
341
342 if ( ! empty( $term_ids ) ) {
343 if ( function_exists( 'wp_prime_term_caches' ) ) {
344 wp_prime_term_caches( $term_ids, Constants::TAXONOMY_GROUP );
345 } else {
346 foreach ( $term_ids as $term_id ) {
347 get_term( $term_id, Constants::TAXONOMY_GROUP );
348 }
349 }
350
351 update_termmeta_cache( $term_ids );
352 }
353
354 $groups = [];
355 foreach ( $term_ids as $term_id ) {
356 $group = wp_advads_get_group( $term_id );
357
358 if ( $group ) {
359 $groups[ $term_id ] = $group;
360 }
361 }
362
363 return $groups;
364 }
365
366 /**
367 * Get groups associated with a given ad id.
368 *
369 * @param int $ad_id The ID of the ad.
370 *
371 * @return Group[] Groups array
372 */
373 public function get_groups_by_ad_id( $ad_id ) {
374 $ad_id = absint( $ad_id );
375
376 if ( ! $ad_id ) {
377 return [];
378 }
379
380 $group_ids = get_post_meta( $ad_id, Constants::AD_META_GROUP_IDS, true );
381
382 if ( ! is_array( $group_ids ) || empty( $group_ids ) ) {
383 return [];
384 }
385
386 return $this->hydrate_groups( $group_ids );
387 }
388
389 /**
390 * Hydrate group objects for the given term IDs.
391 *
392 * @param int[] $term_ids Group term IDs.
393 *
394 * @return array<int, Group>
395 */
396 public function get_groups_by_ids( array $term_ids ): array {
397 return $this->hydrate_groups( $term_ids );
398 }
399
400 /* Additional Methods ------------------- */
401
402 /**
403 * Read group data. Can be overridden by child classes to load other props.
404 *
405 * @param Group $group Group object.
406 *
407 * @return void
408 */
409 private function read_group_data( &$group ): void {
410 $type = get_term_meta( $group->get_id(), self::TYPE_METAKEY, true );
411 $meta_values = get_term_meta( $group->get_id(), self::OPTION_METAKEY, true );
412 $publish_date = get_term_meta( $group->get_id(), 'publish_date', true );
413 $modified_date = get_term_meta( $group->get_id(), 'modified_date', true );
414
415 if ( ! is_array( $meta_values ) ) {
416 $meta_values = [];
417 }
418
419 $type = $this->normalize_group_type( $type ?: ( $meta_values['type'] ?? 'default' ) );
420
421 $meta_values = $this->merge_group_options_meta( $meta_values, $type );
422 $meta_values['type'] = $type;
423
424 $meta_values['publish_date'] = $publish_date ?? '';
425 $meta_values['modified_date'] = $modified_date ?? '';
426
427 $group->set_props( $meta_values );
428
429 foreach ( [ 'random', 'enabled' ] as $prop ) {
430 if ( array_key_exists( $prop, $meta_values ) ) {
431 $value = $meta_values[ $prop ];
432 $value = Formatting::string_to_bool( $value );
433 $group->set_prop( $prop, $value );
434 }
435 }
436 }
437
438 /**
439 * Update group data. Can be overridden by child classes to load other props.
440 *
441 * @param Group $group Group object.
442 *
443 * @return void
444 */
445 private function update_term_meta( &$group ): void {
446 $current_date = current_time( 'mysql', true );
447 $meta_values = [
448 'type' => $group->get_type(),
449 'ad_count' => $group->get_ad_count(),
450 'options' => $group->get_options(),
451 'ad_weights' => $group->get_ad_weights(),
452 ];
453
454 update_term_meta( $group->get_id(), self::TYPE_METAKEY, $group->get_type() );
455 update_term_meta( $group->get_id(), self::OPTION_METAKEY, $meta_values );
456
457 update_term_meta( $group->get_id(), 'modified_date', $current_date );
458 if ( empty( $group->get_publish_date() ) ) {
459 update_term_meta( $group->get_id(), 'publish_date', $current_date );
460 }
461 }
462
463 /**
464 * Normalize stored group type to a registered type slug.
465 *
466 * @param string $type Raw type from meta or legacy storage.
467 *
468 * @return string
469 */
470 private function normalize_group_type( $type ): string {
471 if ( empty( $type ) ) {
472 return 'default';
473 }
474
475 if ( 'refresh' === $type ) {
476 return 'default';
477 }
478
479 return $type;
480 }
481
482 /**
483 * Merge per-type options from stored group meta.
484 *
485 * @param array $meta_values Group option meta values.
486 * @param string $type Normalized group type.
487 *
488 * @return array
489 */
490 private function merge_group_options_meta( array $meta_values, string $type ): array {
491 if ( ! isset( $meta_values['options'] ) || ! is_array( $meta_values['options'] ) ) {
492 return $meta_values;
493 }
494
495 $bucket = $type;
496
497 if ( ! isset( $meta_values['options'][ $bucket ] ) && 'default' === $type && isset( $meta_values['options']['refresh'] ) ) {
498 $bucket = 'refresh';
499 }
500
501 if ( isset( $meta_values['options'][ $bucket ] ) && is_array( $meta_values['options'][ $bucket ] ) ) {
502 return array_merge( $meta_values['options'][ $bucket ], $meta_values );
503 }
504
505 return $meta_values;
506 }
507 }
508