0

I am working on a WordPress plugin feature that checks for usage of image media before deletion – specifically within Advanced Custom Fields image fields in posts of a custom post type, but this part is not the issue.

I can use a WP_Query/meta_query to successfully check for this scenario, but the problem is that I would like to print the results of my WP_Query to the wp-admin/upload.php page so that administrators can understand if the attachment was deleted successfully, or if not, why. I am not sure how to make this possible.

Here is example code I am testing with now. Currently I am writing the results of my check to wp-content/debug.log. It would be better if administrators could see that in wp-admin.

// Prevent deletion of attached media
function check_acf_image_field_usage( $attachment_id ) {

    // Relevant meta keys are the image field names
    $image_field_names = array(
        'acf_image_field_name_example_1',
        'acf_image_field_name_example_2',
        'acf_image_field_name_example_3',
    );

    // Create a meta query from $image_field_names starting with 'relation' => 'OR'
    $image_fields_meta_query = array('relation' => 'OR');
    for ($i = 0; $i < count($image_field_names); $i++)  {
        $newArray = array(
            'key' => $image_field_names[$i],
            'value' => $attachment_id,
            'compare' => '=',
        );
        array_push($image_fields_meta_query, $newArray);
    }

    $args = array(
        'post_type'  => 'custom-post-type',
        'meta_query' => $image_fields_meta_query
    );
    $query = new WP_Query($args);

    // If 0 posts were found in the meta_query
    if (count($query->posts) === 0) {
        // CHANGE THIS write_log FUNCTION INTO SOMETHING THAT WILL OUTPUT TO wp-admin?
        write_log("The attachment that was requested to be deleted is included in " . count($query->posts) . " posts, so it will be deleted.");

        // Proceed to delete the attachment.
        return;
    
    // If 1 or more posts were found in the meta_query
    } else if (count($query->posts) > 0) {
        // CHANGE THESE write_log FUNCTIONS INTO SOMETHING THAT WILL OUTPUT TO wp-admin?
        write_log("The attachment that was requested to be deleted is included in " . count($query->posts) . " posts.");
        write_log('It is currently attached as an image to:');

        // Loop through meta query results to log each discovered post containing the attachment
        for ($i = 0; $i < count($query->posts); $i++)  {
            write_log($query->posts[$i]->ID . ' - ' . $query->posts[$i]->post_title);
        }

        // Stop WordPress execution so that the attachment is not deleted.
        $message = 'Sorry, this attachment cannot be deleted.'; 
        wp_die($message);
    }
}
add_action( 'delete_attachment', 'check_acf_image_field_usage' );

// Generic function for writing data to wp-content/debug.log file
function write_log( $log ) {

    if ( true === WP_DEBUG ) {

        if ( is_array($log) || is_object($log) ) {
            error_log( print_r($log, true) );
        } else {
            error_log( $log );
        }
        
    }

}

Here are the requirements:

  • Print results of a WP_Query to a wp-admin page (upload.php) that happens within the ‘delete_attachment’ hook.
  • All that matters to me is that administrators see the results of the query, I don’t care much about how or where it appears.
  • In other words, the content for the admin notification depends on the WP_Query results, which runs when an admin tries to delete an attachment.
  • What is the best way to print information from a WP_Query to a wp-admin page at the time the hook is called?
  • Simply using an admin notice doesn’t seem to be a solution because that shows the same data every time the page is loaded, and the WP_Query does not run when the page loads.

Additionally, I am wondering is there a better method than using wp_die() to stop the attachment from being deleted?

Thanks for your help!

1 Answer 1

0

Here is a workaround that I decided to use thanks to a suggestion on WordPress.org forums. I added a new column to the media library list view that displays the results of the WP_Query for each media attachment.

This lets wp-admin users see if a post is attached to an ACF image field or not. I am still preventing attachment deletion using similar code as in the original question, but instead of giving wp-admin users a notification or modal that the attachment can be deleted on triggering the 'delete_attachment' hook, users can see in the list view if the media is attached to any ACF image field -> which explains if it is able to be deleted or not.

In the code below, $query represents the same data as in my original question (see above $query = new WP_Query($args)), just refactored that bit into a new function wp_query_metaquery_check_acf_image_field_usage( $attachment_id ).

add_filter('manage_media_columns', function($columns) {
    // Remove the default 'comments' column
    unset($columns['comments']);
    
    // Add the custom column 'ACF Image field usage' under column key 'acf_image_field_usage'
    return array_merge($columns, ['acf_image_field_usage' => __('ACF Image field usage', 'textdomain')]);
});

 
add_action('manage_media_custom_column', function($column_key, $attachment_id) {

    if ($column_key == 'acf_image_field_usage') {

        $query = wp_query_metaquery_check_acf_image_field_usage( $attachment_id );

        // If 0 posts were found in the meta_query
        if (count($query->posts) === 0) {
            echo '<span style="color:inherit;">'; _e("None", 'textdomain');
            echo '</span>';
            
        // If 1 or more posts were found in the meta_query
        } else if (count($query->posts) > 0) {
            // Loop through meta query results to log each discovered post containing the attachment
            for ($i = 0; $i < count($query->posts); $i++)  {
                echo '<span style="color:inherit;">'; _e($query->posts[$i]->ID . ' - ' . $query->posts[$i]->post_title, 'textdomain'); 
                echo '</span>';
                echo '<br>';
            }
        }

    }

}, 10, 2);

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.