'; } else { echo '–'; } } } /** * Marks an ad's currently selected image as used by AdPresso, and un-marks * its previous image if the ad switched to a different one (and no other * ad still references the old one). * * Hooked to 'adpresso_ad_saved' (fired by AdRepository::save() after this * save's meta_data is fully persisted) rather than 'save_post' - see hooks(). * * @param int $post_id The ad's post ID. * @param int $previous_image_id The ad's image_id meta value before this save (0 if none/new ad). */ public function mark_media_as_used( int $post_id, int $previous_image_id = 0 ): void { $is_image_ad = get_post_meta( $post_id, Constants::META_PREFIX . 'ad_type', true ) === 'image'; $image_id = $is_image_ad ? (int) get_post_meta( $post_id, Constants::META_PREFIX . 'image_id', true ) : 0; if ( $previous_image_id && $previous_image_id !== $image_id && ! $this->is_image_used_by_another_ad( $previous_image_id, $post_id ) ) { delete_post_meta( $previous_image_id, self::META_KEY ); } if ( $image_id ) { update_post_meta( $image_id, self::META_KEY, 1 ); } } /** * Whether an attachment is still referenced as the image of some OTHER * image-type ad - used before un-marking an ad's previous image, so a * shared image doesn't get incorrectly un-flagged while still in use * elsewhere. * * @param int $image_id The attachment ID to check. * @param int $excluding_ad_id The ad ID to exclude from the check (the one currently being saved). * * @return bool */ private function is_image_used_by_another_ad( int $image_id, int $excluding_ad_id ): bool { $others = get_posts( [ 'post_type' => Constants::POST_TYPE_AD, 'post_status' => 'any', 'posts_per_page' => 1, 'fields' => 'ids', 'no_found_rows' => true, 'post__not_in' => [ $excluding_ad_id ], 'meta_query' => [ 'relation' => 'AND', [ 'key' => Constants::META_PREFIX . 'ad_type', 'value' => 'image' ], [ 'key' => Constants::META_PREFIX . 'image_id', 'value' => $image_id ], ], ] ); return ! empty( $others ); } /** * Adds a read-only field to the attachment details modal indicating usage in AdPresso. * * @param array $fields Existing form fields. * @param WP_Post $post The attachment post object. * * @return array Modified form fields. */ public function add_used_in_ads_field( array $fields, WP_Post $post ): array { if ( get_post_meta( $post->ID, self::META_KEY, true ) ) { $fields['adpresso_used_for_ad'] = [ 'label' => __( 'AdPresso Usage', 'adpresso' ), 'input' => 'html', 'html' => ' ' . 'Used in AdPresso', 'helps' => 'This attachment is currently used in one or more AdPresso items (Ads, Placements, etc.).', ]; } return $fields; } /** * Adds a filter dropdown to the Media Library list table ("List" mode). */ public function add_media_library_filter_dropdown(): void { $screen = get_current_screen(); if ( ! $screen instanceof WP_Screen || $screen->base !== 'upload' || $screen->post_type !== 'attachment' ) { return; } $selected = Params::get()->getKey( 'adpresso_filter' ); echo ''; echo ''; } /** * Modifies the Media Library query based on the selected filter. * * @param WP_Query $query The WP_Query instance (passed by reference). */ public function filter_media_library_query( WP_Query $query ): void { if ( ! is_admin() || ! $query->is_main_query() || $query->get( 'post_type' ) !== 'attachment' ) { return; } $filter_value = Params::get()->getString( 'adpresso_filter', '' ); if ( $filter_value === 'adpresso_used' ) { $meta_query = $query->get( 'meta_query' ) ?: []; if ( ! empty( $meta_query ) && ! isset( $meta_query['relation'] ) ) { $meta_query['relation'] = 'AND'; } $meta_query[] = [ 'key' => self::META_KEY, 'compare' => 'EXISTS', ]; $query->set( 'meta_query', $meta_query ); } elseif ( $filter_value === 'adpresso_not_used' ) { $meta_query = $query->get( 'meta_query' ) ?: []; if ( ! empty( $meta_query ) && ! isset( $meta_query['relation'] ) ) { $meta_query['relation'] = 'AND'; } $meta_query[] = [ 'key' => self::META_KEY, 'compare' => 'NOT EXISTS', ]; $query->set( 'meta_query', $meta_query ); } } }