|
Server : Apache System : Linux s1230 5.15.0-139-generic #149~20.04.1 SMP Tue Jul 14 11:21:49 UTC 2026 x86_64 User : p141464 ( 418825) PHP Version : 7.4.33.12 Disable Function : NONE Directory : /html/relaunch-kmu/wp-content/plugins/imagify/classes/Abilities/ |
Upload File : |
<?php
declare(strict_types=1);
namespace Imagify\Abilities;
use Imagify\Optimization\Data\WP;
use Imagify\Optimization\Process\ProcessInterface;
/**
* MCP ability: imagify/get-media-status
*
* Returns the optimization status and key metrics for a given WordPress
* media library attachment.
*
* @since 2.3.0
*/
class GetMediaStatus extends AbstractAbility {
/**
* Returns the ability slug.
*
* @return string
*/
public function get_id(): string {
return 'imagify/get-media-status';
}
/**
* Returns the ability label.
*
* @return string
*/
public function get_name(): string {
return 'Get Media Status';
}
/**
* Register the ability with the WP Abilities API.
*
* No-ops silently when `wp_register_ability` is unavailable (WP < 6.9).
*
* @since 2.3.0
*
* @return void
*/
public function register(): void {
if ( ! function_exists( 'wp_register_ability' ) ) {
return;
}
wp_register_ability(
'imagify/get-media-status',
[
'label' => __( 'Get Media Status', 'imagify' ),
'description' => __( 'Retrieve the optimization status and metrics for a WordPress media library attachment.', 'imagify' ),
'category' => 'imagify',
'input_schema' => [
'type' => 'object',
'properties' => [
'media_id' => [
'type' => 'integer',
'description' => __( 'The WordPress attachment ID. Provide media_filename or media_url instead when the ID is unknown.', 'imagify' ),
],
] + MediaResolver::get_input_schema_properties(),
],
'output_schema' => [
'type' => 'object',
'properties' => [
'status' => [
'type' => 'string',
'description' => __( 'Optimization status: "success", "error", or "unoptimized".', 'imagify' ),
'enum' => [ 'success', 'error', 'unoptimized' ],
],
'optimization_level' => [
'type' => [ 'integer', 'null' ],
'description' => __( '0 = lossless, 1 = aggressive, 2 = ultra. Null when not optimized.', 'imagify' ),
],
'original_size' => [
'type' => 'integer',
'description' => __( 'File size in bytes before optimization.', 'imagify' ),
],
'optimized_size' => [
'type' => 'integer',
'description' => __( 'File size in bytes after optimization.', 'imagify' ),
],
'webp_available' => [
'type' => 'boolean',
'description' => __( 'True when a WebP version of the full-size image has been generated.', 'imagify' ),
],
'avif_available' => [
'type' => 'boolean',
'description' => __( 'True when an AVIF version of the full-size image has been generated.', 'imagify' ),
],
'error_message' => [
'type' => [ 'string', 'null' ],
'description' => __( 'Human-readable error message when status is "error". Null otherwise.', 'imagify' ),
],
],
],
'execute_callback' => [ $this, 'execute' ],
'permission_callback' => [ $this, 'check_permissions' ],
'meta' => [
'show_in_rest' => true,
'mcp' => [ 'public' => true ],
'annotations' => [
'readonly' => true,
'destructive' => false,
'idempotent' => true,
],
],
]
);
}
/**
* Routes through Imagify's capability abstraction so the `imagify_capacity`
* filter and multisite network-admin logic are honoured.
*
* @since 2.3.0
*
* @return bool True when the current user has the Imagify `manage` capability.
*/
protected function has_permission(): bool {
return imagify_get_context( 'wp' )->current_user_can( 'manage' );
}
/**
* Execute the ability and return the media optimization status.
*
* @since 2.3.0
*
* @param array $args Input arguments. Expects `media_id` (int) — the WordPress attachment ID.
* @return array Optimization status response keyed by status, optimization_level, original_size,
* optimized_size, webp_available, avif_available, and error_message.
*/
public function execute( array $args = [] ): array {
$start_time = microtime( true );
$result = $this->do_execute( $args );
$this->fire_executed( $result, $start_time, $args );
return $result;
}
/**
* Internal execution logic for the ability.
*
* @param array $args Input arguments.
* @return array
*/
private function do_execute( array $args ): array {
$media_id = MediaResolver::resolve_id( $args );
if ( is_wp_error( $media_id ) ) {
return $this->error_response( $media_id->get_error_message() );
}
// Verify the attachment exists.
if ( ! get_post( $media_id ) ) {
return $this->error_response( 'Media not found.' );
}
$wp_data = $this->create_wp_data( $media_id );
$opt_data = $wp_data->get_optimization_data();
$internal_status = isset( $opt_data['status'] ) ? (string) $opt_data['status'] : '';
$status = $this->map_status( $internal_status );
$level = isset( $opt_data['level'] ) && false !== $opt_data['level']
? (int) $opt_data['level']
: null;
// get_original_size(false) falls back to the filesystem when no optimization data
// exists yet (unoptimized media), which avoids the 0-byte read from empty meta.
$original_size = $wp_data->get_original_size( false );
$optimized_size = isset( $opt_data['stats']['optimized_size'] ) ? (int) $opt_data['stats']['optimized_size'] : 0;
$webp_available = false;
$avif_available = false;
if ( ! empty( $opt_data['sizes'] ) && is_array( $opt_data['sizes'] ) ) {
foreach ( array_keys( $opt_data['sizes'] ) as $size_key ) {
if ( ! $webp_available && $this->size_key_ends_with( (string) $size_key, ProcessInterface::WEBP_SUFFIX ) ) {
$webp_available = true;
}
if ( ! $avif_available && $this->size_key_ends_with( (string) $size_key, ProcessInterface::AVIF_SUFFIX ) ) {
$avif_available = true;
}
if ( $webp_available && $avif_available ) {
break;
}
}
}
$error_message = null;
if ( 'error' === $status ) {
$error_message = isset( $opt_data['message'] ) && '' !== $opt_data['message']
? (string) $opt_data['message']
: null;
}
return [
'status' => $status,
'optimization_level' => $level,
'original_size' => $original_size,
'optimized_size' => $optimized_size,
'webp_available' => $webp_available,
'avif_available' => $avif_available,
'error_message' => $error_message,
];
}
/**
* Build an error response with every output field set to a neutral value.
*
* @since 2.3.3
*
* @param string $error_message Human-readable error message.
* @return array{status: string, optimization_level: null, original_size: int, optimized_size: int, webp_available: bool, avif_available: bool, error_message: string}
*/
private function error_response( string $error_message ): array {
return [
'status' => 'error',
'optimization_level' => null,
'original_size' => 0,
'optimized_size' => 0,
'webp_available' => false,
'avif_available' => false,
'error_message' => $error_message,
];
}
/**
* Instantiate the WP optimization-data object for a given media.
*
* Extracted to a protected method so tests can override it without hitting the database.
*
* @since 2.3.0
*
* @param int $media_id WordPress attachment ID.
* @return WP
*/
protected function create_wp_data( int $media_id ): WP {
return new WP( $media_id );
}
/**
* Map the internal Imagify optimization status to the public API status.
*
* @since 2.3.0
*
* @param string $internal_status The internal status string from `_imagify_status` meta.
* @return string 'success', 'error', or 'unoptimized'.
*/
private function map_status( string $internal_status ): string {
if ( 'success' === $internal_status || 'already_optimized' === $internal_status ) {
return 'success';
}
if ( 'error' === $internal_status ) {
return 'error';
}
return 'unoptimized';
}
/**
* Check whether a size key ends with a given suffix.
*
* @since 2.3.0
*
* @param string $size_key The thumbnail size key to inspect.
* @param string $suffix The suffix to check for.
* @return bool
*/
private function size_key_ends_with( string $size_key, string $suffix ): bool {
$suffix_length = strlen( $suffix );
if ( 0 === $suffix_length ) {
return true;
}
return substr( $size_key, -$suffix_length ) === $suffix;
}
}