Attachment page per category

Attachments does not have categories, so a simple in_category() or has_category() check will not work. What we will need to do to solve is this issue is the following

  • Get the current attachment object. We will make use of get_queried_object() which will hold the current post object of the attachment being viewed

  • Determine the post parent of the current attachment. This is easy, from get_queried_object() we will make use of the post_parent property which stores the ID of the post the attachment belongs to

  • We will then use has_category() to determine if the attachment’s parent has the desired category

  • All of this info will be used inside attachment_template where we will set a specific template if an attachment parent is in the required category

You can do the following: (NOTE: The following code is untested and requires at least PHP5.4)

add_filter( 'attachment_template', function ( $template )
{
    // Get the current attachment object
    $attachment = get_queried_object();

    // Check if current attachment's parent is attached to our desired category or not
    if ( 
         !has_category( // If our parent does not have this category, return 
            1, // Category id, or name or slug, change as needed
            $attachment->post_parent // The id from the post parent
         )
    ) 
        return $template;

    // We have made it to here, lets set the new template for this attachment
    // Check if the template exist before we add it
    $locate_template = locate_template( 'image-mycategory.php'); // Change as needed
    if ( !$locate_template )
       return $template;

    // YEAH, everything checks out, finaly. Set the new template
    return $template = $locate_template;
});

I have commented the code for easy following, and I also have added where you should change value to suite your needs

EDIT

If you need to set the same template for multiple categories, you can just extend the in_category() check. in_category() accepts an array of category ID’s, names, and slugs. Something like the following would work

    if ( 
         !has_category( // If our parent does not have this category, return 
            [1, 2, 3] // Array of category id's, or names or slugs, change as needed
            $attachment->post_parent // The id from the post parent
         )
    ) 
        return $template;

If you need to extend this to set different templates for different categories, we need a few more checks

add_filter( 'attachment_template', function ( $template )
{
    // Get the current attachment object
    $attachment = get_queried_object();

    /**
     * Check if current attachment's parent is attached to our desired category or not and set template part
     * For example, templates will be image-cars.php and image-tech.php, so our
     * $parts will be cars and tech
     */
    $part="";

    // Check for cars category and set $part
    if ( 
         has_category( // If our parent have this category, set template part
            1, // Category id, or name or slug, change as needed
            $attachment->post_parent // The id from the post parent
         )
    ) 
        $part="cars";

    // Check for tech category and set $part
    if ( 
         has_category( // If our parent have this category, set template part
            2, // Category id, or name or slug, change as needed
            $attachment->post_parent // The id from the post parent
         )
    ) 
        $part="tech";

    // Check if $part have a value, if not, bail
    if ( !$part )
        return $template;

    // We have made it to here, lets set the new template for this attachment
    // Check if the template exist before we add it
    $locate_template = locate_template( "image-$part.php"); // Change as needed
    if ( !$locate_template )
       return $template;

    // YEAH, everything checks out, finally. Set the new template
    return $template = $locate_template;
});