<?php
declare(strict_types=1);
namespace MeinWeimar;
use WP_Error;
use WP_REST_Request;
use WP_REST_Response;
use WP_REST_Server;
final class Favorites
{
private const SCHEMA_VERSION = '0.1.0';
public static function hooks(): void
{
add_action('rest_api_init', [self::class, 'register_routes']);
}
public static function install(): void
{
global $wpdb;
require_once ABSPATH . 'wp-admin/includes/upgrade.php';
$table = self::table();
$charset_collate = $wpdb->get_charset_collate();
dbDelta("CREATE TABLE {$table} (
id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
user_id bigint(20) unsigned NOT NULL,
object_type varchar(40) NOT NULL,
object_id bigint(20) unsigned NOT NULL,
created_at datetime NOT NULL,
PRIMARY KEY (id),
UNIQUE KEY user_object (user_id,object_type,object_id),
KEY user_created (user_id,created_at)
) {$charset_collate};");
update_option('meinweimar_favorites_schema_version', self::SCHEMA_VERSION, false);
}
public static function register_routes(): void
{
register_rest_route('meinweimar/v1', '/favorites', [
'methods' => WP_REST_Server::READABLE,
'callback' => [self::class, 'list'],
'permission_callback' => [AccountApi::class, 'require_login'],
]);
register_rest_route('meinweimar/v1', '/favorites/(?P<object_type>[a-z0-9-]+)/(?P<object_id>\d+)', [
[
'methods' => WP_REST_Server::CREATABLE,
'callback' => [self::class, 'add'],
'permission_callback' => [AccountApi::class, 'require_login'],
],
[
'methods' => WP_REST_Server::DELETABLE,
'callback' => [self::class, 'remove'],
'permission_callback' => [AccountApi::class, 'require_login'],
],
]);
}
public static function list(): WP_REST_Response
{
global $wpdb;
$rows = $wpdb->get_results($wpdb->prepare(
'SELECT object_type, object_id, created_at FROM ' . self::table() . ' WHERE user_id = %d ORDER BY created_at DESC LIMIT 500',
get_current_user_id()
), ARRAY_A);
$items = [];
foreach ($rows as $row) {
$post_type = ContentTypes::post_type_for_route((string) $row['object_type']);
$post = $post_type ? get_post((int) $row['object_id']) : null;
if (!$post || $post->post_type !== $post_type || 'publish' !== $post->post_status) {
continue;
}
$items[] = [
'object_type' => (string) $row['object_type'],
'object_id' => (int) $row['object_id'],
'created_at' => (string) $row['created_at'],
'item' => RestApi::public_item($post),
];
}
return new WP_REST_Response(['items' => $items]);
}
public static function add(WP_REST_Request $request): WP_REST_Response|WP_Error
{
[$route, $post] = self::resolve_object($request);
if (is_wp_error($post)) {
return $post;
}
global $wpdb;
$now = current_time('mysql', true);
$result = $wpdb->query($wpdb->prepare(
'INSERT INTO ' . self::table() . ' (user_id,object_type,object_id,created_at) VALUES (%d,%s,%d,%s) ON DUPLICATE KEY UPDATE created_at = created_at',
get_current_user_id(),
$route,
$post->ID,
$now
));
if (false === $result) {
return new WP_Error('meinweimar_favorite_store_failed', __('Favorit konnte nicht gespeichert werden.', 'meinweimar-core'), ['status' => 500]);
}
return new WP_REST_Response(['object_type' => $route, 'object_id' => $post->ID, 'saved' => true], 201);
}
public static function remove(WP_REST_Request $request): WP_REST_Response|WP_Error
{
[$route, $post] = self::resolve_object($request);
if (is_wp_error($post)) {
return $post;
}
global $wpdb;
$wpdb->delete(self::table(), ['user_id' => get_current_user_id(), 'object_type' => $route, 'object_id' => $post->ID], ['%d', '%s', '%d']);
return new WP_REST_Response(['object_type' => $route, 'object_id' => $post->ID, 'saved' => false]);
}
private static function resolve_object(WP_REST_Request $request): array|WP_Error
{
$route = sanitize_key((string) $request['object_type']);
$post_type = ContentTypes::post_type_for_route($route);
$post = $post_type ? get_post(absint($request['object_id'])) : null;
if (!$post || $post->post_type !== $post_type || 'publish' !== $post->post_status) {
return new WP_Error('meinweimar_favorite_not_found', __('Der gespeicherte Eintrag wurde nicht gefunden.', 'meinweimar-core'), ['status' => 404]);
}
return [$route, $post];
}
private static function table(): string
{
global $wpdb;
return $wpdb->prefix . 'mw_favorites';
}
}
