feat: media usage finder and media-get tool
Usage search distinguishes certain (ID referenced) and possible (file URL only) usages, hides titles the user cannot read, and keeps queries bounded. MediaGuard checks per-attachment capabilities and refuses trashed media unless the caller opts in. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01At3V6SjwbMe6eMzVGW3Hs7
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace LIT\MCP\Integrations\Media;
|
||||
|
||||
use LIT\MCP\Abilities\JsonMap;
|
||||
use WP_Post;
|
||||
|
||||
/**
|
||||
* Output format of an attachment. Not final so abilities can be tested with a mock.
|
||||
*/
|
||||
class MediaPresenter
|
||||
{
|
||||
/** @return array<string, mixed> */
|
||||
public function summary(WP_Post $attachment): array
|
||||
{
|
||||
$id = (int) $attachment->ID;
|
||||
$meta = $this->metadata($attachment);
|
||||
|
||||
return [
|
||||
'id' => $id,
|
||||
'title' => (string) $attachment->post_title,
|
||||
'filename' => wp_basename((string) get_attached_file($id)),
|
||||
'mime_type' => (string) $attachment->post_mime_type,
|
||||
'url' => (string) wp_get_attachment_url($id),
|
||||
'alt' => (string) get_post_meta($id, '_wp_attachment_image_alt', true),
|
||||
'width' => isset($meta['width']) ? (int) $meta['width'] : null,
|
||||
'height' => isset($meta['height']) ? (int) $meta['height'] : null,
|
||||
'filesize' => isset($meta['filesize']) ? (int) $meta['filesize'] : null,
|
||||
'date' => (string) $attachment->post_date,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param list<array<string, mixed>> $usages From MediaUsageFinder::usages().
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
public function full(WP_Post $attachment, array $usages): array
|
||||
{
|
||||
$id = (int) $attachment->ID;
|
||||
$sizes = [];
|
||||
foreach ((array) ($this->metadata($attachment)['sizes'] ?? []) as $name => $size) {
|
||||
$source = wp_get_attachment_image_src($id, (string) $name);
|
||||
if (is_array($source)) {
|
||||
$sizes[(string) $name] = [
|
||||
'url' => (string) $source[0],
|
||||
'width' => (int) $source[1],
|
||||
'height' => (int) $source[2],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return array_merge($this->summary($attachment), [
|
||||
'caption' => (string) $attachment->post_excerpt,
|
||||
'description' => (string) $attachment->post_content,
|
||||
'parent' => (int) $attachment->post_parent,
|
||||
'sizes' => JsonMap::of($sizes),
|
||||
'usages' => $usages,
|
||||
'edit_url' => (string) get_edit_post_link($id, 'raw'),
|
||||
]);
|
||||
}
|
||||
|
||||
/** @return array<string, mixed> */
|
||||
public static function summarySchema(): array
|
||||
{
|
||||
return [
|
||||
'type' => 'object',
|
||||
'properties' => [
|
||||
'id' => ['type' => 'integer'],
|
||||
'title' => ['type' => 'string'],
|
||||
'filename' => ['type' => 'string'],
|
||||
'mime_type' => ['type' => 'string'],
|
||||
'url' => ['type' => 'string'],
|
||||
'alt' => ['type' => 'string'],
|
||||
'width' => ['type' => ['integer', 'null']],
|
||||
'height' => ['type' => ['integer', 'null']],
|
||||
'filesize' => ['type' => ['integer', 'null']],
|
||||
'date' => ['type' => 'string'],
|
||||
],
|
||||
'required' => ['id', 'title', 'mime_type', 'url', 'alt'],
|
||||
];
|
||||
}
|
||||
|
||||
/** @return array<string, mixed> */
|
||||
public static function fullSchema(): array
|
||||
{
|
||||
$schema = self::summarySchema();
|
||||
$schema['properties'] = array_merge($schema['properties'], [
|
||||
'caption' => ['type' => 'string'],
|
||||
'description' => ['type' => 'string'],
|
||||
'parent' => ['type' => 'integer'],
|
||||
'sizes' => ['type' => 'object'],
|
||||
'usages' => ['type' => 'array', 'items' => MediaUsageFinder::usageSchema()],
|
||||
'edit_url' => ['type' => 'string'],
|
||||
]);
|
||||
$schema['required'] = array_merge($schema['required'], ['sizes', 'usages']);
|
||||
|
||||
return $schema;
|
||||
}
|
||||
|
||||
/** @return array<string, mixed> */
|
||||
private function metadata(WP_Post $attachment): array
|
||||
{
|
||||
$meta = wp_get_attachment_metadata((int) $attachment->ID);
|
||||
|
||||
return is_array($meta) ? $meta : [];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user