PluginProbe ʕ •ᴥ•ʔ
Advanced Ads – Ad Manager & AdSense / 2.0.25
Advanced Ads – Ad Manager & AdSense v2.0.25
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 2 days ago class-group-ordered.php 1 year ago class-group-repository.php 2 days ago class-group-slider.php 5 months ago class-group-standard.php 1 year ago class-group-types.php 2 days ago class-groups.php 2 days ago index.php 1 year ago
class-group-repository.php
504 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\Traits\Repository_Helpers;
17 use AdvancedAds\Utilities\Cache;
18 use Exception;
19
20 defined( 'ABSPATH' ) || exit;
21
22 /**
23 * Group Repository.
24 */
25 class Group_Repository {
26 use Repository_Helpers;
27
28 /**
29 * Group options metakey
30 *
31 * @var string
32 */
33 const OPTION_METAKEY = 'advanced_ads_group_options';
34
35 /**
36 * Group type metakey
37 *
38 * @var string
39 */
40 const TYPE_METAKEY = '_advads_group_type';
41
42 /* CRUD Methods ------------------- */
43
44 /**
45 * Create a new group in the database.
46 *
47 * @param Group $group Group object.
48 *
49 * @return Group
50 */
51 public function create( &$group ): Group {
52 apply_filters( 'advanced-ads-group-pre-save', $group );
53
54 $ids = wp_insert_term(
55 $group->get_title(),
56 Constants::TAXONOMY_GROUP,
57 [
58 'description' => $group->get_content(),
59 'slug' => $group->get_slug(),
60 ]
61 );
62
63 if ( $ids && ! is_wp_error( $ids ) ) {
64 $group->set_id( $ids['term_id'] );
65 $this->update_term_meta( $group );
66 $group->apply_changes();
67 }
68
69 return $group;
70 }
71
72 /**
73 * Read an group from the database.
74 *
75 * @param Group $group Group object.
76 * @throws Exception If invalid group.
77 *
78 * @return void
79 */
80 public function read( &$group ): void {
81 $group->set_defaults();
82 $term_object = get_term( $group->get_id(), Constants::TAXONOMY_GROUP );
83
84 if ( null === $term_object || is_wp_error( $term_object ) ) {
85 throw new Exception( esc_html__( 'Invalid group.', 'advanced-ads' ) );
86 }
87
88 $group->set_title( $term_object->name );
89 $group->set_slug( $term_object->slug );
90 $group->set_content( $term_object->description );
91
92 $this->read_group_data( $group );
93 $group->set_object_read( true );
94 }
95
96 /**
97 * Update an existing group in the database.
98 *
99 * @param Group $group Group object.
100 *
101 * @return void
102 */
103 public function update( &$group ): void {
104 apply_filters( 'advanced-ads-group-pre-save', $group );
105
106 $changed = array_keys( $group->get_changes() );
107
108 $term_args = [];
109
110 if ( in_array( 'title', $changed, true ) ) {
111 $term_args['name'] = $group->get_title( 'edit' );
112 }
113
114 if ( in_array( 'slug', $changed, true ) ) {
115 $term_args['slug'] = $group->get_slug( 'edit' );
116 }
117
118 if ( in_array( 'content', $changed, true ) ) {
119 $term_args['description'] = $group->get_content( 'edit' );
120 }
121
122 if ( ! empty( $term_args ) ) {
123 wp_update_term( $group->get_id(), Constants::TAXONOMY_GROUP, $term_args );
124 }
125
126 // Only update weights when there is a change.
127 if ( in_array( 'ad_weights', $changed, true ) ) {
128 ( new Group_Ad_Relation() )->relate( $group );
129 }
130
131 $this->update_term_meta( $group );
132 $group->apply_changes();
133
134 if ( empty( $term_args ) ) {
135 Cache_Invalidator::invalidate_groups();
136 }
137 }
138
139 /**
140 * Delete an group from the database.
141 *
142 * @param Group $group Group object or Id.
143 * @param bool $force_delete Unused; taxonomy terms are always deleted permanently.
144 *
145 * @return void
146 */
147 public function delete( &$group, $force_delete = false ): void {
148 // Early bail!!
149 if ( ! $group || ! $group->get_id() ) {
150 return;
151 }
152
153 wp_delete_term( $group->get_id(), Constants::TAXONOMY_GROUP );
154
155 $group->set_id( 0 );
156 $group->set_status( 'trash' );
157 }
158
159 /* Finder Methods ------------------- */
160
161 /**
162 * Get all groups object.
163 *
164 * @deprecated 2.0.24 Use get_group_summaries() or get_groups_by_ids() instead.
165 *
166 * @return Group[]
167 */
168 public function get_all_groups(): array {
169 return $this->hydrate_groups( array_keys( $this->get_group_summaries() ) );
170 }
171
172 /**
173 * Get lightweight group summaries for list UIs (cached cross-request).
174 *
175 * @return array<int, array{id: int, title: string, slug: string, type: string, ad_weights: array<int, int>, publish_date: string, modified_date: string}>
176 */
177 public function get_group_summaries(): array {
178 $summaries = Cache::get( Cache::PREFIX_GROUPS, Cache::KEY_SUMMARIES );
179
180 if ( null === $summaries ) {
181 $summaries = $this->query_group_summaries();
182 Cache::set( Cache::PREFIX_GROUPS, Cache::KEY_SUMMARIES, $summaries );
183 }
184
185 return $summaries;
186 }
187
188 /**
189 * Get all group as dropdown (ID => title), derived from cached summaries.
190 *
191 * @return array<int, string>
192 */
193 public function get_groups_dropdown(): array {
194 return $this->summaries_to_dropdown( $this->get_group_summaries() );
195 }
196
197 /**
198 * Get ads belonging to a group in the requested shape.
199 *
200 * @param int $group_id Group term ID.
201 * @param string $output OBJECT for hydrated ads, 'ids' for ad IDs, 'summaries' for cached ad rows.
202 *
203 * @return Ad[]|int[]|array<int, array{id: int, title: string, type: string, status: string, author_id: int, expiry_date: int}>
204 */
205 public function get_ads_by_group_id( int $group_id, $output = OBJECT ): array {
206 $ad_weights = $this->get_ad_weights_by_group_id( $group_id );
207
208 if ( empty( $ad_weights ) ) {
209 return [];
210 }
211
212 $ad_ids = array_map( 'absint', array_keys( $ad_weights ) );
213
214 if ( 'ids' === $output ) {
215 return $ad_ids;
216 }
217
218 if ( 'summaries' === $output ) {
219 return array_intersect_key( wp_advads_get_ad_summaries(), array_flip( $ad_ids ) );
220 }
221
222 $ads = wp_advads_get_ads_by_ids( $ad_ids );
223
224 foreach ( $ads as $ad_id => $ad ) {
225 $ad->set_prop( 'weight', $ad_weights[ $ad_id ] );
226 }
227
228 return $ads;
229 }
230
231 /**
232 * Get ad IDs assigned to a group from cached summaries.
233 *
234 * @param int $group_id Group term ID.
235 *
236 * @return int[]
237 */
238 private function get_ad_ids_by_group_id( int $group_id ): array {
239 return array_map( 'absint', array_keys( $this->get_ad_weights_by_group_id( $group_id ) ) );
240 }
241
242 /**
243 * Get ad weights for a group from cached summaries.
244 *
245 * @param int $group_id Group term ID.
246 *
247 * @return array<int, int>
248 */
249 private function get_ad_weights_by_group_id( int $group_id ): array {
250 $summaries = $this->get_group_summaries();
251
252 if ( ! isset( $summaries[ $group_id ] ) ) {
253 return [];
254 }
255
256 return $summaries[ $group_id ]['ad_weights'] ?? [];
257 }
258
259 /**
260 * Query lightweight group summaries without hydrating Group objects.
261 *
262 * @return array<int, array{id: int, title: string, slug: string, type: string, ad_weights: array<int, int>, publish_date: string, modified_date: string}>
263 */
264 private function query_group_summaries(): array {
265 $terms = get_terms(
266 [
267 'taxonomy' => Constants::TAXONOMY_GROUP,
268 'hide_empty' => false,
269 'number' => 0,
270 'orderby' => 'name',
271 'update_term_meta_cache' => false,
272 'suppress_filters' => defined( 'ICL_SITEPRESS_VERSION' ) ? true : false, // Suppress filters if WPML is present.
273 ]
274 );
275
276 if ( empty( $terms ) || is_wp_error( $terms ) ) {
277 return [];
278 }
279
280 $term_ids = wp_list_pluck( $terms, 'term_id' );
281 update_termmeta_cache( $term_ids );
282
283 $summaries = [];
284 foreach ( $terms as $term ) {
285 $type = get_term_meta( $term->term_id, self::TYPE_METAKEY, true );
286 $meta_values = get_term_meta( $term->term_id, self::OPTION_METAKEY, true );
287
288 if ( ! $type ) {
289 $type = is_array( $meta_values ) ? ( $meta_values['type'] ?? 'default' ) : 'default';
290 }
291
292 $type = $this->normalize_group_type( $type );
293
294 $summaries[ (int) $term->term_id ] = [
295 'id' => (int) $term->term_id,
296 'title' => $term->name,
297 'slug' => $term->slug,
298 'type' => $type,
299 'ad_weights' => $this->extract_ad_weights_from_meta( $meta_values, $type ),
300 'publish_date' => (string) get_term_meta( $term->term_id, 'publish_date', true ),
301 'modified_date' => (string) get_term_meta( $term->term_id, 'modified_date', true ),
302 ];
303 }
304
305 return $summaries;
306 }
307
308 /**
309 * Extract ad weights from stored group term meta.
310 *
311 * @param mixed $meta_values Group option meta values.
312 * @param string $type Resolved group type.
313 *
314 * @return array<int, int>
315 */
316 private function extract_ad_weights_from_meta( $meta_values, $type ): array {
317 if ( ! is_array( $meta_values ) ) {
318 return [];
319 }
320
321 $meta_values = $this->merge_group_options_meta( $meta_values, $type );
322
323 $ad_weights = $meta_values['ad_weights'] ?? [];
324
325 return is_array( $ad_weights ) ? $ad_weights : [];
326 }
327
328 /**
329 * Hydrate group objects for the given term IDs.
330 *
331 * @param int[] $term_ids Group term IDs.
332 *
333 * @return Group[]
334 */
335 private function hydrate_groups( array $term_ids ): array {
336 $term_ids = $this->normalize_entity_ids( $term_ids );
337
338 if ( ! empty( $term_ids ) ) {
339 if ( function_exists( 'wp_prime_term_caches' ) ) {
340 wp_prime_term_caches( $term_ids, Constants::TAXONOMY_GROUP );
341 } else {
342 foreach ( $term_ids as $term_id ) {
343 get_term( $term_id, Constants::TAXONOMY_GROUP );
344 }
345 }
346
347 update_termmeta_cache( $term_ids );
348 }
349
350 $groups = [];
351 foreach ( $term_ids as $term_id ) {
352 $group = wp_advads_get_group( $term_id );
353
354 if ( $group ) {
355 $groups[ $term_id ] = $group;
356 }
357 }
358
359 return $groups;
360 }
361
362 /**
363 * Get groups associated with a given ad id.
364 *
365 * @param int $ad_id The ID of the ad.
366 *
367 * @return Group[] Groups array
368 */
369 public function get_groups_by_ad_id( $ad_id ) {
370 $ad_id = absint( $ad_id );
371
372 if ( ! $ad_id ) {
373 return [];
374 }
375
376 $group_ids = get_post_meta( $ad_id, Constants::AD_META_GROUP_IDS, true );
377
378 if ( ! is_array( $group_ids ) || empty( $group_ids ) ) {
379 return [];
380 }
381
382 return $this->hydrate_groups( $group_ids );
383 }
384
385 /**
386 * Hydrate group objects for the given term IDs.
387 *
388 * @param int[] $term_ids Group term IDs.
389 *
390 * @return array<int, Group>
391 */
392 public function get_groups_by_ids( array $term_ids ): array {
393 return $this->hydrate_groups( $term_ids );
394 }
395
396 /* Additional Methods ------------------- */
397
398 /**
399 * Read group data. Can be overridden by child classes to load other props.
400 *
401 * @param Group $group Group object.
402 *
403 * @return void
404 */
405 private function read_group_data( &$group ): void {
406 $type = get_term_meta( $group->get_id(), self::TYPE_METAKEY, true );
407 $meta_values = get_term_meta( $group->get_id(), self::OPTION_METAKEY, true );
408 $publish_date = get_term_meta( $group->get_id(), 'publish_date', true );
409 $modified_date = get_term_meta( $group->get_id(), 'modified_date', true );
410
411 if ( ! is_array( $meta_values ) ) {
412 $meta_values = [];
413 }
414
415 $type = $this->normalize_group_type( $type ?: ( $meta_values['type'] ?? 'default' ) );
416
417 $meta_values = $this->merge_group_options_meta( $meta_values, $type );
418 $meta_values['type'] = $type;
419
420 $meta_values['publish_date'] = $publish_date ?? '';
421 $meta_values['modified_date'] = $modified_date ?? '';
422
423 $group->set_props( $meta_values );
424
425 foreach ( [ 'random', 'enabled' ] as $prop ) {
426 if ( array_key_exists( $prop, $meta_values ) ) {
427 $value = $meta_values[ $prop ];
428 $value = Formatting::string_to_bool( $value );
429 $group->set_prop( $prop, $value );
430 }
431 }
432 }
433
434 /**
435 * Update group data. Can be overridden by child classes to load other props.
436 *
437 * @param Group $group Group object.
438 *
439 * @return void
440 */
441 private function update_term_meta( &$group ): void {
442 $current_date = current_time( 'mysql', true );
443 $meta_values = [
444 'type' => $group->get_type(),
445 'ad_count' => $group->get_ad_count(),
446 'options' => $group->get_options(),
447 'ad_weights' => $group->get_ad_weights(),
448 ];
449
450 update_term_meta( $group->get_id(), self::TYPE_METAKEY, $group->get_type() );
451 update_term_meta( $group->get_id(), self::OPTION_METAKEY, $meta_values );
452
453 update_term_meta( $group->get_id(), 'modified_date', $current_date );
454 if ( empty( $group->get_publish_date() ) ) {
455 update_term_meta( $group->get_id(), 'publish_date', $current_date );
456 }
457 }
458
459 /**
460 * Normalize stored group type to a registered type slug.
461 *
462 * @param string $type Raw type from meta or legacy storage.
463 *
464 * @return string
465 */
466 private function normalize_group_type( $type ): string {
467 if ( empty( $type ) ) {
468 return 'default';
469 }
470
471 if ( 'refresh' === $type ) {
472 return 'default';
473 }
474
475 return $type;
476 }
477
478 /**
479 * Merge per-type options from stored group meta.
480 *
481 * @param array $meta_values Group option meta values.
482 * @param string $type Normalized group type.
483 *
484 * @return array
485 */
486 private function merge_group_options_meta( array $meta_values, string $type ): array {
487 if ( ! isset( $meta_values['options'] ) || ! is_array( $meta_values['options'] ) ) {
488 return $meta_values;
489 }
490
491 $bucket = $type;
492
493 if ( ! isset( $meta_values['options'][ $bucket ] ) && 'default' === $type && isset( $meta_values['options']['refresh'] ) ) {
494 $bucket = 'refresh';
495 }
496
497 if ( isset( $meta_values['options'][ $bucket ] ) && is_array( $meta_values['options'][ $bucket ] ) ) {
498 return array_merge( $meta_values['options'][ $bucket ], $meta_values );
499 }
500
501 return $meta_values;
502 }
503 }
504