class-favorites-controller.php
5 days ago
class-library-controller.php
5 days ago
class-request-controller.php
5 days ago
class-favorites-controller.php
128 lines
| 1 | <?php |
| 2 | |
| 3 | namespace SuperbAddons\Library\Controllers; |
| 4 | |
| 5 | defined('ABSPATH') || exit(); |
| 6 | |
| 7 | use Exception; |
| 8 | use WP_Error; |
| 9 | use WP_REST_Server; |
| 10 | use SuperbAddons\Config\Capabilities; |
| 11 | use SuperbAddons\Data\Controllers\LogController; |
| 12 | use SuperbAddons\Data\Controllers\RestController; |
| 13 | |
| 14 | class FavoritesController |
| 15 | { |
| 16 | const FAVORITES_META_KEY = 'superb-addons-library-favorites'; |
| 17 | const MAX_PER_TAB = 500; |
| 18 | |
| 19 | const FAVORITES_ROUTE = '/library/favorites'; |
| 20 | |
| 21 | private static $allowed_tabs = array('patterns', 'pages', 'sections'); |
| 22 | private static $allowed_states = array('add', 'remove'); |
| 23 | |
| 24 | public function __construct() |
| 25 | { |
| 26 | RestController::AddRoute(self::FAVORITES_ROUTE, array( |
| 27 | 'methods' => WP_REST_Server::READABLE, |
| 28 | 'permission_callback' => array($this, 'PermissionCheck'), |
| 29 | 'callback' => array($this, 'GetCallback'), |
| 30 | )); |
| 31 | RestController::AddRoute(self::FAVORITES_ROUTE, array( |
| 32 | 'methods' => WP_REST_Server::EDITABLE, |
| 33 | 'permission_callback' => array($this, 'PermissionCheck'), |
| 34 | 'callback' => array($this, 'ToggleCallback'), |
| 35 | )); |
| 36 | } |
| 37 | |
| 38 | public function PermissionCheck() |
| 39 | { |
| 40 | if (!current_user_can(Capabilities::CONTRIBUTOR)) { |
| 41 | return new WP_Error('rest_forbidden', esc_html__('Unauthorized. Please check user permissions.', "superb-blocks"), array('status' => 401)); |
| 42 | } |
| 43 | return true; |
| 44 | } |
| 45 | |
| 46 | public function GetCallback() |
| 47 | { |
| 48 | try { |
| 49 | return rest_ensure_response(self::GetFavorites(get_current_user_id())); |
| 50 | } catch (Exception $ex) { |
| 51 | LogController::HandleException($ex); |
| 52 | return new WP_Error('internal_error_plugin', 'Internal Plugin Error', array('status' => 500)); |
| 53 | } |
| 54 | } |
| 55 | |
| 56 | public function ToggleCallback($request) |
| 57 | { |
| 58 | try { |
| 59 | $tab = isset($request['tab']) ? sanitize_title($request['tab']) : ''; |
| 60 | $id = isset($request['id']) ? sanitize_text_field($request['id']) : ''; |
| 61 | $state = isset($request['state']) ? sanitize_text_field($request['state']) : ''; |
| 62 | |
| 63 | if (!in_array($tab, self::$allowed_tabs, true)) { |
| 64 | return new WP_Error('invalid_request', 'Invalid tab', array('status' => 400)); |
| 65 | } |
| 66 | if ($id === '' || strlen($id) > 191) { |
| 67 | return new WP_Error('invalid_request', 'Invalid id', array('status' => 400)); |
| 68 | } |
| 69 | if (!in_array($state, self::$allowed_states, true)) { |
| 70 | return new WP_Error('invalid_request', 'Invalid state', array('status' => 400)); |
| 71 | } |
| 72 | |
| 73 | $user_id = get_current_user_id(); |
| 74 | $favorites = self::GetFavorites($user_id); |
| 75 | $bucket = isset($favorites[$tab]) && is_array($favorites[$tab]) ? $favorites[$tab] : array(); |
| 76 | |
| 77 | $index = array_search($id, $bucket, true); |
| 78 | if ($state === 'add') { |
| 79 | if ($index === false) { |
| 80 | $bucket[] = $id; |
| 81 | } |
| 82 | } else { |
| 83 | if ($index !== false) { |
| 84 | array_splice($bucket, $index, 1); |
| 85 | } |
| 86 | } |
| 87 | |
| 88 | // Soft cap per tab — drop oldest entries if we blow past the limit. |
| 89 | if (count($bucket) > self::MAX_PER_TAB) { |
| 90 | $bucket = array_slice($bucket, -self::MAX_PER_TAB); |
| 91 | } |
| 92 | |
| 93 | $favorites[$tab] = array_values($bucket); |
| 94 | |
| 95 | if (update_user_meta($user_id, self::FAVORITES_META_KEY, $favorites) === false) { |
| 96 | throw new Exception('Failed to update user meta'); |
| 97 | } |
| 98 | |
| 99 | return rest_ensure_response($favorites); |
| 100 | } catch (Exception $ex) { |
| 101 | LogController::HandleException($ex); |
| 102 | return new WP_Error('internal_error_plugin', 'Internal Plugin Error', array('status' => 500)); |
| 103 | } |
| 104 | } |
| 105 | |
| 106 | /** |
| 107 | * Return the current user's favorites as an associative array keyed by tab id. |
| 108 | * Missing/invalid meta is normalized to an empty array. |
| 109 | */ |
| 110 | public static function GetFavorites($user_id) |
| 111 | { |
| 112 | $stored = get_user_meta($user_id, self::FAVORITES_META_KEY, true); |
| 113 | if (!is_array($stored)) { |
| 114 | return array(); |
| 115 | } |
| 116 | $normalized = array(); |
| 117 | foreach (self::$allowed_tabs as $tab) { |
| 118 | if (isset($stored[$tab]) && is_array($stored[$tab])) { |
| 119 | // Coerce every id to a string for stable JS comparison. |
| 120 | $normalized[$tab] = array_values(array_map('strval', $stored[$tab])); |
| 121 | } else { |
| 122 | $normalized[$tab] = array(); |
| 123 | } |
| 124 | } |
| 125 | return $normalized; |
| 126 | } |
| 127 | } |
| 128 |