'featured', 'featured_in' => 'featured_in', 'inserted' => 'inserted', 'inserted_in' => 'inserted_in', 'used' => 'used', 'used_in' => 'used_in', 'used_first_feature' => true, 'used_first_insert' => true, ); /** * WordPress version test for $wpdb->esc_like() Vs esc_sql() * * @since 1.00 * * @var boolean */ private static $wp_4dot0_plus = true; /** * Initialization function, similar to __construct() * * @since 1.00 * * @return void */ public static function initialize() { /* * The filter is only needed in the Admin area */ if ( ! is_admin() ) { return; } self::$wp_4dot0_plus = version_compare( get_bloginfo('version'), '4.0', '>=' ); /* * Defined in media-library-assistant/includes/class-mla-media-modal.php * function mla_media_view_settings_filter */ add_filter( 'mla_media_modal_initial_filters', 'MLADynamicReferencesExample::mla_media_modal_initial_filters', 10, 2 ); add_filter( 'mla_media_modal_settings', 'MLADynamicReferencesExample::mla_media_modal_settings', 10, 2 ); /* * Defined in wp-includes/post.php function wp_insert_post */ add_action( 'post_updated', 'MLADynamicReferencesExample::post_updated', 10, 3 ); add_action( 'wp_insert_post', 'MLADynamicReferencesExample::wp_insert_post', 10, 3 ); /* * Defined in wp-includes/meta.php */ add_action( 'added_post_meta', 'MLADynamicReferencesExample::added_post_meta', 10, 4 ); add_action( 'update_post_meta', 'MLADynamicReferencesExample::update_post_meta', 10, 4 ); add_action( 'updated_post_meta', 'MLADynamicReferencesExample::updated_post_meta', 10, 4 ); add_action( 'delete_post_meta', 'MLADynamicReferencesExample::delete_post_meta', 10, 4 ); add_action( 'deleted_post_meta', 'MLADynamicReferencesExample::deleted_post_meta', 10, 4 ); } /** * Add the "Available" view to the Set Featured Image dropdown control * * @since 1.01 * * @param array $initial_values Settings passed to the Media Manager Modal Window scripts. * @param WP_Post $post Post object in which the MMMW is embeded. */ public static function mla_media_modal_initial_filters( $initial_values, $post ) { //error_log( __LINE__ . " mla_media_modal_settings post = " . var_export( $post, true ), 0 ); if ( ! empty( self::$field_names['used'] ) ) { if ( self::$field_names['used_first_feature'] && isset( $initial_values['filterUploaded'] ) ) { $initial_values['filterUploaded'] = 'custom:' . self::$field_names['used'] . ',null'; } if ( self::$field_names['used_first_insert'] && isset( $initial_values['filterMime'] ) ) { $initial_values['filterMime'] = 'custom:' . self::$field_names['used'] . ',null'; } } //error_log( __LINE__ . " mla_media_modal_settings initial_values = " . var_export( $initial_values, true ), 0 ); return $initial_values; } /** * Add the "Available" view to the Set Featured Image dropdown control * * @since 1.01 * * @param array $settings Settings passed to the Media Manager Modal Window scripts. * @param WP_Post $post Post object in which the MMMW is embeded. */ public static function mla_media_modal_settings( $settings, $post ) { //error_log( __LINE__ . " mla_media_modal_settings settings = " . var_export( $settings, true ), 0 ); //error_log( __LINE__ . " mla_media_modal_settings post = " . var_export( $post, true ), 0 ); if ( ! empty( self::$field_names['used'] ) ) { if ( isset( $settings['mla_settings'] ) && isset( $settings['mla_settings']['uploadMimeTypes'] ) ) { $settings['mla_settings']['uploadMimeTypes']['custom:' . self::$field_names['used'] . ',null'] = 'Not Used'; $settings['mla_settings']['uploadMimeTypes']['custom:' . self::$field_names['used'] . '=*'] = 'Already Used'; } } //error_log( __LINE__ . " mla_media_modal_settings settings[mla_settings][uploadMimeTypes] = " . var_export( $settings['mla_settings']['uploadMimeTypes'], true ), 0 ); return $settings; } /** * Analyze before and after content when an existing item is updated * * @since 1.00 * * @param int $post_ID Post ID. * @param WP_Post $post_after Post object following the update. * @param WP_Post $post_before Post object before the update. */ public static function post_updated( $post_ID, $post_after, $post_before ) { //error_log( __LINE__ . " post_updated( {$post_ID} ) post_after = " . var_export( $post_after, true ), 0 ); if ( 'trash' == $post_after->post_status ) { $after = array(); } else { $after = self::_attachments_in( $post_after->post_content ); } //error_log( __LINE__ . " post_updated( {$post_ID} ) post_before = " . var_export( $post_before, true ), 0 ); if ( 'trash' == $post_before->post_status ) { $attachments_before = array(); } else { $attachments_before = self::_attachments_in( $post_before->post_content ); } // Eliminate unchanged attachments $attachments_after = array(); foreach( $after as $ID ) { if ( isset( $attachments_before[ $ID ] ) ) { unset( $attachments_before[ $ID ] ); } else { $attachments_after[ $ID ] = $ID; } } self::_update_inserted_in( $attachments_after ); self::_update_inserted_in( $attachments_before ); if ( 'auto-draft' == $post_before->post_status ) { if ( $attachment = get_post_meta( $post_ID, '_thumbnail_id', true ) ) { self::_update_featured_in( $attachment ); } } } /** * Analyze post content when a new item is inserted i.e., $update == false * * @since 1.00 * * @param int $post_ID Post ID. * @param WP_Post $post Post object following the update. * @param WP_Post $update true if updating, false if inserting. */ public static function wp_insert_post( $post_ID, $post, $update ) { //error_log( __LINE__ . " wp_insert_post( {$post_ID}, " . var_export( $update, true ) . " ) post = " . var_export( $post, true ), 0 ); if ( $update || in_array( $post->post_status, array( 'inherit', 'auto-draft' ) ) ) { return; } $attachments = self::_attachments_in( $post->post_content ); self::_update_inserted_in( $attachments ); } /** * Fires immediately after meta of a specific type is added. * * @since 1.00 * * @param int $mid The meta ID after successful update. * @param int $object_id Object ID. * @param string $meta_key Meta key. * @param mixed $meta_value Meta value. */ public static function added_post_meta( $mid, $object_id, $meta_key, $_meta_value ) { //error_log( __LINE__ . " added_post_meta( {$object_id}, {$meta_key} ) _meta_value = " . var_export( $_meta_value, true ), 0 ); if ( '_thumbnail_id' == $meta_key ) { self::_update_featured_in( $_meta_value ); } } /** * Fires immediately before updating metadata of a specific type. * * @since 1.00 * * @param int $meta_id ID of the metadata entry to update. * @param int $object_id Object ID. * @param string $meta_key Meta key. * @param mixed $meta_value New meta value. */ public static function update_post_meta( $meta_id, $object_id, $meta_key, $_meta_value ) { if ( '_thumbnail_id' == $meta_key ) { // $_meta_value contains the NEW value. Must get the old value ourselves. self::$old_value = get_post_meta( $object_id, '_thumbnail_id', true ); //error_log( __LINE__ . " update_post_meta( {$object_id}, {$meta_key} ) old_value = " . var_export( self::$old_value, true ), 0 ); } } /** * Featured Image value before update * * @since 1.00 * * @var integer */ private static $old_value = 0; /** * Fires immediately after updating metadata of a specific type. * * @since 1.00 * * @param int $meta_id ID of updated metadata entry. * @param int $object_id Object ID. * @param string $meta_key Meta key. * @param mixed $meta_value Meta value. */ public static function updated_post_meta( $meta_id, $object_id, $meta_key, $_meta_value ) { //error_log( __LINE__ . " updated_post_meta( {$object_id}, {$meta_key} ) _meta_value = " . var_export( $_meta_value, true ), 0 ); if ( '_thumbnail_id' == $meta_key ) { if ( self::$old_value ) { self::_update_featured_in( self::$old_value ); self::$old_value = 0; } self::_update_featured_in( $_meta_value ); } } /** * Fires immediately before deleting metadata of a specific type. * * @since 1.00 * * @param array $meta_ids An array of deleted metadata entry IDs. * @param int $object_id Object ID. * @param string $meta_key Meta key. * @param mixed $meta_value Meta value. */ public static function delete_post_meta( $meta_ids, $object_id, $meta_key, $_meta_value ){ if ( '_thumbnail_id' == $meta_key ) { // $_meta_value contains nothing. Must get the old value ourselves. self::$old_value = get_post_meta( $object_id, '_thumbnail_id', true ); //error_log( __LINE__ . " delete_post_meta( {$object_id}, {$meta_key} ) old_value = " . var_export( self::$old_value, true ), 0 ); } } /** * Fires immediately after deleting metadata of a specific type. * * @since 1.00 * * @param array $meta_ids An array of deleted metadata entry IDs. * @param int $object_id Object ID. * @param string $meta_key Meta key. * @param mixed $meta_value Meta value. */ public static function deleted_post_meta( $meta_ids, $object_id, $meta_key, $_meta_value ){ //error_log( __LINE__ . " deleted_post_meta( {$object_id}, {$meta_key} ) _meta_value = " . var_export( $_meta_value, true ), 0 ); if ( '_thumbnail_id' == $meta_key && self::$old_value ) { self::_update_featured_in( self::$old_value ); self::$old_value = 0; } } /** * Update "Used/Used in" data for one attachment * * Called from _update_inserted_in and _update_featured_in. * * @since 1.00 * * @param array $attachments attachment IDs ( ID => ID ) */ private static function _update_used_in( $ID, $inserts = NULL, $features = NULL ) { //error_log( __LINE__ . " _update_used_in( {$ID} ) inserts = " . var_export( $inserts, true ), 0 ); //error_log( __LINE__ . " _update_used_in( {$ID} ) features = " . var_export( $features, true ), 0 ); if ( empty( self::$field_names['used_in'] ) && empty( self::$field_names['used'] ) ) { return; } if ( empty( $inserts ) ) { $inserts = self::_inserted_in( $ID ); } if ( empty( $features ) ) { $features = self::_featured_in( $ID ); } $results = array(); $titles = array(); foreach ( $features as $post_id => $value ) { if ( 'auto-draft' === $value->post_status ) { continue; } $results[] = sprintf( '%1$s (%2$s %3$d)', $value->post_title, $value->post_type, $post_id ); $titles[] = $value->post_title; } $final_results = implode( ',', $results ); $final_titles = implode( ',', $titles ); $results = array(); $titles = array(); // $inserts is indexed on file name; need a second level foreach ( $inserts as $files ) { foreach ( $files as $value ) { $results[] = sprintf( '%1$s (%2$s %3$d)', $value->post_title, $value->post_type, $value->ID ); $titles[] = $value->post_title; } } $final_results = trim( $final_results . implode( ',', $results ) ); $final_titles = trim( $final_titles . implode( ',', $titles ) ); if ( ! empty( self::$field_names['used_in'] ) ) { if ( empty( $final_results ) ) { delete_metadata( 'post', $ID, self::$field_names['used_in'] ); } else { update_metadata( 'post', $ID, self::$field_names['used_in'], $final_results ); } } if ( ! empty( self::$field_names['used'] ) ) { if ( empty( $final_titles ) ) { delete_metadata( 'post', $ID, self::$field_names['used'] ); } else { update_metadata( 'post', $ID, self::$field_names['used'], $final_titles ); } } } /** * Update "Inserted in" data for one or more attachments * * @since 1.00 * * @param array $attachments attachment IDs ( ID => ID ) */ private static function _update_inserted_in( $attachments ) { //error_log( __LINE__ . " _update_inserted_in attachments = " . var_export( $attachments, true ), 0 ); if ( empty( $attachments ) ) { return; } elseif ( is_numeric( $attachments ) ) { $attachments = absint( $attachments ); $attachments = array( $attachments => $attachments ); } foreach ( $attachments as $ID ){ $inserts = self::_inserted_in( $ID ); $results = array(); $titles = array(); // $inserts is indexed on file name; need a second level foreach ( $inserts as $files ) { foreach ( $files as $value ) { $results[] = sprintf( '%1$s (%2$s %3$d)', $value->post_title, $value->post_type, $value->ID ); $titles[] = $value->post_title; } } if ( ! empty( self::$field_names['inserted_in'] ) ) { if ( empty( $results ) ) { delete_metadata( 'post', $ID, self::$field_names['inserted_in'] ); } else { update_metadata( 'post', $ID, self::$field_names['inserted_in'], implode( ',', $results ) ); } } if ( ! empty( self::$field_names['inserted'] ) ) { if ( empty( $titles ) ) { delete_metadata( 'post', $ID, self::$field_names['inserted'] ); } else { update_metadata( 'post', $ID, self::$field_names['inserted'], implode( ',', $titles ) ); } } self::_update_used_in( $ID, $inserts, NULL ); } } /** * Update "Featured in" data for one or more attachments * * @since 1.00 * * @param array $attachments attachment IDs ( ID => ID ) */ private static function _update_featured_in( $attachments ) { //error_log( __LINE__ . " _update_featured_in attachments = " . var_export( $attachments, true ), 0 ); if ( empty( $attachments ) ) { return; } elseif ( is_numeric( $attachments ) ) { $attachments = absint( $attachments ); $attachments = array( $attachments => $attachments ); } foreach ( $attachments as $ID ){ $features = self::_featured_in( $ID ); $results = array(); $titles = array(); foreach ( $features as $post_id => $value ) { if ( 'auto-draft' === $value->post_status ) { continue; } $results[] = sprintf( '%1$s (%2$s %3$d)', $value->post_title, $value->post_type, $post_id ); $titles[] = $value->post_title; } if ( ! empty( self::$field_names['featured_in'] ) ) { if ( empty( $results ) ) { delete_metadata( 'post', $ID, self::$field_names['featured_in'] ); } else { update_metadata( 'post', $ID, self::$field_names['featured_in'], implode( ',', $results ) ); } } if ( ! empty( self::$field_names['featured'] ) ) { if ( empty( $titles ) ) { delete_metadata( 'post', $ID, self::$field_names['featured'] ); } else { update_metadata( 'post', $ID, self::$field_names['featured'], implode( ',', $titles ) ); } } self::_update_used_in( $ID, NULL, $features ); } } /** * Find the attachments inserted in post_content * * @since 1.00 * * @param string $post_content Post/Page contents. * * @return array Attachment IDs, indexed by ID ( ID => ID ). */ private static function _attachments_in( $post_content ){ $inserts = array(); $match_count = preg_match_all( '/\/', $post_content, $matches ); if ( ( $match_count == false ) || ( $match_count == 0 ) ) { return $inserts; } //error_log( __LINE__ . " _attachments_in( {$match_count} ) matches = " . var_export( $matches, true ), 0 ); foreach ( $matches[1] as $match ) { $ID = absint( $match ); $inserts[ $ID ] = $ID; } //error_log( __LINE__ . " _attachments_in( {$match_count} ) inserts = " . var_export( $inserts, true ), 0 ); return $inserts; } /** * Find the "Featured in" information for an attachment * * @since 1.00 * * @param int $object_id Attachment ID. * * @return array Featured in information object ( 'ID' =>, 'post_type' =>, 'post_status' =>, 'post_title' => ). */ private static function _featured_in( $object_id ){ global $wpdb; $results = $wpdb->get_results( " SELECT p.ID, p.post_type, p.post_status, p.post_title FROM {$wpdb->postmeta} AS m INNER JOIN {$wpdb->posts} AS p ON m.post_id = p.ID WHERE ( m.meta_key = '_thumbnail_id' ) AND ( m.meta_value = {$object_id} ) AND (post_type <> 'revision') " ); $features = array(); foreach ( $results as $result ) { $features[ $result->ID ] = $result; } //error_log( __LINE__ . " _featured_in( {$object_id} ) features = " . var_export( $features, true ), 0 ); return $features; } /** * Find the "Inserted in" information for an attachment * * @since 1.00 * * @param int $object_id Attachment ID. * * @return array Inserted in information array( file_name => array( object ( 'ID' =>, 'post_type' =>, 'post_status' =>, 'post_title' =>, ) ) ). */ private static function _inserted_in( $object_id ){ global $wpdb; $references = array(); $references['base_file'] = get_post_meta( $object_id, '_wp_attached_file', true ); $pathinfo = pathinfo($references['base_file']); $references['file'] = $pathinfo['basename']; if ( ( ! isset( $pathinfo['dirname'] ) ) || '.' == $pathinfo['dirname'] ) { $references['path'] = '/'; } else { $references['path'] = $pathinfo['dirname'] . '/'; } $attachment_metadata = get_post_meta( $object_id, '_wp_attachment_metadata', true ); $sizes = isset( $attachment_metadata['sizes'] ) ? $attachment_metadata['sizes'] : NULL; if ( is_array( $sizes ) ) { // Using the name as the array key ensures each name is added only once foreach ( $sizes as $size => $size_info ) { $size_info['size'] = $size; $references['files'][ $references['path'] . $size_info['file'] ] = $size_info; } } $base_type = wp_check_filetype( $references['file'] ); $base_reference = array( 'file' => $references['file'], 'width' => isset( $attachment_metadata['width'] ) ? $attachment_metadata['width'] : 0, 'height' => isset( $attachment_metadata['height'] ) ? $attachment_metadata['height'] : 0, 'mime_type' => isset( $base_type['type'] ) ? $base_type['type'] : 'unknown', 'size' => 'full', ); $references['files'][ $references['base_file'] ] = $base_reference; $query_parameters = array(); $query = array(); $query[] = "SELECT ID, post_type, post_status, post_title, CONVERT(`post_content` USING utf8 ) AS POST_CONTENT FROM {$wpdb->posts} WHERE (post_type <> 'revision') AND ( %s=%s"; $query_parameters[] = '1'; // for empty file name array $query_parameters[] = '0'; // for empty file name array foreach ( $references['files'] as $file => $file_data ) { if ( empty( $file ) ) { continue; } $query[] = 'OR ( POST_CONTENT LIKE %s)'; if ( self::$wp_4dot0_plus ) { $query_parameters[] = '%' . $wpdb->esc_like( $file ) . '%'; } else { $query_parameters[] = '%' . like_escape( $file ) . '%'; } } $query[] = ')'; $query = join(' ', $query); $inserts = $wpdb->get_results( $wpdb->prepare( $query, $query_parameters ) ); if ( ! empty( $inserts ) ) { $references['inserts'][ $pathinfo['filename'] ] = $inserts; foreach ( $inserts as $index => $insert ) { unset( $references['inserts'][ $pathinfo['filename'] ][ $index ]->POST_CONTENT ); } // foreach $insert } else { $references['inserts'] = array(); } //error_log( __LINE__ . " _inserted_in( {$object_id} ) references = " . var_export( $references, true ), 0 ); return $references['inserts']; } } // Class MLADynamicReferencesExample /* * Install the filter at an early opportunity */ add_action('init', 'MLADynamicReferencesExample::initialize'); ?>