Skip to content

Commit

Permalink
Add relationships between posts and attachments/featured images (Clas…
Browse files Browse the repository at this point in the history
…sicPress#1446)

* Update post.php to create a relationship between a post and any attachment it uses.

* Update media.php to add functions to create relationship between a post and any attachment it uses

* Update post.php to create and delete relationships between posts and thumbnails

* Update class-wp-media-list-table.php to add a new column to the media list view page

* Update media.php to meet coding standards

* Update class-wp-media-list-table.php to meet coding standards

* Update class-wp-media-list-table.php to meet coding standards

* Update post.php to fix trailing whitespaces

* Update media.php to add a check for an empty array

* Update class-wp-media-list-table.php to have separate columns for featured images

* Update class-wp-media-list-table.php to remove unnecessary dates

* Bump cp_db_version

---------

Co-authored-by: xxsimoxx <[email protected]>
  • Loading branch information
KTS915 and xxsimoxx authored Jul 1, 2024
1 parent 0454d62 commit d9c6035
Show file tree
Hide file tree
Showing 4 changed files with 317 additions and 9 deletions.
103 changes: 96 additions & 7 deletions src/wp-admin/includes/class-wp-media-list-table.php
Original file line number Diff line number Diff line change
Expand Up @@ -182,16 +182,17 @@ protected function get_bulk_actions() {
if ( MEDIA_TRASH ) {
if ( $this->is_trash ) {
$actions['untrash'] = __( 'Restore' );
$actions['delete'] = __( 'Delete permanently' );
$actions['delete'] = __( 'Delete permanently' );
} else {
$actions['trash'] = __( 'Move to Trash' );
}
} else {
$actions['edit'] = __( 'Edit' );
$actions['delete'] = __( 'Delete permanently' );
}

if ( $this->detached ) {
$actions['attach'] = __( 'Attach' );
$actions['attach'] = __( 'Attach to post' );
}

return $actions;
Expand Down Expand Up @@ -356,6 +357,9 @@ public function get_columns() {
}

/* translators: Column name. */
$posts_columns['thumbnail'] = _x( 'Featured Image', 'column name' );
$posts_columns['used_in'] = _x( 'Used In', 'column name' );

if ( ! $this->detached ) {
$posts_columns['parent'] = _x( 'Uploaded to', 'column name' );

Expand Down Expand Up @@ -389,11 +393,13 @@ public function get_columns() {
*/
protected function get_sortable_columns() {
return array(
'title' => 'title',
'author' => 'author',
'parent' => 'parent',
'comments' => 'comment_count',
'date' => array( 'date', true ),
'title' => 'title',
'author' => 'author',
'parent' => 'parent',
'thumbnail' => 'thumbnail',
'used_in' => 'used_in',
'comments' => 'comment_count',
'date' => array( 'date', true ),
);
}

Expand Down Expand Up @@ -552,6 +558,89 @@ public function column_date( $post ) {
echo apply_filters( 'media_date_column_time', $h_time, $post, 'date' );
}

/**
* Handles the thumbnail column output.
*
* @since CP-2.2.0
*
* @param WP_Post $post The current WP_Post object.
*/
public function column_thumbnail( $post ) {
$user_can_edit = current_user_can( 'edit_post', $post->ID );

// Get all post types except attachments and revisions.
$parent_types = get_post_types();
unset( $parent_types['attachment'] );
unset( $parent_types['revision'] );

// Set output variable.
$output = '';

foreach ( $parent_types as $parent_type ) {

// Get all posts where this attachment is the featured image.
$relationship_ids = cp_get_object_relationship_ids( $post->ID, 'thumbnail', $parent_type );

if ( ! empty( $relationship_ids ) ) {
foreach ( $relationship_ids as $relationship_id ) {
if ( absint( $relationship_id ) !== 0 ) {
$ancestor = get_post( $relationship_id );
$ancestor_type_obj = get_post_type_object( $ancestor->post_type );
$title = _draft_or_post_title( $relationship_id );

if ( $ancestor_type_obj->show_ui && current_user_can( 'edit_post', $relationship_id ) ) {
$output .= '<strong><a href="' . esc_url( get_edit_post_link( $relationship_id ) ) . '">' . esc_html( $title ) . '</a></strong><br>';
} else {
$output .= $title . '<br>';
}
}
}
}
}
return $output;
}

/**
* Handles the used-in column output.
*
* @since CP-2.2.0
*
* @param WP_Post $post The current WP_Post object.
*/
public function column_used_in( $post ) {
$user_can_edit = current_user_can( 'edit_post', $post->ID );

// Get all post types except attachments and revisions.
$parent_types = get_post_types();
unset( $parent_types['attachment'] );
unset( $parent_types['revision'] );

// Set output variable.
$output = '';

foreach ( $parent_types as $parent_type ) {

// Get all posts where this attachment is used in the content.
$parent_ids = cp_get_object_relationship_ids( $post->ID, 'attachment', $parent_type );

if ( ! empty( $parent_ids ) ) {
foreach ( $parent_ids as $parent_id ) {
if ( absint( $parent_id ) !== 0 ) {
$parent_type_obj = get_post_type_object( $parent_type );
$title = _draft_or_post_title( $parent_id );

if ( $parent_type_obj->show_ui && current_user_can( 'edit_post', $parent_id ) ) {
$output .= '<strong><a href="' . esc_url( get_edit_post_link( $parent_id ) ) . '">' . esc_html( $title ) . '</a></strong><br>';
} else {
$output .= $title . '<br>';
}
}
}
}
}
return $output;
}

/**
* Handles the parent column output.
*
Expand Down
161 changes: 160 additions & 1 deletion src/wp-includes/media.php
Original file line number Diff line number Diff line change
Expand Up @@ -5059,6 +5059,165 @@ function attachment_url_to_postid( $url ) {
return (int) apply_filters( 'attachment_url_to_postid', $post_id, $url );
}

/**
* Gets an attachment ID from its URL.
*
* Based on https://stackoverflow.com/a/50335619
*
* @since CP-2.2.0
*
* @param string $url URL of media file.
*
* @return int $attachment_id on success, 0 on failure.
*/
function cp_get_attachment_id_from_url( $url ) {

$attachment_id = 0;
$dir = wp_upload_dir();

if ( 0 === strpos( $url, $dir['baseurl'] . '/' ) ) { // Is URL in uploads directory?
$file = basename( $url );

$args = array(
'post_type' => 'attachment',
'post_status' => 'inherit',
'fields' => 'ids',
'meta_query' => array(
array(
'value' => $file,
'compare' => 'LIKE',
'key' => '_wp_attachment_metadata',
),
),
);
$post_ids = get_posts( $args );

if ( ! empty( $post_ids ) ) {
foreach ( $post_ids as $post_id ) {
$meta = wp_get_attachment_metadata( $post_id );

$original_file = basename( $meta['file'] );
$cropped_image_files = wp_list_pluck( $meta['sizes'], 'file' );

if ( $original_file === $file || in_array( $file, $cropped_image_files ) ) {
$attachment_id = $post_id;
break;
}
}
}
}
return $attachment_id;
}

/**
* Creates a relationship between a post, page, or custom post and an attachment.
*
* @since CP-2.2.0
*
* @param int $post_id Post ID.
* @param WP_Post $post Post object.
* @param bool $update Whether this is an existing post being updated.
*/
function cp_create_post_attachment_relationship( $post_id, $post, $update ) {

// Don't run for updates because we have another function for that.
if ( $update ) {
return;
}

// Create empty array of attachment IDs.
$attachment_ids = array();

// Get all hyperlinks included in a post.
$link_strings = wp_extract_urls( $post->post_content );

// Get the attachment ID (if it exists) for each URL.
if ( ! empty( $link_strings ) ) {
foreach ( $link_strings as $link_string ) {
$attachment_id = cp_get_attachment_id_from_url( $link_string );

// Filter out all hyperlinks that do not point to the uploads folder.
if ( absint( $attachment_id ) !== 0 ) {
$attachment_ids[] = $attachment_id;
}
}
}

// Create a relationship between the post and the attachment.
if ( ! empty( $attachment_ids ) ) {
foreach ( $attachment_ids as $attachment_id ) {
cp_add_object_relationship( $attachment_id, 'attachment', $post->post_type, $post_id );
}
}
}

/**
* Updates the relationship between a post, page, or custom post and an attachment.
*
* @since CP-2.2.0
*
* @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.
* @param string $post_type Post type.
*/
function cp_update_post_attachment_relationship( $post_id, $post_after, $post_before, $post_type ) {

// Create empty array of attachment IDs after the post was updated.
$new_attachment_ids = array();

// Get all hyperlinks included in a post.
$link_strings = wp_extract_urls( $post_after->post_content );

// Get the attachment ID (if it exists) for each URL.
if ( ! empty( $link_strings ) ) {
foreach ( $link_strings as $link_string ) {
$new_attachment_id = cp_get_attachment_id_from_url( $link_string );

// Filter out all hyperlinks that do not point to the uploads folder.
if ( absint( $new_attachment_id ) !== 0 ) {
$new_attachment_ids[] = $new_attachment_id;
}
}
}

// Update a relationship between the post and the attachment.
if ( ! empty( $new_attachment_ids ) ) {
foreach ( $new_attachment_ids as $new_attachment_id ) {
cp_add_object_relationship( $new_attachment_id, 'attachment', $post_type, $post_id );
}
}

// Create empty array of attachment IDs before the post was updated.
$old_attachment_ids = array();

// Get previous hyperlinks included in the post before it was updated.
$old_link_strings = wp_extract_urls( $post_before->post_content );

// Get the attachment ID (if it exists) for each URL.
if ( ! empty( $old_link_strings ) ) {
foreach ( $old_link_strings as $old_link_string ) {
$old_attachment_id = cp_get_attachment_id_from_url( $old_link_string );

// Filter out all hyperlinks that do not point to the uploads folder.
if ( absint( $old_attachment_id ) !== 0 ) {
$old_attachment_ids[] = $old_attachment_id;
}
}
}

// Identify the hyperlinks from the old array that are not present in the updated array.
$removed_attachment_ids = array_diff( $old_attachment_ids, $new_attachment_ids );

// Remove the relationship between the post and the attachments that are no longer used in it.
if ( ! empty( $removed_attachment_ids ) ) {
foreach ( $removed_attachment_ids as $removed_attachment_id ) {
cp_delete_object_relationship( $removed_attachment_id, 'attachment', $post_type, $post_id );
}
}
}

/**
* Returns the URLs for CSS files used in an iframe-sandbox'd TinyMCE media view.
*
Expand Down Expand Up @@ -5197,7 +5356,7 @@ function wp_show_heic_upload_error( $plupload_settings ) {
* @param array $image_info Optional. Extended image information (passed by reference).
* @return array|false Array of image information or false on failure.
*/
function wp_getimagesize( $filename, ?array &$image_info = null ) {
function wp_getimagesize( $filename, array &$image_info = null ) {
// Don't silence errors when in debug mode, unless running unit tests.
if ( defined( 'WP_DEBUG' ) && WP_DEBUG
&& ! defined( 'WP_RUN_CORE_TESTS' )
Expand Down
Loading

0 comments on commit d9c6035

Please sign in to comment.