diff --git a/composer.json b/composer.json index e37d6a1..bbd3cc4 100644 --- a/composer.json +++ b/composer.json @@ -5,6 +5,7 @@ "type": "library", "require": { "php": "^8.1", + "ext-fileinfo": "*", "illuminate/http": "^10.0", "illuminate/support": "^10.0", "justinrainbow/json-schema": "^5.2" diff --git a/src/Exceptions/InvalidPostIdException.php b/src/Exceptions/InvalidPostIdException.php new file mode 100644 index 0000000..03ccdab --- /dev/null +++ b/src/Exceptions/InvalidPostIdException.php @@ -0,0 +1,10 @@ + + */ + public array $meta; + + public string $alt_text; + + public string $media_type; + + public string $mime_type; + + public MediaDetails $media_details; + + public ?int $post; + + public string $source_url; + + public static function from(stdClass $data): static + { + $data->guid = Render::from($data->guid); + + $data->title = Render::from($data->title); + + $data->description = Render::from($data->description); + + $data->caption = Render::from($data->caption); + + $data->media_details = MediaDetails::from($data->media_details); + + return parent::from($data); + } +} diff --git a/src/Objects/MediaDetails.php b/src/Objects/MediaDetails.php new file mode 100644 index 0000000..d68f4d3 --- /dev/null +++ b/src/Objects/MediaDetails.php @@ -0,0 +1,22 @@ + + * + * @throws WordPressException + */ + public function list(): array + { + $data = $this->request('get', '/media'); + + if (!is_array($data)) { + throw $this->unexpectedValueException(); + } + + return array_map( + fn ($data) => MediaObject::from($data), + $data, + ); + } + + /** + * https://developer.wordpress.org/rest-api/reference/media/#create-a-media-item + * + * @param array $arguments + * + * @throws WordPressException + */ + public function create(UploadedFile $file, array $arguments): MediaObject + { + $arguments['file'] = $file; + + $data = $this->request('post', '/media', $arguments); + + if (is_array($data)) { + throw $this->unexpectedValueException(); + } + + return MediaObject::from($data); + } + + /** + * https://developer.wordpress.org/rest-api/reference/media/#retrieve-a-media-item + * + * + * @throws WordPressException + */ + public function retrieve(int $mediaId, string $context = 'view'): MediaObject + { + $uri = sprintf('/media/%d', $mediaId); + + $data = $this->request('get', $uri, [ + 'context' => $context, + ]); + + if (is_array($data)) { + throw $this->unexpectedValueException(); + } + + return MediaObject::from($data); + } + + /** + * https://developer.wordpress.org/rest-api/reference/media/#update-a-media-item + * + * @param array $arguments + * + * @throws WordPressException + */ + public function update(int $mediaId, array $arguments): MediaObject + { + $uri = sprintf('/media/%d', $mediaId); + + $data = $this->request('patch', $uri, $arguments); + + if (is_array($data)) { + throw $this->unexpectedValueException(); + } + + return MediaObject::from($data); + } + + /** + * https://developer.wordpress.org/rest-api/reference/media/#delete-a-media-item + * + * @throws WordPressException + */ + public function delete(int $mediaId): bool + { + $uri = sprintf('/media/%s', $mediaId); + + return $this->request('delete', $uri, [ + 'force' => true, + ]); + } +} diff --git a/src/Requests/Request.php b/src/Requests/Request.php index 76fca02..a89608b 100644 --- a/src/Requests/Request.php +++ b/src/Requests/Request.php @@ -5,6 +5,7 @@ namespace Storipress\WordPress\Requests; use Illuminate\Http\Client\Response; +use Illuminate\Http\UploadedFile; use JsonSchema\Constraints\Constraint; use JsonSchema\Validator; use stdClass; @@ -13,6 +14,7 @@ use Storipress\WordPress\Exceptions\CannotUpdateException; use Storipress\WordPress\Exceptions\DuplicateTermSlugException; use Storipress\WordPress\Exceptions\ForbiddenException; +use Storipress\WordPress\Exceptions\InvalidPostIdException; use Storipress\WordPress\Exceptions\NoRouteException; use Storipress\WordPress\Exceptions\NotFoundException; use Storipress\WordPress\Exceptions\TermExistsException; @@ -36,7 +38,7 @@ public function __construct( /** * @param 'get'|'post'|'patch'|'delete' $method * @param non-empty-string $path - * @param array $options + * @param array $options * @return ($method is 'delete' ? bool : stdClass|array) * * @throws UnexpectedValueException|WordPressException @@ -55,6 +57,12 @@ protected function request( $http->withUserAgent($this->app->userAgent()); } + if (isset($options['file']) && $options['file'] instanceof UploadedFile) { + $http->attach('file', $options['file']->getContent(), $options['file']->getClientOriginalName()); + + unset($options['file']); + } + $response = $http->{$method}( $this->getUrl( $path, @@ -124,6 +132,7 @@ protected function error(stdClass $payload, string $message, int $status): void 'rest_cannot_create' => new CannotCreateException($error, $status), 'rest_cannot_update' => new CannotUpdateException($error, $status), 'rest_no_route' => new NoRouteException($error, $status), + 'rest_post_invalid_id' => new InvalidPostIdException($error, $status), default => new UnknownException($error, $status), }; } diff --git a/src/WordPress.php b/src/WordPress.php index fb31a66..c2cee5d 100644 --- a/src/WordPress.php +++ b/src/WordPress.php @@ -7,6 +7,7 @@ use Illuminate\Http\Client\Factory; use Storipress\WordPress\Requests\Category; use Storipress\WordPress\Requests\GeneralRequest; +use Storipress\WordPress\Requests\Media; use Storipress\WordPress\Requests\Post; use Storipress\WordPress\Requests\Tag; use Storipress\WordPress\Requests\User; @@ -23,6 +24,8 @@ class WordPress protected readonly Tag $tag; + protected readonly Media $media; + protected string $site; protected string $username; @@ -47,6 +50,8 @@ public function __construct( $this->category = new Category($this); $this->tag = new Tag($this); + + $this->media = new Media($this); } public function instance(): static @@ -150,4 +155,9 @@ public function tag(): Tag { return $this->tag; } + + public function media(): Media + { + return $this->media; + } }