Changeset 3283881
- Timestamp:
- 04/29/2025 07:56:28 AM (10 months ago)
- Location:
- image-source-control-isc
- Files:
-
- 12 added
- 2 deleted
- 34 edited
- 8 copied
-
assets/screenshot-11-de.png (added)
-
assets/screenshot-11.png (added)
-
tags/3.2.0 (copied) (copied from image-source-control-isc/trunk)
-
tags/3.2.0/admin/assets/js/settings.js (modified) (1 diff)
-
tags/3.2.0/admin/assets/js/sources.js (modified) (1 diff)
-
tags/3.2.0/admin/templates/settings/plugin/images-only.php (added)
-
tags/3.2.0/admin/templates/sources/storage.php (modified) (1 diff)
-
tags/3.2.0/includes/block-options/block-options.php (copied) (copied from image-source-control-isc/trunk/includes/block-options/block-options.php)
-
tags/3.2.0/includes/image-sources/Post_Meta (added)
-
tags/3.2.0/includes/image-sources/Post_Meta/Image_Posts_Meta.php (added)
-
tags/3.2.0/includes/image-sources/Post_Meta/Post_Images_Meta.php (added)
-
tags/3.2.0/includes/image-sources/admin.php (copied) (copied from image-source-control-isc/trunk/includes/image-sources/admin.php) (1 diff)
-
tags/3.2.0/includes/image-sources/admin/ajax.php (modified) (5 diffs)
-
tags/3.2.0/includes/image-sources/admin/fields.php (modified) (1 diff)
-
tags/3.2.0/includes/image-sources/admin/media-library-filters.php (copied) (copied from image-source-control-isc/trunk/includes/image-sources/admin/media-library-filters.php) (1 diff)
-
tags/3.2.0/includes/image-sources/analyze-html.php (modified) (1 diff)
-
tags/3.2.0/includes/image-sources/image-sources.php (modified) (2 diffs)
-
tags/3.2.0/includes/image-sources/utils.php (copied) (copied from image-source-control-isc/trunk/includes/image-sources/utils.php)
-
tags/3.2.0/includes/indexer.php (modified) (6 diffs)
-
tags/3.2.0/includes/media-type-checker.php (added)
-
tags/3.2.0/includes/model.php (modified) (15 diffs)
-
tags/3.2.0/includes/options.php (modified) (1 diff)
-
tags/3.2.0/includes/settings/sections/global-list.php (copied) (copied from image-source-control-isc/trunk/includes/settings/sections/global-list.php)
-
tags/3.2.0/includes/settings/sections/plugin-options.php (modified) (3 diffs)
-
tags/3.2.0/isc.php (copied) (copied from image-source-control-isc/trunk/isc.php) (2 diffs)
-
tags/3.2.0/js (deleted)
-
tags/3.2.0/lib/composer/autoload_classmap.php (modified) (2 diffs)
-
tags/3.2.0/lib/composer/autoload_static.php (modified) (2 diffs)
-
tags/3.2.0/public/public.php (modified) (2 diffs)
-
tags/3.2.0/readme.txt (copied) (copied from image-source-control-isc/trunk/readme.txt) (6 diffs)
-
tags/3.2.0/templates (deleted)
-
tags/3.2.0/uninstall.php (modified) (1 diff)
-
trunk/admin/assets/js/settings.js (modified) (1 diff)
-
trunk/admin/assets/js/sources.js (modified) (1 diff)
-
trunk/admin/templates/settings/plugin/images-only.php (added)
-
trunk/admin/templates/sources/storage.php (modified) (1 diff)
-
trunk/includes/image-sources/Post_Meta (added)
-
trunk/includes/image-sources/Post_Meta/Image_Posts_Meta.php (added)
-
trunk/includes/image-sources/Post_Meta/Post_Images_Meta.php (added)
-
trunk/includes/image-sources/admin.php (modified) (1 diff)
-
trunk/includes/image-sources/admin/ajax.php (modified) (5 diffs)
-
trunk/includes/image-sources/admin/fields.php (modified) (1 diff)
-
trunk/includes/image-sources/admin/media-library-filters.php (modified) (1 diff)
-
trunk/includes/image-sources/analyze-html.php (modified) (1 diff)
-
trunk/includes/image-sources/image-sources.php (modified) (2 diffs)
-
trunk/includes/indexer.php (modified) (6 diffs)
-
trunk/includes/media-type-checker.php (added)
-
trunk/includes/model.php (modified) (15 diffs)
-
trunk/includes/options.php (modified) (1 diff)
-
trunk/includes/settings/sections/plugin-options.php (modified) (3 diffs)
-
trunk/isc.php (modified) (2 diffs)
-
trunk/lib/composer/autoload_classmap.php (modified) (2 diffs)
-
trunk/lib/composer/autoload_static.php (modified) (2 diffs)
-
trunk/public/public.php (modified) (2 diffs)
-
trunk/readme.txt (modified) (6 diffs)
-
trunk/uninstall.php (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
image-source-control-isc/tags/3.2.0/admin/assets/js/settings.js
r3253182 r3283881 18 18 $( '#isc-settings-caption-style input' ).on( 'change', function(){ isc_toggle_caption_position(); } ); 19 19 $( '#isc-settings-global-list-indexed-images' ).on( 'change', function(){ isc_show_reindex_warning(); } ); 20 $('#isc-settings-plugin-modules input[type="checkbox"]').on('change', function() { isc_toggle_module_sections(); }); 20 $( '#isc-settings-plugin-modules input[type="checkbox"]').on('change', function() { isc_toggle_module_sections(); }); 21 $( '#isc-settings-plugin-images-only' ).on( 'change', function() { 22 const enabled = this.checked; 23 $( '#isc-settings-plugin-images-only-indexer' ).toggleClass( 'hidden' ); 24 $( '#isc-settings-plugin-images-only-cleanup-wrapper' ).toggleClass( 'hidden', !enabled ); 25 }); 21 26 22 27 // Show and update preview when a position option is clicked -
image-source-control-isc/tags/3.2.0/admin/assets/js/sources.js
r3101157 r3283881 102 102 } 103 103 ); 104 // show frontend storage 105 $( '#isc-show-storage' ).on( 106 'click', 107 function(){ 108 // disable the button 109 var button = this; 110 button.disabled = true; 111 112 $.ajax( 113 { 114 type: 'POST', 115 url: ajaxurl, 116 data: { 117 action: 'isc-show-storage', 118 nonce: isc.ajaxNonce, 119 }, 120 success:function(data, textStatus, XMLHttpRequest){ 121 // display return messages 122 $( '#isc-show-storage-output' ).html( data ); 123 button.disabled = false; 124 }, 125 error: function(MLHttpRequest, textStatus, errorThrown){ 126 $( '#isc-show-storage-output' ).html( errorThrown ); 127 button.disabled = false; 128 } 129 } 130 ); 131 } 132 ); 104 133 // clear frontend storage 105 134 $( '#isc-clear-storage' ).on( -
image-source-control-isc/tags/3.2.0/admin/templates/sources/storage.php
r3253182 r3283881 22 22 <button id="isc-clear-storage" class="button button-secondary"><?php esc_html_e( 'clear storage', 'image-source-control-isc' ); ?></button> 23 23 <div id="isc-clear-storage-feedback"></div> 24 <?php 25 // if the WordPress debug mode is enabled, show the button to dump the storage 26 if ( $storage_size > 0 && defined( 'WP_DEBUG' ) && WP_DEBUG ) : 27 ?> 28 <br/> 29 <button id="isc-show-storage" class="button button-secondary"><?php esc_html_e( 'show storage', 'image-source-control-isc' ); ?></button> 30 <pre id="isc-show-storage-output"></pre> 31 <?php 32 endif; ?> -
image-source-control-isc/tags/3.2.0/includes/image-sources/admin.php
r3254673 r3283881 6 6 * Admin features for image sources 7 7 */ 8 class Admin { 9 use \ISC\Options; 10 8 class Admin extends Image_Sources { 11 9 /** 12 10 * Initiate admin functions 13 11 */ 14 12 public function __construct() { 13 parent::__construct(); 14 15 15 // load components 16 16 new Image_Sources_Admin_Scripts(); -
image-source-control-isc/tags/3.2.0/includes/image-sources/admin/ajax.php
r3253182 r3283881 3 3 namespace ISC\Image_Sources; 4 4 5 use ISC_Model; 5 use ISC\Image_Sources\Post_Meta\Image_Posts_Meta; 6 use ISC\Image_Sources\Post_Meta\Post_Images_Meta; 6 7 7 8 /** … … 18 19 add_action( 'wp_ajax_isc-image-post-relations', [ $this, 'list_image_post_relations' ] ); 19 20 add_action( 'wp_ajax_isc-clear-index', [ $this, 'clear_index' ] ); 21 add_action( 'wp_ajax_isc-show-storage', [ $this, 'show_storage' ] ); 20 22 add_action( 'wp_ajax_isc-clear-storage', [ $this, 'clear_storage' ] ); 21 23 add_action( 'wp_ajax_isc-clear-image-posts-index', [ $this, 'clear_image_posts_index' ] ); … … 98 100 } 99 101 100 die( 101 sprintf( 102 // translators: %d is the number of deleted entries 103 esc_html__( '%d entries deleted', 'image-source-control-isc' ), 104 (int) ISC_Model::clear_index() 105 ) 106 ); 102 if ( \ISC\Indexer::clear_index() ) { 103 wp_send_json_success( esc_html__( 'Index cleared', 'image-source-control-isc' ) ); 104 } else { 105 wp_send_json_error( 'Error' ); 106 } 107 } 108 109 /** 110 * Show the storage array for debugging 111 */ 112 public function show_storage() { 113 check_ajax_referer( 'isc-admin-ajax-nonce', 'nonce' ); 114 115 if ( ! current_user_can( 'manage_options' ) ) { 116 die( 'Wrong capabilities' ); 117 } 118 119 $storage_model = new \ISC_Storage_Model(); 120 $images = $storage_model->get_storage(); 121 122 // We are in debug mode, so it is fine to just output the content 123 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r 124 print_r( $images ); 125 126 die(); 107 127 } 108 128 … … 137 157 138 158 $image_id = (int) $_POST['image_id']; 139 delete_post_meta( $image_id, 'isc_image_posts');159 $deleted = Image_Posts_Meta::delete( $image_id ); 140 160 141 die( 'Image-Posts index cleared' ); 161 if ( $deleted ) { 162 wp_send_json_success( 'Image-Posts index cleared' ); 163 } else { 164 wp_send_json_success( 'Image-Posts index cleared (or did not exist)' ); 165 } 142 166 } 143 167 … … 157 181 158 182 $post_id = (int) $_POST['post_id']; 159 delete_post_meta( $post_id, 'isc_post_images');183 $deleted = Post_Images_Meta::delete( $post_id ); 160 184 161 die( 'Post-Images index cleared' ); 185 if ( $deleted ) { 186 wp_send_json_success( 'Post-Images index cleared' ); 187 } else { 188 wp_send_json_success( 'Post-Images index cleared (or did not exist)' ); 189 } 162 190 } 163 191 } -
image-source-control-isc/tags/3.2.0/includes/image-sources/admin/fields.php
r3253281 r3283881 23 23 * Add custom field to attachment 24 24 * 25 * @param array $form_fields field fields.26 * @param object $post post object.25 * @param array $form_fields field fields. 26 * @param \WP_Post $post post object. 27 27 * 28 28 * @return array with form fields 29 29 */ 30 30 public function add_isc_fields( $form_fields, $post ) { 31 // Check if we should process this attachment based on settings 32 if ( ! \ISC\Media_Type_Checker::should_process_attachment( $post ) ) { 33 return $form_fields; 34 } 35 31 36 /** 32 37 * Return, when the ISC fields are enabled for blocks, and we are not using the block editor. -
image-source-control-isc/tags/3.2.0/includes/image-sources/admin/media-library-filters.php
r3256706 r3283881 45 45 */ 46 46 public function filter_media_library( \WP_Query $query ) { 47 Admin_Utils::is_media_library_list_view_page(); 47 if ( ! Admin_Utils::is_media_library_list_view_page() ) { 48 return; 49 } 48 50 49 51 // phpcs:ignore WordPress.Security.NonceVerification.Recommended 50 52 $filter = isset( $_GET['isc_filter'] ) ? sanitize_text_field( wp_unslash( $_GET['isc_filter'] ) ) : ''; 53 54 // Add image type check if images_only is enabled 55 if ( \ISC\Media_Type_Checker::enabled_images_only_option() ) { 56 $query->set( 'post_mime_type', 'image%' ); 57 } 51 58 52 59 if ( $filter === 'with_source' ) { -
image-source-control-isc/tags/3.2.0/includes/image-sources/analyze-html.php
r3253281 r3283881 120 120 /** 121 121 * Extract image URLs from HTML. 122 * One image URL per HTML tag will be found. 122 * One image URL per HTML attribute will be found. 123 * 124 * Limitations: 125 * - retrieves the first valid image URL from any HTML tag 126 * - if an IMG tag has a SRC attribute with a valid image URL, all other tags with valid URLs are ignored 127 * - technically, one could generate tags with different images from the Media Library, e.g., having a differently cut URL in a data-attribute 128 * that then shows dynamically using JavaScript 129 * this would cause one of the images not being listed with a source or a used image 130 * since I haven’t seen that in the wild, this case is deliberately ignored 123 131 * 124 132 * @param string $html Any HTML code. -
image-source-control-isc/tags/3.2.0/includes/image-sources/image-sources.php
r3253182 r3283881 10 10 */ 11 11 class Image_Sources { 12 /**13 * Define default meta fields14 *15 * @var array option fields.16 */17 protected $fields = [18 'image_source' => [19 'id' => 'isc_image_source',20 'default' => '',21 ],22 'image_source_url' => [23 'id' => 'isc_image_source_url',24 'default' => '',25 ],26 'image_source_own' => [27 'id' => 'isc_image_source_own',28 'default' => '',29 ],30 'image_posts' => [31 'id' => 'isc_image_posts',32 'default' => [],33 ],34 'image_licence' => [35 'id' => 'isc_image_licence',36 'default' => '',37 ],38 ];39 40 12 /** 41 13 * Allowed image file types/extensions … … 129 101 130 102 /** 131 * Clear post-image index whenever the content of a single post is updated 103 * Update index when a post is deleted or moved into trash 104 */ 105 add_action( 'before_delete_post', [ '\ISC\Indexer', 'handle_post_deletion' ] ); 106 add_action( 'wp_trash_post', [ '\ISC\Indexer', 'handle_post_deletion' ] ); 107 108 /** 109 * Clear post-image index whenever the content of a single post is updated and move the content to a temporary post meta 132 110 * this could force reindexing the post after adding or removing image sources 133 111 */ 134 add_action( 'wp_insert_post', [ 'ISC_Model', 'clear_single_post_images_index' ] ); 135 136 /** 137 * Fire when a post or page was updated 138 */ 139 add_action( 'post_updated', [ 'ISC_Model', 'update_image_post_meta' ], 10, 3 ); 112 add_action( 'wp_insert_post', [ '\ISC\Indexer', 'prepare_for_reindex' ] ); 140 113 } 141 114 -
image-source-control-isc/tags/3.2.0/includes/indexer.php
r3253182 r3283881 3 3 namespace ISC; 4 4 5 use ISC\Image_Sources\Post_Meta\Image_Posts_Meta; 6 use ISC\Image_Sources\Post_Meta\Post_Images_Meta; 5 7 use ISC_Log, ISC_Model; 6 8 … … 10 12 class Indexer { 11 13 12 /** 13 * Handle index updates 14 * 15 * @param string $content content of the target post. 14 const BEFORE_UPDATE_META_KEY = 'isc_post_images_before_update'; 15 16 /** 17 * Handle index updates on frontend visit after a post save. 18 * Compares pre-save state with current render and updates indexes. 19 * 20 * @param string $content Rendered content of the target post. 16 21 * 17 22 * @return void … … 26 31 27 32 // Skip indexing if this is a page with a Global list. 28 if ( has_shortcode( $content, '[isc_list_all]' ) || false !== strpos( $content, 'isc_all_image_list_box' ) ) { 29 // an empty isc_post_images meta value is used to indicate that the post was already indexed 30 ISC_Model::update_post_images_meta( $post->ID, [] ); 33 if ( self::is_global_list_page( $content ) ) { 34 // Ensure no temporary meta is left behind if user adds shortcode later. 35 self::cleanup_after_reindex( $post->ID ); // Use the cleanup method 36 // An empty isc_post_images meta value indicates the post was indexed (or intentionally skipped). 37 if ( Post_Images_Meta::get( $post->ID ) === '' ) { 38 Post_Images_Meta::update_images_in_posts( $post->ID, [] ); 39 } 40 ISC_Log::log( sprintf( 'Exiting update_indexes for post %d: Global list page.', $post->ID ) ); 31 41 return; 32 42 } … … 50 60 */ 51 61 if ( $attachments !== '' ) { 62 // Remove the temporary data since we are not updating the index 63 self::cleanup_after_reindex( $post->ID ); 52 64 return; 53 65 } 54 66 } 55 67 56 ISC_Log::log( ' start updating index for post ID ' . $post->ID );57 58 // check if we can even save the image information59 // abort on archive pages since some output from other plugins might be disabled here60 if ( 61 is_archive()62 || is_home()63 || ! self::can_save_image_information( $post->ID ) ) {68 ISC_Log::log( 'Start updating index for post ID ' . $post->ID ); 69 70 // Check if we can even save the image information 71 // Abort on archive pages, home, or unsupported post types 72 if ( is_archive() || is_home() || ! self::can_save_image_information( $post->ID ) ) { 73 ISC_Log::log( sprintf( 'Exiting update_indexes for post %d: Cannot save image information (archive/home/post type).', $post->ID ) ); 74 // Clean up temporary meta if we abort here 75 self::cleanup_after_reindex( $post->ID ); 64 76 return; 65 77 } 66 78 67 $image_ids = ISC_Model::filter_image_ids( $content ); 68 69 ISC_Log::log( 'updating index with image IDs ' . implode( ', ', $image_ids ) ); 70 71 // retrieve images added to a post or page and save all information as a post meta value for the post 72 ISC_Model::update_post_images_meta( $post->ID, $image_ids ); 73 74 // add the post ID to the list of posts associated with a given image 75 ISC_Model::update_image_posts_meta( $post->ID, $image_ids ); 79 // 1. Get the state before the last update(s). 80 $old_indexed_data = self::get_pre_update_state( $post->ID ); 81 82 // 2. Get the image IDs from the currently rendered content. 83 // Call filter_image_ids only ONCE here. 84 $new_rendered_ids = ISC_Model::filter_image_ids( $content ); 85 86 $thumb_id = get_post_thumbnail_id( $post->ID ); 87 if ( ! empty( $thumb_id ) && ! isset( $new_rendered_ids[ $thumb_id ] ) ) { 88 // Add thumbnail to the list if it's not already there from content parsing. 89 // The value structure should match what filter_image_ids returns, 90 // though sync_image_post_associations only cares about the keys. 91 // The 'thumbnail' flag itself is added later in Post_Meta\Post_Images_Meta::update_images_in_posts. 92 $thumb_url = wp_get_attachment_url( $thumb_id ); 93 if ( $thumb_url ) { 94 $new_rendered_ids[ $thumb_id ] = [ $thumb_url ]; 95 ISC_Log::log( sprintf( 'Added thumbnail ID %d to new_rendered_ids for post %d.', $thumb_id, $post->ID ) ); 96 } 97 } 98 99 /** 100 * Allows developers to modify the list before synchronization. 101 * 102 * @return array $new_rendered_ids Image IDs found in the content ([id => data]). 103 * id is expected to be numeric and the attachment post type 104 */ 105 $new_rendered_ids = apply_filters( 'isc_images_in_posts_simple', $new_rendered_ids, $post->ID ); 106 if ( has_filter( 'isc_images_in_posts_simple' ) ) { 107 ISC_Log::log( sprintf( 'Post %d - new_rendered_ids after isc_images_in_posts_simple filter ran: %s', $post->ID, ! empty( $new_rendered_ids ) ? implode( ', ', array_keys( $new_rendered_ids ) ) : 'Empty' ) ); 108 } 109 110 // Check if image IDs refer to a valid post type (default: 'attachment'). 111 $valid_image_post_types = apply_filters( 'isc_valid_post_types', [ 'attachment' ] ); 112 if ( ! empty( $new_rendered_ids ) ) { // Avoid errors if array is empty 113 foreach ( $new_rendered_ids as $_id => $_data ) { 114 // Ensure ID is numeric before checking post type 115 if ( ! is_numeric( $_id ) || $_id <= 0 ) { 116 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r 117 ISC_Log::log( sprintf( 'Removing invalid image ID %s from index for post %d.', print_r( $_id, true ), $post->ID ) ); 118 unset( $new_rendered_ids[ $_id ] ); 119 continue; 120 } 121 $post_type = get_post_type( (int) $_id ); 122 if ( ! $post_type || ! in_array( $post_type, $valid_image_post_types, true ) ) { 123 ISC_Log::log( sprintf( 'Removing image ID %d (type: %s) due to invalid post type for post %d.', $_id, $post_type ? $post_type : 'unknown', $post->ID ) ); 124 unset( $new_rendered_ids[ $_id ] ); 125 } 126 } 127 } 128 129 // 3. Sync the image->post associations based on comparison. 130 // This handles adding/removing $post->ID from individual image's isc_image_posts meta. 131 self::sync_image_post_associations( $post->ID, $old_indexed_data, $new_rendered_ids ); 132 133 // 4. Update the main post->image index ('isc_post_images') with the current state. 134 // This saves the $new_rendered_ids to the post's meta. 135 Post_Images_Meta::update_images_in_posts( $post->ID, $new_rendered_ids ); 136 137 // 5. Clean up the temporary meta key. 138 self::cleanup_after_reindex( $post->ID ); 76 139 77 140 /** 78 141 * Triggered after updating the indexes. 79 142 * 80 * @param int $post->IDPost ID.81 * @param string $content Post content.82 * @param array $image_ids Image IDs found in the content.143 * @param int $post_id Post ID. 144 * @param string $content Post content. 145 * @param array $new_rendered_ids Image IDs found in the content ([id => data]). 83 146 */ 84 do_action( 'isc_after_update_indexes', $post->ID, $content, $image_ids ); 85 } 86 147 do_action( 'isc_after_update_indexes', $post->ID, $content, $new_rendered_ids ); 148 } 87 149 88 150 /** … … 101 163 } else { 102 164 // check if a post-images index exists 103 $attachments = get_post_meta( $post_id, 'isc_post_images', true);165 $attachments = Post_Images_Meta::get( $post_id ); 104 166 if ( $attachments === '' ) { 105 167 ISC_Log::log( 'no post-images index found' ); … … 173 235 public static function is_index_bot(): bool { 174 236 $user_agent = isset( $_SERVER['HTTP_USER_AGENT'] ) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ) ) : ''; 175 return strpos( $user_agent, 'ISC Index Bot' ) !== false; 237 // Check the user agent first 238 $is_bot = strpos( $user_agent, 'ISC Index Bot' ) !== false; 239 240 /** 241 * Apply a filter to allow overriding the result, passing the original check result 242 * 243 * @param bool $is_bot The result of the initial check. 244 * @return bool The final result after applying the filter. 245 */ 246 return apply_filters( 'isc_is_index_bot', $is_bot ); 247 } 248 249 /** 250 * Prepares a post for re-indexing on the next frontend visit. 251 * Moves the current post-image index to a temporary key if it exists. 252 * 253 * Hooked to 'wp_insert_post'. 254 * 255 * @param int $post_id Post ID. 256 * 257 * @return bool True if preparation was done (index moved), false otherwise. 258 */ 259 public static function prepare_for_reindex( int $post_id ): bool { 260 if ( ! self::can_save_image_information( $post_id ) ) { 261 ISC_Log::log( sprintf( 'Skipping prepare_for_reindex for post %d: Cannot save image information.', $post_id ) ); 262 return false; 263 } 264 265 $old_value = Post_Images_Meta::get( $post_id ); 266 267 if ( is_array( $old_value ) ) { 268 ISC_Log::log( sprintf( 'Preparing post %d for frontend re-index. Moving existing index.', $post_id ) ); 269 update_post_meta( $post_id, self::BEFORE_UPDATE_META_KEY, $old_value ); 270 Post_Images_Meta::delete( $post_id ); 271 return true; 272 } else { 273 ISC_Log::log( sprintf( 'Skipping prepare_for_reindex for post %d: No existing index found or already prepared.', $post_id ) ); 274 return false; 275 } 276 } 277 278 /** 279 * Retrieves the pre-update state of the post-image index. 280 * 281 * @param int $post_id Post ID. 282 * 283 * @return array The old index map, or an empty array if none found. 284 */ 285 public static function get_pre_update_state( int $post_id ): array { 286 $state = get_post_meta( $post_id, self::BEFORE_UPDATE_META_KEY, true ); 287 return is_array( $state ) ? $state : []; 288 } 289 290 /** 291 * Compares old and new image associations for a post and updates 292 * the 'isc_image_posts' meta field on individual images accordingly. 293 * 294 * @param int $post_id The ID of the post being updated. 295 * @param array $old_image_map Map of images previously associated [id => data]. 296 * @param array $new_image_map Map of images currently associated [id => data]. 297 */ 298 public static function sync_image_post_associations( int $post_id, array $old_image_map, array $new_image_map ) { 299 ISC_Log::log( sprintf( 'Entering for post %d.', $post_id ) ); 300 301 // 1. Calculate differences based on image IDs (keys). 302 $old_ids = array_keys( $old_image_map ); 303 $new_ids = array_keys( $new_image_map ); 304 305 // Find IDs present in the new map but not in the old map. 306 $added_ids = array_diff( $new_ids, $old_ids ); 307 // Find IDs present in the old map but not in the new map. 308 $removed_ids = array_diff( $old_ids, $new_ids ); 309 310 ISC_Log::log( sprintf( 'Post %d - Sync Calculated Added IDs: %s', $post_id, ! empty( $added_ids ) ? implode( ', ', $added_ids ) : 'None' ) ); 311 ISC_Log::log( sprintf( 'Post %d - Sync Calculated Removed IDs: %s', $post_id, ! empty( $removed_ids ) ? implode( ', ', $removed_ids ) : 'None' ) ); 312 313 // 2. Update added associations 314 foreach ( $added_ids as $id ) { 315 // Basic validation for ID 316 if ( ! empty( $id ) && is_numeric( $id ) ) { 317 Image_Posts_Meta::add_image_post_association( (int) $id, $post_id ); 318 } else { 319 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r 320 ISC_Log::log( sprintf( 'Skipping add association for invalid ID: %s', print_r( $id, true ) ) ); 321 } 322 } 323 324 // 3. Update removed associations 325 foreach ( $removed_ids as $id ) { 326 // Basic validation for ID 327 if ( ! empty( $id ) && is_numeric( $id ) ) { 328 Image_Posts_Meta::remove_image_post_association( (int) $id, $post_id ); 329 } else { 330 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r 331 ISC_Log::log( sprintf( 'Skipping remove association for invalid ID: %s', print_r( $id, true ) ) ); 332 } 333 } 334 ISC_Log::log( sprintf( 'Exiting for post %d.', $post_id ) ); 335 } 336 337 /** 338 * Cleans up the temporary meta key after re-indexing. 339 * 340 * @param int $post_id Post ID. 341 */ 342 public static function cleanup_after_reindex( int $post_id ) { 343 ISC_Log::log( sprintf( 'Deleting temporary index key %s for post %d.', self::BEFORE_UPDATE_META_KEY, $post_id ) ); 344 delete_post_meta( $post_id, self::BEFORE_UPDATE_META_KEY ); 345 } 346 347 /** 348 * Remove all image-post relations 349 * this concerns the post meta fields `isc_image_posts` and `isc_post_images` 350 * 351 * @return bool True on success, false on failure. 352 */ 353 public static function clear_index(): bool { 354 return Post_Images_Meta::delete_all() && Image_Posts_Meta::delete_all(); 355 } 356 357 /** 358 * Handle post deletion and clean up image-post associations. 359 * 360 * @param int $post_id Post ID. 361 */ 362 public static function handle_post_deletion( int $post_id ): void { 363 $images = Post_Images_Meta::get( $post_id ); 364 if ( is_array( $images ) ) { 365 foreach ( array_keys( $images ) as $image_id ) { 366 Image_Posts_Meta::remove_image_post_association( (int) $image_id, $post_id ); 367 } 368 } 369 370 // Clean up the isc_post_images meta too 371 Post_Images_Meta::delete( $post_id ); 372 } 373 374 /** 375 * Return true if the content indicates that this is a page with the Global List on it 376 * 377 * @param string $content The content to check. 378 * @return bool True if the content contains the Global List shortcode or class, false otherwise. 379 */ 380 public static function is_global_list_page( $content ): bool { 381 return has_shortcode( $content, '[isc_list_all]' ) || false !== strpos( $content, 'isc_all_image_list_box' ); 176 382 } 177 383 } -
image-source-control-isc/tags/3.2.0/includes/model.php
r3253182 r3283881 2 2 3 3 use ISC\Image_Sources\Image_Sources; 4 use ISC\Image_Sources\Post_Meta; 5 use ISC\indexer; 6 4 7 /** 5 8 * Logic to get and store sources … … 22 25 */ 23 26 public function __construct() { 24 // attachment field handling25 add_action( 'add_attachment', [ $this, 'attachment_added' ], 10, 2 );26 27 add_filter( 'attachment_fields_to_save', [ $this, 'isc_fields_save' ], 10, 2 ); 27 28 } … … 55 56 * the function should be used to push a post ID to the (maybe) existing meta field 56 57 * 58 * @removed since April 2025 59 * 57 60 * @param integer $post_id ID of the target post. 58 61 * @param array $image_ids IDs of the attachments in the content. 59 62 */ 60 63 public static function update_image_posts_meta( $post_id, $image_ids ) { 61 ISC_Log::log( 'enter update_image_posts_meta()' ); 62 63 $added_images = []; 64 $removed_images = []; 65 66 // add thumbnail information 67 $thumb_id = get_post_thumbnail_id( $post_id ); 68 if ( ! empty( $thumb_id ) ) { 69 $image_ids[ $thumb_id ] = wp_get_attachment_url( $thumb_id ); 70 ISC_Log::log( 'thumbnail found with ID ' . $thumb_id ); 71 } 72 73 // apply filter to image array, so other developers can add their own logic 74 $image_ids = apply_filters( 'isc_images_in_posts_simple', $image_ids, $post_id ); 75 76 ISC_Log::log( 'known image IDs: ' . implode( ",\n\t", $image_ids ) ); 77 78 // check if image IDs refer to an attachment post type 79 $valid_image_post_types = apply_filters( 'isc_valid_post_types', [ 'attachment' ] ); 80 foreach ( $image_ids as $_id => $_url ) { 81 if ( ! in_array( get_post_type( $_id ), $valid_image_post_types, true ) ) { 82 ISC_Log::log( 'remove image due to invalid post type: ' . $_id ); 83 unset( $image_ids[ $_id ] ); 84 } 85 } 86 87 $isc_post_images = get_post_meta( $post_id, 'isc_post_images', true ); 88 // just needed in very rare cases, when updates comes from outside of isc and meta fields doesn’t exist yet 89 if ( empty( $isc_post_images ) ) { 90 $isc_post_images = []; 91 } 92 93 foreach ( $image_ids as $id => $url ) { 94 if ( is_array( $isc_post_images ) && ! array_key_exists( $id, $isc_post_images ) ) { 95 ISC_Log::log( 'add new image: ' . $id ); 96 $added_images[] = $id; 97 } 98 } 99 if ( is_array( $isc_post_images ) ) { 100 foreach ( $isc_post_images as $old_id => $value ) { 101 if ( ! array_key_exists( $old_id, $image_ids ) ) { 102 $removed_images[] = $old_id; 103 ISC_Log::log( 'remove image: ' . $old_id ); 104 } elseif ( ! empty( $old_id ) ) { 105 $meta = get_post_meta( $old_id, 'isc_image_posts', true ); 106 if ( empty( $meta ) ) { 107 ISC_Log::log( sprintf( 'adding isc_image_posts for image %d and post %d', $old_id, $post_id ) ); 108 self::update_image_posts_meta_with_limit( $old_id, [ $post_id ] ); 109 } elseif ( is_array( $meta ) && ! in_array( $post_id, $meta ) ) { 110 // In case the isc_image_posts is not up to date 111 $meta[] = $post_id; 112 $meta = array_unique( $meta ); 113 ISC_Log::log( sprintf( 'updating isc_image_posts for image %d and posts %s', $old_id, implode( ",\n\t", $meta ) ) ); 114 self::update_image_posts_meta_with_limit( $old_id, $meta ); 115 } 116 } 117 } 118 } 119 120 foreach ( $added_images as $id ) { 121 $meta = get_post_meta( $id, 'isc_image_posts', true ); 122 if ( ! is_array( $meta ) || $meta === [] ) { 123 ISC_Log::log( sprintf( 'adding isc_image_posts for NEW image %d and post %d', $id, $post_id ) ); 124 self::update_image_posts_meta_with_limit( $id, [ $post_id ] ); 125 } else { 126 $meta[] = $post_id; 127 $meta = array_unique( $meta ); 128 ISC_Log::log( sprintf( 'adding isc_image_posts for NEW image %d and posts %s', $id, implode( ', ', $meta ) ) ); 129 self::update_image_posts_meta_with_limit( $id, $meta ); 130 } 131 } 132 133 foreach ( $removed_images as $id ) { 134 $image_meta = get_post_meta( $id, 'isc_image_posts', true ); 135 if ( is_array( $image_meta ) ) { 136 $offset = array_search( $post_id, $image_meta ); 137 if ( $offset !== false ) { 138 array_splice( $image_meta, $offset, 1 ); 139 $image_meta = array_unique( $image_meta ); 140 ISC_Log::log( sprintf( 'updating isc_image_posts for REMOVED image %d and posts %s', $id, implode( ', ', $image_meta ) ) ); 141 self::update_image_posts_meta_with_limit( $id, $image_meta ); 142 } 143 } 144 } 145 } 146 147 /** 148 * Update the isc_image_posts meta field with a filtered limit 149 * 150 * @param integer $post_id ID of the target post. 151 * @param array $image_ids IDs of the attachments in the content. 152 */ 153 public static function update_image_posts_meta_with_limit( int $post_id, array $image_ids ) { 154 // limit the number of post IDs to 10 155 $image_ids = array_slice( $image_ids, 0, apply_filters( 'isc_image_posts_meta_limit', 10 ) ); 156 157 self::update_post_meta( $post_id, 'isc_image_posts', $image_ids ); 158 } 159 160 /** 161 * Retrieve images added to a post or page and save all information as a post meta value for the post 162 * 163 * @param integer $post_id ID of a post. 164 * @param array $image_ids IDs of the attachments in the content. 165 */ 166 public static function update_post_images_meta( $post_id, $image_ids ) { 167 // add thumbnail information 168 $thumb_id = get_post_thumbnail_id( $post_id ); 169 170 /** 171 * If an image is used both inside the post and as post thumbnail, the thumbnail entry overrides the regular image. 172 */ 173 if ( ! empty( $thumb_id ) ) { 174 $image_ids[ $thumb_id ] = [ 175 'src' => wp_get_attachment_url( $thumb_id ), 176 'thumbnail' => true, 177 ]; 178 ISC_Log::log( 'thumbnail found with ID ' . $thumb_id ); 179 } 180 181 // apply filter to image array, so other developers can add their own logic 182 $image_ids = apply_filters( 'isc_images_in_posts', $image_ids, $post_id ); 183 184 if ( empty( $image_ids ) ) { 185 $image_ids = []; 186 } 187 188 ISC_Log::log( 'save isc_post_images with size of ' . count( $image_ids ) ); 189 190 self::update_post_meta( $post_id, 'isc_post_images', $image_ids ); 191 } 192 193 /** 194 * Update attachment meta field 195 * 196 * @param integer $att_id attachment post ID. 197 */ 198 public function attachment_added( $att_id ) { 199 if ( ! isset( $this->fields ) ) { 200 return; 201 } 202 203 foreach ( $this->fields as $field ) { 204 self::update_post_meta( $att_id, $field['id'], $field['default'] ); 205 } 64 65 ISC_Log::log( 'function removed. \ISC\Indexer::update_indexes covers most of it now' ); 206 66 } 207 67 … … 262 122 * Update image-post index attached to attachments when a post is updated 263 123 * 124 * @removed since April 2025 125 * 264 126 * @param int $post_ID Post ID. 265 127 * @param WP_Post $post_after Post object following the update. … … 269 131 */ 270 132 public static function update_image_post_meta( $post_ID, $post_after, $post_before ) { 271 if ( ! \ISC\Indexer::can_save_image_information( $post_ID ) ) { 272 return; 273 } 274 275 $image_ids = self::filter_image_ids( $post_before->post_content ); 276 $thumb_id = get_post_thumbnail_id( $post_ID ); 277 if ( ! empty( $thumb_id ) ) { 278 $image_ids[ $thumb_id ] = ''; 279 } 280 281 // iterate through all image ids and remove the post ID from their "image_posts" meta data 282 foreach ( $image_ids as $image_id => $image_src ) { 283 $meta = get_post_meta( $image_id, 'isc_image_posts', true ); 284 if ( is_array( $meta ) ) { 285 unset( $meta[ array_search( $post_ID, $meta ) ] ); 286 self::update_post_meta( $image_id, 'isc_image_posts', $meta ); 287 } 288 } 133 ISC_Log::log( 'function removed without a replacement.' ); 289 134 } 290 135 … … 293 138 * namely the post meta field `isc_post_images` 294 139 * 140 * @moved since April 2025 141 * 295 142 * @param int $post_id Post ID. 296 143 */ 297 144 public static function clear_single_post_images_index( $post_id ) { 298 delete_post_meta( $post_id, 'isc_post_images' ); 145 ISC_Log::log( 'function moved. \ISC\Image_Sources\Post_Meta\Post_Images_Meta::delete' ); 146 147 Post_Meta\Post_Images_Meta::delete( $post_id ); 299 148 } 300 149 … … 303 152 * namely the post meta field `isc_post_images` 304 153 * 154 * @moved since April 2025 155 * 305 156 * @return int|false The number of rows updated, or false on error. 306 157 */ 307 158 public static function clear_post_images_index() { 308 global $wpdb; 309 310 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.SlowDBQuery.slow_db_query_meta_key 311 return $wpdb->delete( $wpdb->postmeta, [ 'meta_key' => 'isc_post_images' ], [ '%s' ] ); 159 ISC_Log::log( 'function moved. \ISC\Image_Sources\Post_Images_Meta::delete_all' ); 160 161 return Post_Meta\Post_Images_Meta::delete_all(); 312 162 } 313 163 … … 316 166 * namely the post meta field `isc_image_posts` 317 167 * 168 * @moved since April 2025 169 * 318 170 * @return int|false The number of rows updated, or false on error. 319 171 */ 320 172 public static function clear_image_posts_index() { 321 global $wpdb; 322 323 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.SlowDBQuery.slow_db_query_meta_key 324 return $wpdb->delete( $wpdb->postmeta, [ 'meta_key' => 'isc_image_posts' ], [ '%s' ] ); 173 ISC_Log::log( 'function moved. \ISC\Image_Sources\Image_Posts_Meta::delete_all' ); 174 175 return Post_Meta\Image_Posts_Meta::delete_all(); 325 176 } 326 177 … … 329 180 * this concerns the post meta fields `isc_image_posts` and `isc_post_images` 330 181 * 331 * @return int|false The number of rows updated, or false on error. 332 */ 333 public static function clear_index() { 334 $rows_deleted_1 = self::clear_post_images_index(); 335 $rows_deleted_2 = self::clear_image_posts_index(); 336 337 if ( $rows_deleted_1 !== false && $rows_deleted_2 !== false ) { 338 return $rows_deleted_1 + $rows_deleted_2; 339 } 340 341 return false; 182 * @deprecated since April 2025 183 * 184 * @return bool True if the option was removed 185 */ 186 public static function clear_index(): bool { 187 ISC_Log::log( 'function moved. \ISC\Indexer::clear_index' ); 188 189 return Indexer::clear_index(); 342 190 } 343 191 … … 383 231 global $wpdb; 384 232 233 $where_clause = "wp_posts.post_type = 'attachment' AND wp_posts.post_status = 'inherit'"; 234 235 // Add image type check if images_only is enabled 236 if ( \ISC\Media_Type_Checker::enabled_images_only_option() ) { 237 $where_clause .= " AND wp_posts.post_mime_type LIKE 'image/%'"; 238 } 239 385 240 /** 386 241 * Using EXISTS instead of LEFT JOINs resulted in much faster queries and helped caching the results. … … 388 243 $query = "SELECT wp_posts.ID, wp_posts.post_title, wp_posts.post_parent 389 244 FROM {$wpdb->posts} AS wp_posts 390 WHERE wp_posts.post_type = 'attachment' 391 AND wp_posts.post_status = 'inherit' 245 WHERE {$where_clause} 392 246 AND NOT EXISTS ( 393 247 SELECT 1 … … 418 272 // The result of the query is already cached for a day, or until an image is added or removed. 419 273 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared 420 return $wpdb->get_results( $wpdb->prepare( $query, 0, self::MAX_POSTS ) ); 274 $attachments = $wpdb->get_results( $wpdb->prepare( $query, 0, self::MAX_POSTS ) ); 275 276 $count = count( $attachments ); 277 278 // update the transient if the number of results differ 279 if ( $count !== (int) get_transient( 'isc-show-missing-sources-warning' ) ) { 280 set_transient( 'isc-show-missing-sources-warning', $count, DAY_IN_SECONDS ); 281 } 282 283 return $attachments; 421 284 } 422 285 … … 685 548 * @param string $key post meta key. 686 549 * @param mixed $value value of the post meta information. 550 * 551 * @return bool|int 687 552 */ 688 553 public static function update_post_meta( int $post_id, string $key, $value ) { 689 690 554 /** 691 555 * Run when any post meta information is stored by ISC … … 699 563 do_action( 'isc_update_post_meta', $post_id, $key, $value ); 700 564 701 update_post_meta( $post_id, $key, $value );565 return update_post_meta( $post_id, $key, $value ); 702 566 } 703 567 … … 763 627 return $file; 764 628 } 629 630 /** 631 * Remove all plugin meta from non-image attachments 632 * 633 * @return void 634 */ 635 public static function remove_plugin_meta_from_non_images() { 636 // The meta keys used by ISC that should be removed from non-images 637 $isc_meta_keys = [ 638 'isc_image_source', 639 'isc_image_source_url', 640 'isc_image_license', 641 'isc_image_source_own', 642 'isc_image_posts', 643 'isc_possible_usages', 644 'isc_possible_usages_last_check', 645 ]; 646 647 /** 648 * Filter the meta keys to be removed from non-image attachments 649 * 650 * @param array $isc_meta_keys The meta keys to be removed from non-image attachments. 651 */ 652 apply_filters( 'isc_cleanup_non_image_meta_keys', $isc_meta_keys ); 653 654 $attachments = get_posts( 655 [ 656 'post_type' => 'attachment', 657 'post_status' => 'inherit', 658 'posts_per_page' => -1, 659 ] 660 ); 661 662 if ( empty( $attachments ) ) { 663 return; 664 } 665 666 foreach ( $attachments as $attachment ) { 667 if ( ! \ISC\Media_Type_Checker::is_image( $attachment ) ) { 668 foreach ( $isc_meta_keys as $meta_key ) { 669 delete_post_meta( $attachment->ID, $meta_key ); 670 } 671 } 672 } 673 } 765 674 } -
image-source-control-isc/tags/3.2.0/includes/options.php
r3253182 r3283881 84 84 $default['standard_source'] = 'custom_text'; 85 85 $default['standard_source_text'] = ''; 86 $default['images_only'] = false; 86 87 87 88 /** -
image-source-control-isc/tags/3.2.0/includes/settings/sections/plugin-options.php
r3253182 r3283881 17 17 add_settings_section( 'isc_settings_section_plugin', __( 'Plugin options', 'image-source-control-isc' ), '__return_false', 'isc_settings_page' ); 18 18 add_settings_field( 'modules', __( 'Modules', 'image-source-control-isc' ), [ $this, 'render_field_modules' ], 'isc_settings_page', 'isc_settings_section_plugin' ); 19 add_settings_field( 'images_only', __( 'Images only', 'image-source-control-isc' ), [ $this, 'render_field_images_only' ], 'isc_settings_page', 'isc_settings_section_plugin' ); 19 20 add_settings_field( 'remove_on_uninstall', __( 'Delete data on uninstall', 'image-source-control-isc' ), [ $this, 'render_field_remove_on_uninstall' ], 'isc_settings_page', 'isc_settings_section_plugin' ); 20 21 } … … 37 38 38 39 /** 40 * Render the option to restrict functionality to images only. 41 */ 42 public function render_field_images_only() { 43 $options = $this->get_options(); 44 $checked = ! empty( $options['images_only'] ); 45 require_once ISCPATH . '/admin/templates/settings/plugin/images-only.php'; 46 } 47 48 /** 39 49 * Render the option to remove all options and meta data when the plugin is deleted. 40 50 */ … … 54 64 */ 55 65 public function validate_settings( array $output, array $input ): array { 66 $output['modules'] = ( isset( $input['modules'] ) && is_array( $input['modules'] ) ) ? $input['modules'] : []; 67 $output['images_only'] = ! empty( $input['images_only'] ); 68 $output['remove_on_uninstall'] = ! empty( $input['remove_on_uninstall'] ); 56 69 57 $output['modules'] = ( isset( $input['modules'] ) && is_array( $input['modules'] ) ) ? $input['modules'] : []; 58 $output['remove_on_uninstall'] = ! empty( $input['remove_on_uninstall'] ); 70 // Cleanup meta data for non-images 71 if ( 72 ! empty( $input['images_only'] ) && 73 ! empty( $input['images_only_cleanup'] ) 74 ) { 75 \ISC_Model::remove_plugin_meta_from_non_images(); 76 } 59 77 60 78 return $output; -
image-source-control-isc/tags/3.2.0/isc.php
r3256989 r3283881 2 2 /** 3 3 * Plugin Name: Image Source Control Lite 4 * Version: 3. 1.44 * Version: 3.2.0 5 5 * Plugin URI: https://imagesourcecontrol.com/ 6 6 * Description: Image Source Control saves the source of an image, lists them and warns if it is missing. … … 30 30 } 31 31 32 define( 'ISCVERSION', '3. 1.4' );32 define( 'ISCVERSION', '3.2.0' ); 33 33 define( 'ISCNAME', 'Image Source Control' ); 34 34 define( 'ISCDIR', basename( __DIR__ ) ); -
image-source-control-isc/tags/3.2.0/lib/composer/autoload_classmap.php
r3253182 r3283881 24 24 'ISC\\Image_Sources\\Image_Sources' => $baseDir . '/includes/image-sources/image-sources.php', 25 25 'ISC\\Image_Sources\\Image_Sources_Admin_Scripts' => $baseDir . '/includes/image-sources/admin/scripts.php', 26 'ISC\\Image_Sources\\Post_Meta\\Image_Posts_Meta' => $baseDir . '/includes/image-sources/Post_Meta/Image_Posts_Meta.php', 27 'ISC\\Image_Sources\\Post_Meta\\Post_Images_Meta' => $baseDir . '/includes/image-sources/Post_Meta/Post_Images_Meta.php', 26 28 'ISC\\Image_Sources\\Renderer' => $baseDir . '/includes/image-sources/renderer.php', 27 29 'ISC\\Image_Sources\\Renderer\\Caption' => $baseDir . '/includes/image-sources/renderer/caption.php', … … 29 31 'ISC\\Image_Sources\\Utils' => $baseDir . '/includes/image-sources/utils.php', 30 32 'ISC\\Indexer' => $baseDir . '/includes/indexer.php', 33 'ISC\\Media_Type_Checker' => $baseDir . '/includes/media-type-checker.php', 31 34 'ISC\\Newsletter' => $baseDir . '/includes/newsletter.php', 32 35 'ISC\\Options' => $baseDir . '/includes/options.php', -
image-source-control-isc/tags/3.2.0/lib/composer/autoload_static.php
r3253182 r3283881 44 44 'ISC\\Image_Sources\\Image_Sources' => __DIR__ . '/../..' . '/includes/image-sources/image-sources.php', 45 45 'ISC\\Image_Sources\\Image_Sources_Admin_Scripts' => __DIR__ . '/../..' . '/includes/image-sources/admin/scripts.php', 46 'ISC\\Image_Sources\\Post_Meta\\Image_Posts_Meta' => __DIR__ . '/../..' . '/includes/image-sources/Post_Meta/Image_Posts_Meta.php', 47 'ISC\\Image_Sources\\Post_Meta\\Post_Images_Meta' => __DIR__ . '/../..' . '/includes/image-sources/Post_Meta/Post_Images_Meta.php', 46 48 'ISC\\Image_Sources\\Renderer' => __DIR__ . '/../..' . '/includes/image-sources/renderer.php', 47 49 'ISC\\Image_Sources\\Renderer\\Caption' => __DIR__ . '/../..' . '/includes/image-sources/renderer/caption.php', … … 49 51 'ISC\\Image_Sources\\Utils' => __DIR__ . '/../..' . '/includes/image-sources/utils.php', 50 52 'ISC\\Indexer' => __DIR__ . '/../..' . '/includes/indexer.php', 53 'ISC\\Media_Type_Checker' => __DIR__ . '/../..' . '/includes/media-type-checker.php', 51 54 'ISC\\Newsletter' => __DIR__ . '/../..' . '/includes/newsletter.php', 52 55 'ISC\\Options' => __DIR__ . '/../..' . '/includes/options.php', -
image-source-control-isc/tags/3.2.0/public/public.php
r3253182 r3283881 182 182 } 183 183 184 if ( ISC\Indexer::is_global_list_page( $content ) ) { 185 ISC_Log::log( 'skipped adding sources because the content contains the Global List' ); 186 return $content; 187 } 188 184 189 // return if this is not the main query or within the loop 185 190 if ( ! self::is_main_loop() ) { … … 629 634 630 635 foreach ( $attachments as $_attachment ) { 636 // skip non-images if option is selected 637 if ( ! \ISC\Media_Type_Checker::should_process_attachment( $_attachment ) ) { 638 ISC_Log::log( sprintf( 'skipped image %d because it is not an image', $_attachment->ID ) ); 639 continue; 640 } 641 631 642 $connected_atts[ $_attachment->ID ]['source'] = self::get_image_source_text_raw( $_attachment->ID ); 632 643 $connected_atts[ $_attachment->ID ]['standard'] = Standard_Source::use_standard_source( $_attachment->ID ); -
image-source-control-isc/tags/3.2.0/readme.txt
r3275604 r3283881 4 4 Requires at least: 6.0 5 5 Tested up to: 6.8 6 Stable tag: 3. 1.46 Stable tag: 3.2.0 7 7 Requires PHP: 7.4 8 8 License: GPLv3 or later … … 48 48 * Warn about missing image sources 49 49 * Manage, display, and link available licenses 50 * Enable the features for any files in the media library or for images only 51 * Filter the media library list by images with or without sources 50 52 51 53 **Featured Image Caption** … … 61 63 [Check out all features of Image Source Control](https://imagesourcecontrol.com/?utm_source=wporg&utm_medium=link&utm_campaign=all-features). 62 64 65 * The Indexer looks for all images in all published content in one go 63 66 * List credits for images outside the content 64 67 * Add multiple links to the source string … … 67 70 * Show image usage in the image details and the List view of the media library 68 71 * Bulk-edit image copyright information in the media library 72 * Preview image credits in the media library 69 73 * Show the standard picture credit for all images without a selected source 70 74 * [Display IPTC copyright metadata](https://imagesourcecontrol.com/blog/iptc-copyright-information-image-caption-wordpress/) in the backend and automatically as a standard source in the frontend … … 80 84 81 85 Extended compatibility with Elementor, Avada, WP Bakery, and other page builders 82 as well as with plugins like Kadence Blocks, Kadence Related Content Carousel, and Lightbox Gallery.86 as well as with plugins like WPML, Kadence Blocks, Kadence Related Content Carousel, and Lightbox Gallery. 83 87 84 88 [See Pricing](https://imagesourcecontrol.com/pricing/?utm_source=wporg&utm_medium=link&utm_campaign=pricing). … … 151 155 1. Customizing the global list of image sources 152 156 1. Manage image usage licenses 157 1. The Indexer searches for all images in published content 153 158 154 159 == Changelog == 160 161 = 3.2.0 = 162 163 - Feature: You can use the option “Images only” to disable features for non-images in the media library, e.g., PDF files 164 - Improvement: When authors change content, ISC now looks for removed or new images at the next visit of that page in the frontend. This highly improved compatibility with page builders and dynamic content like shortcodes. 165 - Improvement: When WP_DEBUG is enabled, show a button to list the content of the internal storage on the Tools page 166 - Improvement: Removes image source output on pages with the Global List on it 167 - Improvement (Pro): Ignores image URLs in `href` attributes when looking for image sources 168 - Improvement (Pro): Clears the URL storage when the Indexer runs. This can help with issues when a site was migrated to another URL 169 - Improvement (Pro): Extends ignored options for unused images 170 - Improvement (Pro): The column with image sources forms in the Media Library list view only shows if the user has the permission to edit any image information 171 - Improvement (Pro): The forms to edit image sources in the Media Library list view only show if the user has the permission to edit information for that given image 172 - Improvement (Pro): The Indexer for Unused Images now works with posts translated by WPML 173 - Fix: Removes old index information when the last image in a post is removed 174 - Fix (Pro): Some reserved characters in URLs caused (e.g., `&`) the bulk edit fields for images sources in the media library to be cut off 175 - Dev: Extracts post meta handling (`isc_image_posts`, `isc_post_images`) into dedicated classes. 176 - Dev (Pro): Disable image source form fields in the Media Library list view when submitting the filter form to prevent broken URLs. This is related to a compatibility issue caused by a third-party setup 177 - Dev (Pro): The Indexer now works in batches to prevent timeouts on large sites when Query Monitor is installed 178 - Dev (Pro): Pages with the Global List shortcode are now ignored by the Indexer. 179 - Dev: Adds cleanup routines for meta data for deleted and trashed posts. 180 - Dev: Replace some direct DB calls with WP functions 181 - Updates German translation 155 182 156 183 = 3.1.4 = -
image-source-control-isc/tags/3.2.0/uninstall.php
r3253182 r3283881 10 10 11 11 // delete post meta fields 12 $wpdb->delete( $wpdb->postmeta, array( 'meta_key' => 'isc_post_images' ), array( '%s' ) ); 13 $wpdb->delete( $wpdb->postmeta, array( 'meta_key' => 'isc_image_posts' ), array( '%s' ) ); 14 $wpdb->delete( $wpdb->postmeta, array( 'meta_key' => 'isc_image_source' ), array( '%s' ) ); 15 $wpdb->delete( $wpdb->postmeta, array( 'meta_key' => 'isc_image_source_own' ), array( '%s' ) ); 16 $wpdb->delete( $wpdb->postmeta, array( 'meta_key' => 'isc_image_source_url' ), array( '%s' ) ); 17 $wpdb->delete( $wpdb->postmeta, array( 'meta_key' => 'isc_possible_usages' ), array( '%s' ) ); 18 $wpdb->delete( $wpdb->postmeta, array( 'meta_key' => 'isc_possible_usages_last_check' ), array( '%s' ) ); 12 delete_post_meta_by_key( 'isc_post_images' ); 13 delete_post_meta_by_key( 'isc_image_posts' ); 14 delete_post_meta_by_key( 'isc_image_source' ); 15 delete_post_meta_by_key( 'isc_image_source_own' ); 16 delete_post_meta_by_key( 'isc_image_source_url' ); 17 delete_post_meta_by_key( 'isc_possible_usages' ); 18 delete_post_meta_by_key( 'isc_possible_usages_last_check' ); 19 delete_post_meta_by_key( 'isc_post_images_before_update' ); 19 20 20 21 // delete main plugin options -
image-source-control-isc/trunk/admin/assets/js/settings.js
r3253182 r3283881 18 18 $( '#isc-settings-caption-style input' ).on( 'change', function(){ isc_toggle_caption_position(); } ); 19 19 $( '#isc-settings-global-list-indexed-images' ).on( 'change', function(){ isc_show_reindex_warning(); } ); 20 $('#isc-settings-plugin-modules input[type="checkbox"]').on('change', function() { isc_toggle_module_sections(); }); 20 $( '#isc-settings-plugin-modules input[type="checkbox"]').on('change', function() { isc_toggle_module_sections(); }); 21 $( '#isc-settings-plugin-images-only' ).on( 'change', function() { 22 const enabled = this.checked; 23 $( '#isc-settings-plugin-images-only-indexer' ).toggleClass( 'hidden' ); 24 $( '#isc-settings-plugin-images-only-cleanup-wrapper' ).toggleClass( 'hidden', !enabled ); 25 }); 21 26 22 27 // Show and update preview when a position option is clicked -
image-source-control-isc/trunk/admin/assets/js/sources.js
r3101157 r3283881 102 102 } 103 103 ); 104 // show frontend storage 105 $( '#isc-show-storage' ).on( 106 'click', 107 function(){ 108 // disable the button 109 var button = this; 110 button.disabled = true; 111 112 $.ajax( 113 { 114 type: 'POST', 115 url: ajaxurl, 116 data: { 117 action: 'isc-show-storage', 118 nonce: isc.ajaxNonce, 119 }, 120 success:function(data, textStatus, XMLHttpRequest){ 121 // display return messages 122 $( '#isc-show-storage-output' ).html( data ); 123 button.disabled = false; 124 }, 125 error: function(MLHttpRequest, textStatus, errorThrown){ 126 $( '#isc-show-storage-output' ).html( errorThrown ); 127 button.disabled = false; 128 } 129 } 130 ); 131 } 132 ); 104 133 // clear frontend storage 105 134 $( '#isc-clear-storage' ).on( -
image-source-control-isc/trunk/admin/templates/sources/storage.php
r3253182 r3283881 22 22 <button id="isc-clear-storage" class="button button-secondary"><?php esc_html_e( 'clear storage', 'image-source-control-isc' ); ?></button> 23 23 <div id="isc-clear-storage-feedback"></div> 24 <?php 25 // if the WordPress debug mode is enabled, show the button to dump the storage 26 if ( $storage_size > 0 && defined( 'WP_DEBUG' ) && WP_DEBUG ) : 27 ?> 28 <br/> 29 <button id="isc-show-storage" class="button button-secondary"><?php esc_html_e( 'show storage', 'image-source-control-isc' ); ?></button> 30 <pre id="isc-show-storage-output"></pre> 31 <?php 32 endif; ?> -
image-source-control-isc/trunk/includes/image-sources/admin.php
r3254673 r3283881 6 6 * Admin features for image sources 7 7 */ 8 class Admin { 9 use \ISC\Options; 10 8 class Admin extends Image_Sources { 11 9 /** 12 10 * Initiate admin functions 13 11 */ 14 12 public function __construct() { 13 parent::__construct(); 14 15 15 // load components 16 16 new Image_Sources_Admin_Scripts(); -
image-source-control-isc/trunk/includes/image-sources/admin/ajax.php
r3253182 r3283881 3 3 namespace ISC\Image_Sources; 4 4 5 use ISC_Model; 5 use ISC\Image_Sources\Post_Meta\Image_Posts_Meta; 6 use ISC\Image_Sources\Post_Meta\Post_Images_Meta; 6 7 7 8 /** … … 18 19 add_action( 'wp_ajax_isc-image-post-relations', [ $this, 'list_image_post_relations' ] ); 19 20 add_action( 'wp_ajax_isc-clear-index', [ $this, 'clear_index' ] ); 21 add_action( 'wp_ajax_isc-show-storage', [ $this, 'show_storage' ] ); 20 22 add_action( 'wp_ajax_isc-clear-storage', [ $this, 'clear_storage' ] ); 21 23 add_action( 'wp_ajax_isc-clear-image-posts-index', [ $this, 'clear_image_posts_index' ] ); … … 98 100 } 99 101 100 die( 101 sprintf( 102 // translators: %d is the number of deleted entries 103 esc_html__( '%d entries deleted', 'image-source-control-isc' ), 104 (int) ISC_Model::clear_index() 105 ) 106 ); 102 if ( \ISC\Indexer::clear_index() ) { 103 wp_send_json_success( esc_html__( 'Index cleared', 'image-source-control-isc' ) ); 104 } else { 105 wp_send_json_error( 'Error' ); 106 } 107 } 108 109 /** 110 * Show the storage array for debugging 111 */ 112 public function show_storage() { 113 check_ajax_referer( 'isc-admin-ajax-nonce', 'nonce' ); 114 115 if ( ! current_user_can( 'manage_options' ) ) { 116 die( 'Wrong capabilities' ); 117 } 118 119 $storage_model = new \ISC_Storage_Model(); 120 $images = $storage_model->get_storage(); 121 122 // We are in debug mode, so it is fine to just output the content 123 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r 124 print_r( $images ); 125 126 die(); 107 127 } 108 128 … … 137 157 138 158 $image_id = (int) $_POST['image_id']; 139 delete_post_meta( $image_id, 'isc_image_posts');159 $deleted = Image_Posts_Meta::delete( $image_id ); 140 160 141 die( 'Image-Posts index cleared' ); 161 if ( $deleted ) { 162 wp_send_json_success( 'Image-Posts index cleared' ); 163 } else { 164 wp_send_json_success( 'Image-Posts index cleared (or did not exist)' ); 165 } 142 166 } 143 167 … … 157 181 158 182 $post_id = (int) $_POST['post_id']; 159 delete_post_meta( $post_id, 'isc_post_images');183 $deleted = Post_Images_Meta::delete( $post_id ); 160 184 161 die( 'Post-Images index cleared' ); 185 if ( $deleted ) { 186 wp_send_json_success( 'Post-Images index cleared' ); 187 } else { 188 wp_send_json_success( 'Post-Images index cleared (or did not exist)' ); 189 } 162 190 } 163 191 } -
image-source-control-isc/trunk/includes/image-sources/admin/fields.php
r3253281 r3283881 23 23 * Add custom field to attachment 24 24 * 25 * @param array $form_fields field fields.26 * @param object $post post object.25 * @param array $form_fields field fields. 26 * @param \WP_Post $post post object. 27 27 * 28 28 * @return array with form fields 29 29 */ 30 30 public function add_isc_fields( $form_fields, $post ) { 31 // Check if we should process this attachment based on settings 32 if ( ! \ISC\Media_Type_Checker::should_process_attachment( $post ) ) { 33 return $form_fields; 34 } 35 31 36 /** 32 37 * Return, when the ISC fields are enabled for blocks, and we are not using the block editor. -
image-source-control-isc/trunk/includes/image-sources/admin/media-library-filters.php
r3256706 r3283881 45 45 */ 46 46 public function filter_media_library( \WP_Query $query ) { 47 Admin_Utils::is_media_library_list_view_page(); 47 if ( ! Admin_Utils::is_media_library_list_view_page() ) { 48 return; 49 } 48 50 49 51 // phpcs:ignore WordPress.Security.NonceVerification.Recommended 50 52 $filter = isset( $_GET['isc_filter'] ) ? sanitize_text_field( wp_unslash( $_GET['isc_filter'] ) ) : ''; 53 54 // Add image type check if images_only is enabled 55 if ( \ISC\Media_Type_Checker::enabled_images_only_option() ) { 56 $query->set( 'post_mime_type', 'image%' ); 57 } 51 58 52 59 if ( $filter === 'with_source' ) { -
image-source-control-isc/trunk/includes/image-sources/analyze-html.php
r3253281 r3283881 120 120 /** 121 121 * Extract image URLs from HTML. 122 * One image URL per HTML tag will be found. 122 * One image URL per HTML attribute will be found. 123 * 124 * Limitations: 125 * - retrieves the first valid image URL from any HTML tag 126 * - if an IMG tag has a SRC attribute with a valid image URL, all other tags with valid URLs are ignored 127 * - technically, one could generate tags with different images from the Media Library, e.g., having a differently cut URL in a data-attribute 128 * that then shows dynamically using JavaScript 129 * this would cause one of the images not being listed with a source or a used image 130 * since I haven’t seen that in the wild, this case is deliberately ignored 123 131 * 124 132 * @param string $html Any HTML code. -
image-source-control-isc/trunk/includes/image-sources/image-sources.php
r3253182 r3283881 10 10 */ 11 11 class Image_Sources { 12 /**13 * Define default meta fields14 *15 * @var array option fields.16 */17 protected $fields = [18 'image_source' => [19 'id' => 'isc_image_source',20 'default' => '',21 ],22 'image_source_url' => [23 'id' => 'isc_image_source_url',24 'default' => '',25 ],26 'image_source_own' => [27 'id' => 'isc_image_source_own',28 'default' => '',29 ],30 'image_posts' => [31 'id' => 'isc_image_posts',32 'default' => [],33 ],34 'image_licence' => [35 'id' => 'isc_image_licence',36 'default' => '',37 ],38 ];39 40 12 /** 41 13 * Allowed image file types/extensions … … 129 101 130 102 /** 131 * Clear post-image index whenever the content of a single post is updated 103 * Update index when a post is deleted or moved into trash 104 */ 105 add_action( 'before_delete_post', [ '\ISC\Indexer', 'handle_post_deletion' ] ); 106 add_action( 'wp_trash_post', [ '\ISC\Indexer', 'handle_post_deletion' ] ); 107 108 /** 109 * Clear post-image index whenever the content of a single post is updated and move the content to a temporary post meta 132 110 * this could force reindexing the post after adding or removing image sources 133 111 */ 134 add_action( 'wp_insert_post', [ 'ISC_Model', 'clear_single_post_images_index' ] ); 135 136 /** 137 * Fire when a post or page was updated 138 */ 139 add_action( 'post_updated', [ 'ISC_Model', 'update_image_post_meta' ], 10, 3 ); 112 add_action( 'wp_insert_post', [ '\ISC\Indexer', 'prepare_for_reindex' ] ); 140 113 } 141 114 -
image-source-control-isc/trunk/includes/indexer.php
r3253182 r3283881 3 3 namespace ISC; 4 4 5 use ISC\Image_Sources\Post_Meta\Image_Posts_Meta; 6 use ISC\Image_Sources\Post_Meta\Post_Images_Meta; 5 7 use ISC_Log, ISC_Model; 6 8 … … 10 12 class Indexer { 11 13 12 /** 13 * Handle index updates 14 * 15 * @param string $content content of the target post. 14 const BEFORE_UPDATE_META_KEY = 'isc_post_images_before_update'; 15 16 /** 17 * Handle index updates on frontend visit after a post save. 18 * Compares pre-save state with current render and updates indexes. 19 * 20 * @param string $content Rendered content of the target post. 16 21 * 17 22 * @return void … … 26 31 27 32 // Skip indexing if this is a page with a Global list. 28 if ( has_shortcode( $content, '[isc_list_all]' ) || false !== strpos( $content, 'isc_all_image_list_box' ) ) { 29 // an empty isc_post_images meta value is used to indicate that the post was already indexed 30 ISC_Model::update_post_images_meta( $post->ID, [] ); 33 if ( self::is_global_list_page( $content ) ) { 34 // Ensure no temporary meta is left behind if user adds shortcode later. 35 self::cleanup_after_reindex( $post->ID ); // Use the cleanup method 36 // An empty isc_post_images meta value indicates the post was indexed (or intentionally skipped). 37 if ( Post_Images_Meta::get( $post->ID ) === '' ) { 38 Post_Images_Meta::update_images_in_posts( $post->ID, [] ); 39 } 40 ISC_Log::log( sprintf( 'Exiting update_indexes for post %d: Global list page.', $post->ID ) ); 31 41 return; 32 42 } … … 50 60 */ 51 61 if ( $attachments !== '' ) { 62 // Remove the temporary data since we are not updating the index 63 self::cleanup_after_reindex( $post->ID ); 52 64 return; 53 65 } 54 66 } 55 67 56 ISC_Log::log( ' start updating index for post ID ' . $post->ID );57 58 // check if we can even save the image information59 // abort on archive pages since some output from other plugins might be disabled here60 if ( 61 is_archive()62 || is_home()63 || ! self::can_save_image_information( $post->ID ) ) {68 ISC_Log::log( 'Start updating index for post ID ' . $post->ID ); 69 70 // Check if we can even save the image information 71 // Abort on archive pages, home, or unsupported post types 72 if ( is_archive() || is_home() || ! self::can_save_image_information( $post->ID ) ) { 73 ISC_Log::log( sprintf( 'Exiting update_indexes for post %d: Cannot save image information (archive/home/post type).', $post->ID ) ); 74 // Clean up temporary meta if we abort here 75 self::cleanup_after_reindex( $post->ID ); 64 76 return; 65 77 } 66 78 67 $image_ids = ISC_Model::filter_image_ids( $content ); 68 69 ISC_Log::log( 'updating index with image IDs ' . implode( ', ', $image_ids ) ); 70 71 // retrieve images added to a post or page and save all information as a post meta value for the post 72 ISC_Model::update_post_images_meta( $post->ID, $image_ids ); 73 74 // add the post ID to the list of posts associated with a given image 75 ISC_Model::update_image_posts_meta( $post->ID, $image_ids ); 79 // 1. Get the state before the last update(s). 80 $old_indexed_data = self::get_pre_update_state( $post->ID ); 81 82 // 2. Get the image IDs from the currently rendered content. 83 // Call filter_image_ids only ONCE here. 84 $new_rendered_ids = ISC_Model::filter_image_ids( $content ); 85 86 $thumb_id = get_post_thumbnail_id( $post->ID ); 87 if ( ! empty( $thumb_id ) && ! isset( $new_rendered_ids[ $thumb_id ] ) ) { 88 // Add thumbnail to the list if it's not already there from content parsing. 89 // The value structure should match what filter_image_ids returns, 90 // though sync_image_post_associations only cares about the keys. 91 // The 'thumbnail' flag itself is added later in Post_Meta\Post_Images_Meta::update_images_in_posts. 92 $thumb_url = wp_get_attachment_url( $thumb_id ); 93 if ( $thumb_url ) { 94 $new_rendered_ids[ $thumb_id ] = [ $thumb_url ]; 95 ISC_Log::log( sprintf( 'Added thumbnail ID %d to new_rendered_ids for post %d.', $thumb_id, $post->ID ) ); 96 } 97 } 98 99 /** 100 * Allows developers to modify the list before synchronization. 101 * 102 * @return array $new_rendered_ids Image IDs found in the content ([id => data]). 103 * id is expected to be numeric and the attachment post type 104 */ 105 $new_rendered_ids = apply_filters( 'isc_images_in_posts_simple', $new_rendered_ids, $post->ID ); 106 if ( has_filter( 'isc_images_in_posts_simple' ) ) { 107 ISC_Log::log( sprintf( 'Post %d - new_rendered_ids after isc_images_in_posts_simple filter ran: %s', $post->ID, ! empty( $new_rendered_ids ) ? implode( ', ', array_keys( $new_rendered_ids ) ) : 'Empty' ) ); 108 } 109 110 // Check if image IDs refer to a valid post type (default: 'attachment'). 111 $valid_image_post_types = apply_filters( 'isc_valid_post_types', [ 'attachment' ] ); 112 if ( ! empty( $new_rendered_ids ) ) { // Avoid errors if array is empty 113 foreach ( $new_rendered_ids as $_id => $_data ) { 114 // Ensure ID is numeric before checking post type 115 if ( ! is_numeric( $_id ) || $_id <= 0 ) { 116 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r 117 ISC_Log::log( sprintf( 'Removing invalid image ID %s from index for post %d.', print_r( $_id, true ), $post->ID ) ); 118 unset( $new_rendered_ids[ $_id ] ); 119 continue; 120 } 121 $post_type = get_post_type( (int) $_id ); 122 if ( ! $post_type || ! in_array( $post_type, $valid_image_post_types, true ) ) { 123 ISC_Log::log( sprintf( 'Removing image ID %d (type: %s) due to invalid post type for post %d.', $_id, $post_type ? $post_type : 'unknown', $post->ID ) ); 124 unset( $new_rendered_ids[ $_id ] ); 125 } 126 } 127 } 128 129 // 3. Sync the image->post associations based on comparison. 130 // This handles adding/removing $post->ID from individual image's isc_image_posts meta. 131 self::sync_image_post_associations( $post->ID, $old_indexed_data, $new_rendered_ids ); 132 133 // 4. Update the main post->image index ('isc_post_images') with the current state. 134 // This saves the $new_rendered_ids to the post's meta. 135 Post_Images_Meta::update_images_in_posts( $post->ID, $new_rendered_ids ); 136 137 // 5. Clean up the temporary meta key. 138 self::cleanup_after_reindex( $post->ID ); 76 139 77 140 /** 78 141 * Triggered after updating the indexes. 79 142 * 80 * @param int $post->IDPost ID.81 * @param string $content Post content.82 * @param array $image_ids Image IDs found in the content.143 * @param int $post_id Post ID. 144 * @param string $content Post content. 145 * @param array $new_rendered_ids Image IDs found in the content ([id => data]). 83 146 */ 84 do_action( 'isc_after_update_indexes', $post->ID, $content, $image_ids ); 85 } 86 147 do_action( 'isc_after_update_indexes', $post->ID, $content, $new_rendered_ids ); 148 } 87 149 88 150 /** … … 101 163 } else { 102 164 // check if a post-images index exists 103 $attachments = get_post_meta( $post_id, 'isc_post_images', true);165 $attachments = Post_Images_Meta::get( $post_id ); 104 166 if ( $attachments === '' ) { 105 167 ISC_Log::log( 'no post-images index found' ); … … 173 235 public static function is_index_bot(): bool { 174 236 $user_agent = isset( $_SERVER['HTTP_USER_AGENT'] ) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ) ) : ''; 175 return strpos( $user_agent, 'ISC Index Bot' ) !== false; 237 // Check the user agent first 238 $is_bot = strpos( $user_agent, 'ISC Index Bot' ) !== false; 239 240 /** 241 * Apply a filter to allow overriding the result, passing the original check result 242 * 243 * @param bool $is_bot The result of the initial check. 244 * @return bool The final result after applying the filter. 245 */ 246 return apply_filters( 'isc_is_index_bot', $is_bot ); 247 } 248 249 /** 250 * Prepares a post for re-indexing on the next frontend visit. 251 * Moves the current post-image index to a temporary key if it exists. 252 * 253 * Hooked to 'wp_insert_post'. 254 * 255 * @param int $post_id Post ID. 256 * 257 * @return bool True if preparation was done (index moved), false otherwise. 258 */ 259 public static function prepare_for_reindex( int $post_id ): bool { 260 if ( ! self::can_save_image_information( $post_id ) ) { 261 ISC_Log::log( sprintf( 'Skipping prepare_for_reindex for post %d: Cannot save image information.', $post_id ) ); 262 return false; 263 } 264 265 $old_value = Post_Images_Meta::get( $post_id ); 266 267 if ( is_array( $old_value ) ) { 268 ISC_Log::log( sprintf( 'Preparing post %d for frontend re-index. Moving existing index.', $post_id ) ); 269 update_post_meta( $post_id, self::BEFORE_UPDATE_META_KEY, $old_value ); 270 Post_Images_Meta::delete( $post_id ); 271 return true; 272 } else { 273 ISC_Log::log( sprintf( 'Skipping prepare_for_reindex for post %d: No existing index found or already prepared.', $post_id ) ); 274 return false; 275 } 276 } 277 278 /** 279 * Retrieves the pre-update state of the post-image index. 280 * 281 * @param int $post_id Post ID. 282 * 283 * @return array The old index map, or an empty array if none found. 284 */ 285 public static function get_pre_update_state( int $post_id ): array { 286 $state = get_post_meta( $post_id, self::BEFORE_UPDATE_META_KEY, true ); 287 return is_array( $state ) ? $state : []; 288 } 289 290 /** 291 * Compares old and new image associations for a post and updates 292 * the 'isc_image_posts' meta field on individual images accordingly. 293 * 294 * @param int $post_id The ID of the post being updated. 295 * @param array $old_image_map Map of images previously associated [id => data]. 296 * @param array $new_image_map Map of images currently associated [id => data]. 297 */ 298 public static function sync_image_post_associations( int $post_id, array $old_image_map, array $new_image_map ) { 299 ISC_Log::log( sprintf( 'Entering for post %d.', $post_id ) ); 300 301 // 1. Calculate differences based on image IDs (keys). 302 $old_ids = array_keys( $old_image_map ); 303 $new_ids = array_keys( $new_image_map ); 304 305 // Find IDs present in the new map but not in the old map. 306 $added_ids = array_diff( $new_ids, $old_ids ); 307 // Find IDs present in the old map but not in the new map. 308 $removed_ids = array_diff( $old_ids, $new_ids ); 309 310 ISC_Log::log( sprintf( 'Post %d - Sync Calculated Added IDs: %s', $post_id, ! empty( $added_ids ) ? implode( ', ', $added_ids ) : 'None' ) ); 311 ISC_Log::log( sprintf( 'Post %d - Sync Calculated Removed IDs: %s', $post_id, ! empty( $removed_ids ) ? implode( ', ', $removed_ids ) : 'None' ) ); 312 313 // 2. Update added associations 314 foreach ( $added_ids as $id ) { 315 // Basic validation for ID 316 if ( ! empty( $id ) && is_numeric( $id ) ) { 317 Image_Posts_Meta::add_image_post_association( (int) $id, $post_id ); 318 } else { 319 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r 320 ISC_Log::log( sprintf( 'Skipping add association for invalid ID: %s', print_r( $id, true ) ) ); 321 } 322 } 323 324 // 3. Update removed associations 325 foreach ( $removed_ids as $id ) { 326 // Basic validation for ID 327 if ( ! empty( $id ) && is_numeric( $id ) ) { 328 Image_Posts_Meta::remove_image_post_association( (int) $id, $post_id ); 329 } else { 330 // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_print_r 331 ISC_Log::log( sprintf( 'Skipping remove association for invalid ID: %s', print_r( $id, true ) ) ); 332 } 333 } 334 ISC_Log::log( sprintf( 'Exiting for post %d.', $post_id ) ); 335 } 336 337 /** 338 * Cleans up the temporary meta key after re-indexing. 339 * 340 * @param int $post_id Post ID. 341 */ 342 public static function cleanup_after_reindex( int $post_id ) { 343 ISC_Log::log( sprintf( 'Deleting temporary index key %s for post %d.', self::BEFORE_UPDATE_META_KEY, $post_id ) ); 344 delete_post_meta( $post_id, self::BEFORE_UPDATE_META_KEY ); 345 } 346 347 /** 348 * Remove all image-post relations 349 * this concerns the post meta fields `isc_image_posts` and `isc_post_images` 350 * 351 * @return bool True on success, false on failure. 352 */ 353 public static function clear_index(): bool { 354 return Post_Images_Meta::delete_all() && Image_Posts_Meta::delete_all(); 355 } 356 357 /** 358 * Handle post deletion and clean up image-post associations. 359 * 360 * @param int $post_id Post ID. 361 */ 362 public static function handle_post_deletion( int $post_id ): void { 363 $images = Post_Images_Meta::get( $post_id ); 364 if ( is_array( $images ) ) { 365 foreach ( array_keys( $images ) as $image_id ) { 366 Image_Posts_Meta::remove_image_post_association( (int) $image_id, $post_id ); 367 } 368 } 369 370 // Clean up the isc_post_images meta too 371 Post_Images_Meta::delete( $post_id ); 372 } 373 374 /** 375 * Return true if the content indicates that this is a page with the Global List on it 376 * 377 * @param string $content The content to check. 378 * @return bool True if the content contains the Global List shortcode or class, false otherwise. 379 */ 380 public static function is_global_list_page( $content ): bool { 381 return has_shortcode( $content, '[isc_list_all]' ) || false !== strpos( $content, 'isc_all_image_list_box' ); 176 382 } 177 383 } -
image-source-control-isc/trunk/includes/model.php
r3253182 r3283881 2 2 3 3 use ISC\Image_Sources\Image_Sources; 4 use ISC\Image_Sources\Post_Meta; 5 use ISC\indexer; 6 4 7 /** 5 8 * Logic to get and store sources … … 22 25 */ 23 26 public function __construct() { 24 // attachment field handling25 add_action( 'add_attachment', [ $this, 'attachment_added' ], 10, 2 );26 27 add_filter( 'attachment_fields_to_save', [ $this, 'isc_fields_save' ], 10, 2 ); 27 28 } … … 55 56 * the function should be used to push a post ID to the (maybe) existing meta field 56 57 * 58 * @removed since April 2025 59 * 57 60 * @param integer $post_id ID of the target post. 58 61 * @param array $image_ids IDs of the attachments in the content. 59 62 */ 60 63 public static function update_image_posts_meta( $post_id, $image_ids ) { 61 ISC_Log::log( 'enter update_image_posts_meta()' ); 62 63 $added_images = []; 64 $removed_images = []; 65 66 // add thumbnail information 67 $thumb_id = get_post_thumbnail_id( $post_id ); 68 if ( ! empty( $thumb_id ) ) { 69 $image_ids[ $thumb_id ] = wp_get_attachment_url( $thumb_id ); 70 ISC_Log::log( 'thumbnail found with ID ' . $thumb_id ); 71 } 72 73 // apply filter to image array, so other developers can add their own logic 74 $image_ids = apply_filters( 'isc_images_in_posts_simple', $image_ids, $post_id ); 75 76 ISC_Log::log( 'known image IDs: ' . implode( ",\n\t", $image_ids ) ); 77 78 // check if image IDs refer to an attachment post type 79 $valid_image_post_types = apply_filters( 'isc_valid_post_types', [ 'attachment' ] ); 80 foreach ( $image_ids as $_id => $_url ) { 81 if ( ! in_array( get_post_type( $_id ), $valid_image_post_types, true ) ) { 82 ISC_Log::log( 'remove image due to invalid post type: ' . $_id ); 83 unset( $image_ids[ $_id ] ); 84 } 85 } 86 87 $isc_post_images = get_post_meta( $post_id, 'isc_post_images', true ); 88 // just needed in very rare cases, when updates comes from outside of isc and meta fields doesn’t exist yet 89 if ( empty( $isc_post_images ) ) { 90 $isc_post_images = []; 91 } 92 93 foreach ( $image_ids as $id => $url ) { 94 if ( is_array( $isc_post_images ) && ! array_key_exists( $id, $isc_post_images ) ) { 95 ISC_Log::log( 'add new image: ' . $id ); 96 $added_images[] = $id; 97 } 98 } 99 if ( is_array( $isc_post_images ) ) { 100 foreach ( $isc_post_images as $old_id => $value ) { 101 if ( ! array_key_exists( $old_id, $image_ids ) ) { 102 $removed_images[] = $old_id; 103 ISC_Log::log( 'remove image: ' . $old_id ); 104 } elseif ( ! empty( $old_id ) ) { 105 $meta = get_post_meta( $old_id, 'isc_image_posts', true ); 106 if ( empty( $meta ) ) { 107 ISC_Log::log( sprintf( 'adding isc_image_posts for image %d and post %d', $old_id, $post_id ) ); 108 self::update_image_posts_meta_with_limit( $old_id, [ $post_id ] ); 109 } elseif ( is_array( $meta ) && ! in_array( $post_id, $meta ) ) { 110 // In case the isc_image_posts is not up to date 111 $meta[] = $post_id; 112 $meta = array_unique( $meta ); 113 ISC_Log::log( sprintf( 'updating isc_image_posts for image %d and posts %s', $old_id, implode( ",\n\t", $meta ) ) ); 114 self::update_image_posts_meta_with_limit( $old_id, $meta ); 115 } 116 } 117 } 118 } 119 120 foreach ( $added_images as $id ) { 121 $meta = get_post_meta( $id, 'isc_image_posts', true ); 122 if ( ! is_array( $meta ) || $meta === [] ) { 123 ISC_Log::log( sprintf( 'adding isc_image_posts for NEW image %d and post %d', $id, $post_id ) ); 124 self::update_image_posts_meta_with_limit( $id, [ $post_id ] ); 125 } else { 126 $meta[] = $post_id; 127 $meta = array_unique( $meta ); 128 ISC_Log::log( sprintf( 'adding isc_image_posts for NEW image %d and posts %s', $id, implode( ', ', $meta ) ) ); 129 self::update_image_posts_meta_with_limit( $id, $meta ); 130 } 131 } 132 133 foreach ( $removed_images as $id ) { 134 $image_meta = get_post_meta( $id, 'isc_image_posts', true ); 135 if ( is_array( $image_meta ) ) { 136 $offset = array_search( $post_id, $image_meta ); 137 if ( $offset !== false ) { 138 array_splice( $image_meta, $offset, 1 ); 139 $image_meta = array_unique( $image_meta ); 140 ISC_Log::log( sprintf( 'updating isc_image_posts for REMOVED image %d and posts %s', $id, implode( ', ', $image_meta ) ) ); 141 self::update_image_posts_meta_with_limit( $id, $image_meta ); 142 } 143 } 144 } 145 } 146 147 /** 148 * Update the isc_image_posts meta field with a filtered limit 149 * 150 * @param integer $post_id ID of the target post. 151 * @param array $image_ids IDs of the attachments in the content. 152 */ 153 public static function update_image_posts_meta_with_limit( int $post_id, array $image_ids ) { 154 // limit the number of post IDs to 10 155 $image_ids = array_slice( $image_ids, 0, apply_filters( 'isc_image_posts_meta_limit', 10 ) ); 156 157 self::update_post_meta( $post_id, 'isc_image_posts', $image_ids ); 158 } 159 160 /** 161 * Retrieve images added to a post or page and save all information as a post meta value for the post 162 * 163 * @param integer $post_id ID of a post. 164 * @param array $image_ids IDs of the attachments in the content. 165 */ 166 public static function update_post_images_meta( $post_id, $image_ids ) { 167 // add thumbnail information 168 $thumb_id = get_post_thumbnail_id( $post_id ); 169 170 /** 171 * If an image is used both inside the post and as post thumbnail, the thumbnail entry overrides the regular image. 172 */ 173 if ( ! empty( $thumb_id ) ) { 174 $image_ids[ $thumb_id ] = [ 175 'src' => wp_get_attachment_url( $thumb_id ), 176 'thumbnail' => true, 177 ]; 178 ISC_Log::log( 'thumbnail found with ID ' . $thumb_id ); 179 } 180 181 // apply filter to image array, so other developers can add their own logic 182 $image_ids = apply_filters( 'isc_images_in_posts', $image_ids, $post_id ); 183 184 if ( empty( $image_ids ) ) { 185 $image_ids = []; 186 } 187 188 ISC_Log::log( 'save isc_post_images with size of ' . count( $image_ids ) ); 189 190 self::update_post_meta( $post_id, 'isc_post_images', $image_ids ); 191 } 192 193 /** 194 * Update attachment meta field 195 * 196 * @param integer $att_id attachment post ID. 197 */ 198 public function attachment_added( $att_id ) { 199 if ( ! isset( $this->fields ) ) { 200 return; 201 } 202 203 foreach ( $this->fields as $field ) { 204 self::update_post_meta( $att_id, $field['id'], $field['default'] ); 205 } 64 65 ISC_Log::log( 'function removed. \ISC\Indexer::update_indexes covers most of it now' ); 206 66 } 207 67 … … 262 122 * Update image-post index attached to attachments when a post is updated 263 123 * 124 * @removed since April 2025 125 * 264 126 * @param int $post_ID Post ID. 265 127 * @param WP_Post $post_after Post object following the update. … … 269 131 */ 270 132 public static function update_image_post_meta( $post_ID, $post_after, $post_before ) { 271 if ( ! \ISC\Indexer::can_save_image_information( $post_ID ) ) { 272 return; 273 } 274 275 $image_ids = self::filter_image_ids( $post_before->post_content ); 276 $thumb_id = get_post_thumbnail_id( $post_ID ); 277 if ( ! empty( $thumb_id ) ) { 278 $image_ids[ $thumb_id ] = ''; 279 } 280 281 // iterate through all image ids and remove the post ID from their "image_posts" meta data 282 foreach ( $image_ids as $image_id => $image_src ) { 283 $meta = get_post_meta( $image_id, 'isc_image_posts', true ); 284 if ( is_array( $meta ) ) { 285 unset( $meta[ array_search( $post_ID, $meta ) ] ); 286 self::update_post_meta( $image_id, 'isc_image_posts', $meta ); 287 } 288 } 133 ISC_Log::log( 'function removed without a replacement.' ); 289 134 } 290 135 … … 293 138 * namely the post meta field `isc_post_images` 294 139 * 140 * @moved since April 2025 141 * 295 142 * @param int $post_id Post ID. 296 143 */ 297 144 public static function clear_single_post_images_index( $post_id ) { 298 delete_post_meta( $post_id, 'isc_post_images' ); 145 ISC_Log::log( 'function moved. \ISC\Image_Sources\Post_Meta\Post_Images_Meta::delete' ); 146 147 Post_Meta\Post_Images_Meta::delete( $post_id ); 299 148 } 300 149 … … 303 152 * namely the post meta field `isc_post_images` 304 153 * 154 * @moved since April 2025 155 * 305 156 * @return int|false The number of rows updated, or false on error. 306 157 */ 307 158 public static function clear_post_images_index() { 308 global $wpdb; 309 310 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.SlowDBQuery.slow_db_query_meta_key 311 return $wpdb->delete( $wpdb->postmeta, [ 'meta_key' => 'isc_post_images' ], [ '%s' ] ); 159 ISC_Log::log( 'function moved. \ISC\Image_Sources\Post_Images_Meta::delete_all' ); 160 161 return Post_Meta\Post_Images_Meta::delete_all(); 312 162 } 313 163 … … 316 166 * namely the post meta field `isc_image_posts` 317 167 * 168 * @moved since April 2025 169 * 318 170 * @return int|false The number of rows updated, or false on error. 319 171 */ 320 172 public static function clear_image_posts_index() { 321 global $wpdb; 322 323 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.SlowDBQuery.slow_db_query_meta_key 324 return $wpdb->delete( $wpdb->postmeta, [ 'meta_key' => 'isc_image_posts' ], [ '%s' ] ); 173 ISC_Log::log( 'function moved. \ISC\Image_Sources\Image_Posts_Meta::delete_all' ); 174 175 return Post_Meta\Image_Posts_Meta::delete_all(); 325 176 } 326 177 … … 329 180 * this concerns the post meta fields `isc_image_posts` and `isc_post_images` 330 181 * 331 * @return int|false The number of rows updated, or false on error. 332 */ 333 public static function clear_index() { 334 $rows_deleted_1 = self::clear_post_images_index(); 335 $rows_deleted_2 = self::clear_image_posts_index(); 336 337 if ( $rows_deleted_1 !== false && $rows_deleted_2 !== false ) { 338 return $rows_deleted_1 + $rows_deleted_2; 339 } 340 341 return false; 182 * @deprecated since April 2025 183 * 184 * @return bool True if the option was removed 185 */ 186 public static function clear_index(): bool { 187 ISC_Log::log( 'function moved. \ISC\Indexer::clear_index' ); 188 189 return Indexer::clear_index(); 342 190 } 343 191 … … 383 231 global $wpdb; 384 232 233 $where_clause = "wp_posts.post_type = 'attachment' AND wp_posts.post_status = 'inherit'"; 234 235 // Add image type check if images_only is enabled 236 if ( \ISC\Media_Type_Checker::enabled_images_only_option() ) { 237 $where_clause .= " AND wp_posts.post_mime_type LIKE 'image/%'"; 238 } 239 385 240 /** 386 241 * Using EXISTS instead of LEFT JOINs resulted in much faster queries and helped caching the results. … … 388 243 $query = "SELECT wp_posts.ID, wp_posts.post_title, wp_posts.post_parent 389 244 FROM {$wpdb->posts} AS wp_posts 390 WHERE wp_posts.post_type = 'attachment' 391 AND wp_posts.post_status = 'inherit' 245 WHERE {$where_clause} 392 246 AND NOT EXISTS ( 393 247 SELECT 1 … … 418 272 // The result of the query is already cached for a day, or until an image is added or removed. 419 273 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared 420 return $wpdb->get_results( $wpdb->prepare( $query, 0, self::MAX_POSTS ) ); 274 $attachments = $wpdb->get_results( $wpdb->prepare( $query, 0, self::MAX_POSTS ) ); 275 276 $count = count( $attachments ); 277 278 // update the transient if the number of results differ 279 if ( $count !== (int) get_transient( 'isc-show-missing-sources-warning' ) ) { 280 set_transient( 'isc-show-missing-sources-warning', $count, DAY_IN_SECONDS ); 281 } 282 283 return $attachments; 421 284 } 422 285 … … 685 548 * @param string $key post meta key. 686 549 * @param mixed $value value of the post meta information. 550 * 551 * @return bool|int 687 552 */ 688 553 public static function update_post_meta( int $post_id, string $key, $value ) { 689 690 554 /** 691 555 * Run when any post meta information is stored by ISC … … 699 563 do_action( 'isc_update_post_meta', $post_id, $key, $value ); 700 564 701 update_post_meta( $post_id, $key, $value );565 return update_post_meta( $post_id, $key, $value ); 702 566 } 703 567 … … 763 627 return $file; 764 628 } 629 630 /** 631 * Remove all plugin meta from non-image attachments 632 * 633 * @return void 634 */ 635 public static function remove_plugin_meta_from_non_images() { 636 // The meta keys used by ISC that should be removed from non-images 637 $isc_meta_keys = [ 638 'isc_image_source', 639 'isc_image_source_url', 640 'isc_image_license', 641 'isc_image_source_own', 642 'isc_image_posts', 643 'isc_possible_usages', 644 'isc_possible_usages_last_check', 645 ]; 646 647 /** 648 * Filter the meta keys to be removed from non-image attachments 649 * 650 * @param array $isc_meta_keys The meta keys to be removed from non-image attachments. 651 */ 652 apply_filters( 'isc_cleanup_non_image_meta_keys', $isc_meta_keys ); 653 654 $attachments = get_posts( 655 [ 656 'post_type' => 'attachment', 657 'post_status' => 'inherit', 658 'posts_per_page' => -1, 659 ] 660 ); 661 662 if ( empty( $attachments ) ) { 663 return; 664 } 665 666 foreach ( $attachments as $attachment ) { 667 if ( ! \ISC\Media_Type_Checker::is_image( $attachment ) ) { 668 foreach ( $isc_meta_keys as $meta_key ) { 669 delete_post_meta( $attachment->ID, $meta_key ); 670 } 671 } 672 } 673 } 765 674 } -
image-source-control-isc/trunk/includes/options.php
r3253182 r3283881 84 84 $default['standard_source'] = 'custom_text'; 85 85 $default['standard_source_text'] = ''; 86 $default['images_only'] = false; 86 87 87 88 /** -
image-source-control-isc/trunk/includes/settings/sections/plugin-options.php
r3253182 r3283881 17 17 add_settings_section( 'isc_settings_section_plugin', __( 'Plugin options', 'image-source-control-isc' ), '__return_false', 'isc_settings_page' ); 18 18 add_settings_field( 'modules', __( 'Modules', 'image-source-control-isc' ), [ $this, 'render_field_modules' ], 'isc_settings_page', 'isc_settings_section_plugin' ); 19 add_settings_field( 'images_only', __( 'Images only', 'image-source-control-isc' ), [ $this, 'render_field_images_only' ], 'isc_settings_page', 'isc_settings_section_plugin' ); 19 20 add_settings_field( 'remove_on_uninstall', __( 'Delete data on uninstall', 'image-source-control-isc' ), [ $this, 'render_field_remove_on_uninstall' ], 'isc_settings_page', 'isc_settings_section_plugin' ); 20 21 } … … 37 38 38 39 /** 40 * Render the option to restrict functionality to images only. 41 */ 42 public function render_field_images_only() { 43 $options = $this->get_options(); 44 $checked = ! empty( $options['images_only'] ); 45 require_once ISCPATH . '/admin/templates/settings/plugin/images-only.php'; 46 } 47 48 /** 39 49 * Render the option to remove all options and meta data when the plugin is deleted. 40 50 */ … … 54 64 */ 55 65 public function validate_settings( array $output, array $input ): array { 66 $output['modules'] = ( isset( $input['modules'] ) && is_array( $input['modules'] ) ) ? $input['modules'] : []; 67 $output['images_only'] = ! empty( $input['images_only'] ); 68 $output['remove_on_uninstall'] = ! empty( $input['remove_on_uninstall'] ); 56 69 57 $output['modules'] = ( isset( $input['modules'] ) && is_array( $input['modules'] ) ) ? $input['modules'] : []; 58 $output['remove_on_uninstall'] = ! empty( $input['remove_on_uninstall'] ); 70 // Cleanup meta data for non-images 71 if ( 72 ! empty( $input['images_only'] ) && 73 ! empty( $input['images_only_cleanup'] ) 74 ) { 75 \ISC_Model::remove_plugin_meta_from_non_images(); 76 } 59 77 60 78 return $output; -
image-source-control-isc/trunk/isc.php
r3256989 r3283881 2 2 /** 3 3 * Plugin Name: Image Source Control Lite 4 * Version: 3. 1.44 * Version: 3.2.0 5 5 * Plugin URI: https://imagesourcecontrol.com/ 6 6 * Description: Image Source Control saves the source of an image, lists them and warns if it is missing. … … 30 30 } 31 31 32 define( 'ISCVERSION', '3. 1.4' );32 define( 'ISCVERSION', '3.2.0' ); 33 33 define( 'ISCNAME', 'Image Source Control' ); 34 34 define( 'ISCDIR', basename( __DIR__ ) ); -
image-source-control-isc/trunk/lib/composer/autoload_classmap.php
r3253182 r3283881 24 24 'ISC\\Image_Sources\\Image_Sources' => $baseDir . '/includes/image-sources/image-sources.php', 25 25 'ISC\\Image_Sources\\Image_Sources_Admin_Scripts' => $baseDir . '/includes/image-sources/admin/scripts.php', 26 'ISC\\Image_Sources\\Post_Meta\\Image_Posts_Meta' => $baseDir . '/includes/image-sources/Post_Meta/Image_Posts_Meta.php', 27 'ISC\\Image_Sources\\Post_Meta\\Post_Images_Meta' => $baseDir . '/includes/image-sources/Post_Meta/Post_Images_Meta.php', 26 28 'ISC\\Image_Sources\\Renderer' => $baseDir . '/includes/image-sources/renderer.php', 27 29 'ISC\\Image_Sources\\Renderer\\Caption' => $baseDir . '/includes/image-sources/renderer/caption.php', … … 29 31 'ISC\\Image_Sources\\Utils' => $baseDir . '/includes/image-sources/utils.php', 30 32 'ISC\\Indexer' => $baseDir . '/includes/indexer.php', 33 'ISC\\Media_Type_Checker' => $baseDir . '/includes/media-type-checker.php', 31 34 'ISC\\Newsletter' => $baseDir . '/includes/newsletter.php', 32 35 'ISC\\Options' => $baseDir . '/includes/options.php', -
image-source-control-isc/trunk/lib/composer/autoload_static.php
r3253182 r3283881 44 44 'ISC\\Image_Sources\\Image_Sources' => __DIR__ . '/../..' . '/includes/image-sources/image-sources.php', 45 45 'ISC\\Image_Sources\\Image_Sources_Admin_Scripts' => __DIR__ . '/../..' . '/includes/image-sources/admin/scripts.php', 46 'ISC\\Image_Sources\\Post_Meta\\Image_Posts_Meta' => __DIR__ . '/../..' . '/includes/image-sources/Post_Meta/Image_Posts_Meta.php', 47 'ISC\\Image_Sources\\Post_Meta\\Post_Images_Meta' => __DIR__ . '/../..' . '/includes/image-sources/Post_Meta/Post_Images_Meta.php', 46 48 'ISC\\Image_Sources\\Renderer' => __DIR__ . '/../..' . '/includes/image-sources/renderer.php', 47 49 'ISC\\Image_Sources\\Renderer\\Caption' => __DIR__ . '/../..' . '/includes/image-sources/renderer/caption.php', … … 49 51 'ISC\\Image_Sources\\Utils' => __DIR__ . '/../..' . '/includes/image-sources/utils.php', 50 52 'ISC\\Indexer' => __DIR__ . '/../..' . '/includes/indexer.php', 53 'ISC\\Media_Type_Checker' => __DIR__ . '/../..' . '/includes/media-type-checker.php', 51 54 'ISC\\Newsletter' => __DIR__ . '/../..' . '/includes/newsletter.php', 52 55 'ISC\\Options' => __DIR__ . '/../..' . '/includes/options.php', -
image-source-control-isc/trunk/public/public.php
r3253182 r3283881 182 182 } 183 183 184 if ( ISC\Indexer::is_global_list_page( $content ) ) { 185 ISC_Log::log( 'skipped adding sources because the content contains the Global List' ); 186 return $content; 187 } 188 184 189 // return if this is not the main query or within the loop 185 190 if ( ! self::is_main_loop() ) { … … 629 634 630 635 foreach ( $attachments as $_attachment ) { 636 // skip non-images if option is selected 637 if ( ! \ISC\Media_Type_Checker::should_process_attachment( $_attachment ) ) { 638 ISC_Log::log( sprintf( 'skipped image %d because it is not an image', $_attachment->ID ) ); 639 continue; 640 } 641 631 642 $connected_atts[ $_attachment->ID ]['source'] = self::get_image_source_text_raw( $_attachment->ID ); 632 643 $connected_atts[ $_attachment->ID ]['standard'] = Standard_Source::use_standard_source( $_attachment->ID ); -
image-source-control-isc/trunk/readme.txt
r3275604 r3283881 4 4 Requires at least: 6.0 5 5 Tested up to: 6.8 6 Stable tag: 3. 1.46 Stable tag: 3.2.0 7 7 Requires PHP: 7.4 8 8 License: GPLv3 or later … … 48 48 * Warn about missing image sources 49 49 * Manage, display, and link available licenses 50 * Enable the features for any files in the media library or for images only 51 * Filter the media library list by images with or without sources 50 52 51 53 **Featured Image Caption** … … 61 63 [Check out all features of Image Source Control](https://imagesourcecontrol.com/?utm_source=wporg&utm_medium=link&utm_campaign=all-features). 62 64 65 * The Indexer looks for all images in all published content in one go 63 66 * List credits for images outside the content 64 67 * Add multiple links to the source string … … 67 70 * Show image usage in the image details and the List view of the media library 68 71 * Bulk-edit image copyright information in the media library 72 * Preview image credits in the media library 69 73 * Show the standard picture credit for all images without a selected source 70 74 * [Display IPTC copyright metadata](https://imagesourcecontrol.com/blog/iptc-copyright-information-image-caption-wordpress/) in the backend and automatically as a standard source in the frontend … … 80 84 81 85 Extended compatibility with Elementor, Avada, WP Bakery, and other page builders 82 as well as with plugins like Kadence Blocks, Kadence Related Content Carousel, and Lightbox Gallery.86 as well as with plugins like WPML, Kadence Blocks, Kadence Related Content Carousel, and Lightbox Gallery. 83 87 84 88 [See Pricing](https://imagesourcecontrol.com/pricing/?utm_source=wporg&utm_medium=link&utm_campaign=pricing). … … 151 155 1. Customizing the global list of image sources 152 156 1. Manage image usage licenses 157 1. The Indexer searches for all images in published content 153 158 154 159 == Changelog == 160 161 = 3.2.0 = 162 163 - Feature: You can use the option “Images only” to disable features for non-images in the media library, e.g., PDF files 164 - Improvement: When authors change content, ISC now looks for removed or new images at the next visit of that page in the frontend. This highly improved compatibility with page builders and dynamic content like shortcodes. 165 - Improvement: When WP_DEBUG is enabled, show a button to list the content of the internal storage on the Tools page 166 - Improvement: Removes image source output on pages with the Global List on it 167 - Improvement (Pro): Ignores image URLs in `href` attributes when looking for image sources 168 - Improvement (Pro): Clears the URL storage when the Indexer runs. This can help with issues when a site was migrated to another URL 169 - Improvement (Pro): Extends ignored options for unused images 170 - Improvement (Pro): The column with image sources forms in the Media Library list view only shows if the user has the permission to edit any image information 171 - Improvement (Pro): The forms to edit image sources in the Media Library list view only show if the user has the permission to edit information for that given image 172 - Improvement (Pro): The Indexer for Unused Images now works with posts translated by WPML 173 - Fix: Removes old index information when the last image in a post is removed 174 - Fix (Pro): Some reserved characters in URLs caused (e.g., `&`) the bulk edit fields for images sources in the media library to be cut off 175 - Dev: Extracts post meta handling (`isc_image_posts`, `isc_post_images`) into dedicated classes. 176 - Dev (Pro): Disable image source form fields in the Media Library list view when submitting the filter form to prevent broken URLs. This is related to a compatibility issue caused by a third-party setup 177 - Dev (Pro): The Indexer now works in batches to prevent timeouts on large sites when Query Monitor is installed 178 - Dev (Pro): Pages with the Global List shortcode are now ignored by the Indexer. 179 - Dev: Adds cleanup routines for meta data for deleted and trashed posts. 180 - Dev: Replace some direct DB calls with WP functions 181 - Updates German translation 155 182 156 183 = 3.1.4 = -
image-source-control-isc/trunk/uninstall.php
r3253182 r3283881 10 10 11 11 // delete post meta fields 12 $wpdb->delete( $wpdb->postmeta, array( 'meta_key' => 'isc_post_images' ), array( '%s' ) ); 13 $wpdb->delete( $wpdb->postmeta, array( 'meta_key' => 'isc_image_posts' ), array( '%s' ) ); 14 $wpdb->delete( $wpdb->postmeta, array( 'meta_key' => 'isc_image_source' ), array( '%s' ) ); 15 $wpdb->delete( $wpdb->postmeta, array( 'meta_key' => 'isc_image_source_own' ), array( '%s' ) ); 16 $wpdb->delete( $wpdb->postmeta, array( 'meta_key' => 'isc_image_source_url' ), array( '%s' ) ); 17 $wpdb->delete( $wpdb->postmeta, array( 'meta_key' => 'isc_possible_usages' ), array( '%s' ) ); 18 $wpdb->delete( $wpdb->postmeta, array( 'meta_key' => 'isc_possible_usages_last_check' ), array( '%s' ) ); 12 delete_post_meta_by_key( 'isc_post_images' ); 13 delete_post_meta_by_key( 'isc_image_posts' ); 14 delete_post_meta_by_key( 'isc_image_source' ); 15 delete_post_meta_by_key( 'isc_image_source_own' ); 16 delete_post_meta_by_key( 'isc_image_source_url' ); 17 delete_post_meta_by_key( 'isc_possible_usages' ); 18 delete_post_meta_by_key( 'isc_possible_usages_last_check' ); 19 delete_post_meta_by_key( 'isc_post_images_before_update' ); 19 20 20 21 // delete main plugin options
Note: See TracChangeset
for help on using the changeset viewer.