From d7e7d248cbe41cd7a9ef9c2fb022b6c4831f99a3 Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Sun, 31 May 2026 15:22:56 +0000
Subject: [PATCH] =jakevan complete
---
inc/rest/routes/AdminRoutes.php | 722 ++++++++++---------------------------------------------
1 files changed, 133 insertions(+), 589 deletions(-)
diff --git a/inc/rest/routes/AdminRoutes.php b/inc/rest/routes/AdminRoutes.php
index cf58a34..4f89e76 100644
--- a/inc/rest/routes/AdminRoutes.php
+++ b/inc/rest/routes/AdminRoutes.php
@@ -2,8 +2,11 @@
namespace JVBase\rest\routes;
use JVBase\JVB;
-use JVBase\rest\RestRouteManager;
-use JVBase\meta\MetaManager;
+use JVBase\managers\Cache;
+use JVBase\managers\IconsManager;
+use JVBase\rest\Rest;
+use JVBase\rest\Route;
+use JVBase\rest\PermissionHandler;
use WP_Query;
use WP_Error;
use WP_REST_Request;
@@ -13,7 +16,7 @@
exit; // Exit if accessed directly
}
-class AdminRoutes extends RestRouteManager
+class AdminRoutes extends Rest
{
protected array $fields;
protected $meta;
@@ -22,52 +25,28 @@
public function __construct()
{
- $this->cache_name = 'itsme';
+ $this->cacheName = 'itsme';
parent::__construct();
- $this->action = 'itsme';
}
public function registerRoutes():void
{
- if (!current_user_can('manage_options')) {
- return;
- }
- register_rest_route($this->namespace, '/myster', [
- [
- 'methods' => 'GET',
- 'callback' => [$this, 'getItems'],
- 'permission_callback' => [$this, 'checkPermission']
- ],
- [
- 'methods' => 'POST',
- 'callback' => [$this, 'updateItems'],
- 'permission_callback' => [$this, 'checkPermission']
- ]
- ]);
+ Route::for('admin-cache')
+ ->post([$this, 'handleCacheAction'])
+ ->auth('admin')
+ ->rateLimit(30)
+ ->register();
- register_rest_route($this->namespace, '/admin-action', [
- [
- 'methods' => 'POST',
- 'callback' => [$this, 'adminAction'],
- 'permission_callback' => [$this, 'checkPermission']
- ]
- ]);
- }
+ Route::for('admin-icons')
+ ->post([$this, 'handleIconAction'])
+ ->auth('admin')
+ ->rateLimit(30)
+ ->register();
- /**
- * @param WP_REST_Request $request The Request object
- *
- * @return bool whether or not we can proceed
- */
- public function checkPermission(WP_REST_Request $request):bool
- {
- if (!current_user_can('manage_options')) {
- return false;
- }
- $this->verifyNonce($request, 'wp_rest');
- if ($this->action!=='') {
- $this->verifyNonce($request, $this->action . get_current_user_id(), $request->get_header('action_nonce'));
- }
- return true;
+ Route::for('admin-action')
+ ->post([$this, 'adminAction'])
+ ->auth('admin')
+ ->rateLimit()
+ ->register();
}
/**
@@ -91,227 +70,6 @@
);
}
- /**
- * @param WP_REST_Request $request Request object
- *
- * @return WP_REST_Response
- */
- public function updateItems(WP_REST_Request $request):WP_REST_Response
- {
- error_log('Received Request: '.print_r($request->get_params(), true));
- $content = $request->get_param('content');
- if (!$this->checkContent($content, true)) {
- return new WP_REST_Response([
- 'sucess' => false,
- 'message' => 'Invalid attempt'
- ]);
- }
- $data = $request->get_param('data');
- if (empty($data)) {
- return new WP_REST_Response([
- 'success' => true,
- 'message' => 'Nothing to Update'
- ]);
- }
-
- $type = match ($content) {
- 'shop',
- 'artform',
- 'type',
- 'media',
- 'artstyle',
- 'arttheme',
- 'city',
- 'colour',
- 'offerfor',
- 'pstyle',
- 'style',
- 'theme' => 'term',
- default => 'post',
- };
- $errors = [];
- $success = [];
- error_log('Data: '.print_r($data, true));
-
- foreach ($data as $ID => $fields) {
- $ID = (int)$ID;
- $meta = new MetaManager($ID, $type);
- $allFields = JVB()->getFields($content);
- foreach ($fields as $name => $value) {
- $process = true;
- if (!array_key_exists($name, $allFields)) {
- $errors[$ID][$name] = __('Field not found', 'jvb');
- $process = false;
- }
- error_log('Proceeding as Normal...');
- //Switch between config types to extract values for special cases
- $config = $allFields[$name];
-
- switch ($config['type']) {
- case 'radio':
- //Ensure we only chose one option
- $temp = explode(',', $value);
- $value = trim($temp[0]);
- if (!in_array($value, $config['options'])) {
- $errors[$ID][$name] = __('Invalid Option', 'jvb');
- $process = false;
- }
- break;
- case 'set':
- $temp = explode(',', $value);
- $value = array_map('trim', $temp);
- break;
- case 'repeater':
- error_log('Repeater: '.print_r($name, true));
- $single = false;
- switch ($name) {
- case 'keywords':
- $single = 'keyword';
- break;
- case 'languages':
- $single = 'language';
- break;
- case 'links':
- $single = 'url';
- break;
- case 'followers':
- $single = 'count';
- break;
- }
- $items = array_keys($config['fields']);
-
- //First, separate out any ]
- if (strpos($value, ']')) {
- $rows = array_map(function ($item) {
- return str_replace('[', '', $item);
- }, explode(']', $value));
- array_pop($rows);
- error_log('Rows: '.print_r($rows, true));
- $value = [];
- foreach ($rows as $index => $row) {
- $r = array_map('trim', explode(',', $row));
- if (count($r) !== count($items)) {
- $errors[$ID][$name] = __('Not enough fields set. May not save correctly', 'jvb');
- }
- //attempt to save fields
- $new = [];
- foreach ($items as $key => $i) {
- $new[$i] = (array_key_exists($key, $r)) ? $r[$key] : (($i==='checked') ? date('Y-m-d'): '');
- }
- $value[] = $new;
- }
- error_log('Processed Repeater Value for sanitizing: '.print_r($value, true));
-
- } elseif ($value === '') {
- $value = [];
- } else {
- if (!$single) {
- $errors[$ID][$name] = __('Must set single key', 'jvb');
- $process = false;
- }
- $rows = array_map('trim', explode(',', $value));
- $value = [];
- foreach ($rows as $row) {
- $new = [];
- foreach ($items as $i) {
- $new[$i] = ($i === $single) ? $row : (($i==='checked') ? date('Y-m-d') : '');
- }
- error_log('New Repeater Row Output: '.print_r($new, true));
- $value[] = $new;
- }
- }
-
- break;
- }
-
- switch ($name) {
- case 'shop':
- case 'type':
- case 'city':
- $terms = array_map('trim', explode(',', $value));
- $set = [];
- foreach ($terms as $term) {
- $t = get_term_by('name', $value, BASE.$name);
- if (!$t) {
- $errors[$ID][$name][] = __($value.' does not exist yet', 'jvb');
- } else {
- $set[] = $t->term_id;
- }
- }
- if (!empty($set)) {
- $result = wp_set_post_terms($ID, $set, BASE.$name);
- $result = is_array($result);
- }
- break;
- case 'owner':
- error_log('Processing Owner Request from Admin Routes...');
- $users = array_map('trim', explode(',', $value));
- foreach ($users as $user) {
- $t = jvbGetUserByDisplayName($user)??jvbGetUserByFirstName($user)??false;
- error_log('Got user: '.print_r($t, true));
- if (!$t) {
- $errors[$ID][$name][] = __($value.' does not exist yet...', 'jvb');
- $result = false;
- } else {
- $result = JVB()->routes('shop')->setShopOwner($t->ID, $ID, true);
- }
- }
- break;
- case 'managers':
- error_log('Processing Manager Request from Admin Routes...');
- $users = array_map('trim', explode(',', $value));
- foreach ($users as $user) {
- $t = jvbGetUserByDisplayName($user)??jvbGetUserByFirstName($user)??false;
- error_log('Got user: '.print_r($t, true));
- if (!$t) {
- $result = $errors[$ID][$name][] = __($value.' does not exist yet...', 'jvb');
- } else {
- $result = JVB()->routes('shop')->setShopManager($t->ID, $ID, true);
- }
- }
- break;
- case 'location':
- $value = [
- 'address' => $value,
- 'lat' => '',
- 'lng' => '',
- ];
- $result = $meta->updateValue($name, $value);
- break;
- case 'hours':
- $temp = [];
- foreach ($value as $key => $v) {
- if (strpos($v['days'], '-')) {
- $temp[$key]['days'] = jvbExpandDayRange($v['days']);
- $temp[$key]['time_open'] = $v['time_open'];
- $temp[$key]['time_closes'] = $v['time_closes'];
- }
- }
- $value = $temp;
- error_log('Final Hours for processing: '.print_r($value, true));
- $result = $meta->updateValue($name, $value);
- break;
- default:
- $result = $meta->updateValue($name, $value);
- break;
- }
-
- //Save the value
- if ($result) {
- $success[$ID][] = $name;
- } else {
- $errors[$ID][] = [
- $name => 'Could not update value'
- ];
- }
- }
- }
- return new WP_REST_Response([
- 'success' => true,
- 'successful' => $success,
- 'errors' => $errors
- ]);
- }
/**
* @param array $filters
@@ -331,351 +89,137 @@
return $out;
}
- /**
- * @param WP_REST_Request $request The REST Request
- *
- * @return array
- */
- protected function buildParams(WP_REST_Request $request):array
- {
- $data = $request->get_params();
- $this->setMetaType($data['content']);
- switch ($this->metaType) {
- case 'post':
- $key = 'post_type';
- break;
- case 'term':
- $key = 'taxonomy';
- break;
- case 'user':
- $key = 'role';
- break;
- default:
- return [];
- }
- global $jvb_everything;
- return [
- $key => (array_key_exists('content', $data) &&
- array_key_exists($data['content'], $jvb_everything)) ?
- BASE.$data['content'] : BASE.'artist',
- 'order' => (array_key_exists('order', $data) &&
- in_array(strtolower($data['order']), ['asc', 'desc'])) ?
- strtolower($data['order']) : 'desc',
- 'orderby' => (array_key_exists('orderby', $data) &&
- in_array($data['orderby'], ['name', 'date', 'followers', 'karma'])) ?
- $data['orderby'] : 'name',
- 'paged' => (array_key_exists('page', $data) && is_numeric($data['page'])) ?
- (int)$data['page'] : 1,
- 'filters' => (array_key_exists('filters', $data)) ?
- $this->checkFilters($data['filters']) : null,
- ];
- }
+ /**
+ * Handle cache-related actions
+ */
+ public function handleCacheAction(\WP_REST_Request $request): \WP_REST_Response
+ {
+ $action = sanitize_text_field($request->get_param('action'));
- protected function setMetaType(string $type):void
- {
- $this->metaType = match (true) {
- array_key_exists($type, JVB_CONTENT) => 'post',
- array_key_exists($type, JVB_TAXONOMY) => 'term',
- array_key_exists($type, JVB_USER) => 'user',
- default => false,
- };
- }
+ switch ($action) {
+ case 'flush-all':
+ $total = Cache::flushAll();
+ return new \WP_REST_Response([
+ 'success' => true,
+ 'message' => $total.' caches flushed successfully'
+ ]);
- /**
- * @param WP_REST_Request $request The REST Request
- *
- * @return WP_REST_Response
- */
- public function getItems(WP_REST_Request $request):WP_REST_Response
- {
+ case 'flush-cache':
+ $group = sanitize_text_field($request->get_param('group'));
+ if (empty($group)) {
+ return new \WP_REST_Response([
+ 'success' => false,
+ 'message' => 'No cache group specified'
+ ], 400);
+ }
- $args = $this->buildParams($request);
- $key = $this->cache->generateKey($args);
+ Cache::for($group)?->flush();
- $cache = $this->cache->get($key);
- if ($cache) {
- return new WP_REST_Response($cache);
- }
+ return new \WP_REST_Response([
+ 'success' => true,
+ 'message' => "Cache group '{$group}' flushed successfully"
+ ]);
- $this->content = $request->get_param('content');
- $args['posts_per_page'] = 50;
-
- $this->fields = jvbGetFields($this->content);
-// $this->fields = array_filter(JVB()->getFields($data['content']), function($arr){
-// return array_key_exists('quickEdit', $arr);
-// });
-
- $response = match ($this->metaType) {
- 'post' => $this->getPostItems($args),
- 'term' => $this->getTermItems($args),
- 'user' => $this->getUserItems($args),
- default => []
- };
-
- $this->cache->set($key, $response);
- return new WP_REST_Response($response);
- }
-
- /**
- * @param array $args the data from buildParams method
- *
- * @return array
- */
- protected function getTermItems(array $args):array
- {
- if (isJVBContentTax($args['taxonomy'])) {
- return $this->getContentTypeTaxItems($args);
+ default:
+ return new \WP_REST_Response([
+ 'success' => false,
+ 'message' => 'Invalid action'
+ ], 400);
}
- // Build query arguments
- $args = array_merge($args, [
- 'hide_empty' => false,
- 'number' => $args['posts_per_page'],
- 'offset' => ($args['paged'] - 1) * $args['posts_per_page'],
- 'fields' => 'ids'
- ]);
+ }
- // Add ordering
- switch ($args['orderby']) {
- case 'date':
- $args['orderby'] = 'id'; // Terms don't have date, so use ID as a proxy
- break;
- case 'karma':
- // Terms should be ordered by meta value
- $args['orderby'] = 'meta_value_num';
- $args['meta_key'] = BASE . 'karma';
- break;
- default:
- $args['orderby'] = 'name';
- break;
- }
- $args['order'] = strtoupper($args['order']);
+ /**
+ * Handle icon-related actions
+ */
+ public function handleIconAction(\WP_REST_Request $request): \WP_REST_Response
+ {
+ $action = sanitize_text_field($request->get_param('action'));
+ $source = sanitize_text_field($request->get_param('source') ?? 'icons');
+ $icons = IconsManager::for($source);
- // Add any filters
- if (!empty($args['filters'])) {
- // Term meta filtering would go here
- $meta_query = [];
+ switch ($action) {
+ case 'refresh-icons':
+ // Force regenerate CSS immediately
+ $icons->forceRefresh();
+ IconsManager::regenerateAllCSS([$source => true]);
- foreach ($args['filters'] as $filter_type => $filter_values) {
- if (!empty($filter_values)) {
- // Example: filter by parent terms
- if ($filter_type === 'parent') {
- $args['parent'] = $filter_values[0]; // Assume single parent filter
- } else {
- // For meta-based filters
- $meta_query[] = [
- 'key' => BASE . $filter_type,
- 'value' => $filter_values,
- 'compare' => 'IN'
- ];
- }
- }
- }
+ return new \WP_REST_Response([
+ 'success' => true,
+ 'message' => "Icon CSS regenerated successfully for '{$source}'"
+ ]);
- if (!empty($meta_query)) {
- $args['meta_query'] = $meta_query;
- }
- }
- unset($args['filters']);
+ case 'refresh-all-icons':
+ // Regenerate all icon sources
+ foreach (['icons', 'forms', 'dash'] as $src) {
+ IconsManager::for($src)->forceRefresh();
+ }
+ IconsManager::regenerateAllCSS();
- // Get count first for pagination info
- $count_args = $args;
- unset($count_args['number']);
- unset($count_args['offset']);
- $count_args['fields'] = 'count';
- $total_items = get_terms($count_args);
+ return new \WP_REST_Response([
+ 'success' => true,
+ 'message' => 'All icon CSS files regenerated successfully'
+ ]);
- // Get the actual terms
- $term_ids = get_terms($args);
+ case 'restore-icon-version':
+ $timestamp = (int)$request->get_param('timestamp');
+ if (empty($timestamp)) {
+ return new \WP_REST_Response([
+ 'success' => false,
+ 'message' => 'No timestamp provided'
+ ], 400);
+ }
- // Error handling
- if (is_wp_error($term_ids)) {
- return [
- 'items' => [],
- 'has_more' => false,
- 'total_items' => 0,
- 'total_pages' => 0,
- 'error' => $term_ids->get_error_message()
- ];
- }
+ if ($icons->restoreVersion($timestamp)) {
+ return new \WP_REST_Response([
+ 'success' => true,
+ 'message' => 'Icon version restored successfully'
+ ]);
+ }
- // Format each term
- $items = array_map([$this, 'formatItem'], $term_ids);
+ return new \WP_REST_Response([
+ 'success' => false,
+ 'message' => 'Failed to restore icon version'
+ ], 500);
- return [
- 'items' => $items,
- 'has_more' => ($total_items > ($args['offset'] + $args['number'])),
- 'total_items' => (int)$total_items,
- 'total_pages' => ceil($total_items / $args['posts_per_page'])
- ];
- }
+ case 'merge-icon-versions':
+ $timestamps = $request->get_param('timestamps');
- protected function getUserItems(array $args):array
- {
- return [];
- }
+ if (empty($timestamps) || !is_array($timestamps)) {
+ return new \WP_REST_Response([
+ 'success' => false,
+ 'message' => 'No versions selected for merging'
+ ], 400);
+ }
- /**
- * @param array $data the $data built by buildParams
- *
- * @return array
- */
- protected function getContentTypeTaxItems(array $data):array
- {
- global $wpdb;
- $table_name = $wpdb->prefix . BASE . jvbNoBase($data['taxonomy']);
+ $timestamps = array_map('intval', $timestamps);
- // Start building the query to get just the term_ids with proper ordering
- $sql_select = "SELECT s.term_id";
- $sql_from = " FROM {$table_name} AS s";
- $sql_where = " WHERE 1=1";
- $sql_orderby = "";
- $sql_limit = "";
+ if (count($timestamps) < 2) {
+ return new \WP_REST_Response([
+ 'success' => false,
+ 'message' => 'Please select at least 2 versions to merge'
+ ], 400);
+ }
- $params = [];
+ if ($icons->mergeVersions($timestamps)) {
+ // Regenerate CSS after merge
+ IconsManager::regenerateAllCSS([$source => true]);
- // Add filters if any
- if (!empty($data['filters'])) {
- foreach ($data['filters'] as $filter_type => $filter_values) {
- if ($filter_type === 'city' && !empty($filter_values)) {
- $placeholders = implode(',', array_fill(0, count($filter_values), '%d'));
- $sql_where .= $wpdb->prepare(" AND s.city IN ($placeholders)", ...$filter_values);
- }
- // Add more filter conditions for other fields as needed
- }
- }
+ return new \WP_REST_Response([
+ 'success' => true,
+ 'message' => 'Icon versions merged successfully'
+ ]);
+ }
- // Determine ORDER BY clause - here we can use any column from the custom table
- $valid_order_columns = ['name', 'updated_at', 'established_year', 'karma'];
- $orderby_column = in_array($data['orderby'], $valid_order_columns) ? $data['orderby'] : 'name';
- $sql_orderby = " ORDER BY s." . $orderby_column;
+ return new \WP_REST_Response([
+ 'success' => false,
+ 'message' => 'Failed to merge icon versions'
+ ], 500);
- // Validate order direction
- $order_direction = strtoupper($data['order']) === 'DESC' ? 'DESC' : 'ASC';
- $sql_orderby .= " " . $order_direction;
-
- // Calculate offset for pagination
- $per_page = absint($data['posts_per_page']);
- $page = max(1, absint($data['paged']));
- $offset = ($page - 1) * $per_page;
-
- // Add pagination with prepared statement
- $sql_limit = $wpdb->prepare(" LIMIT %d OFFSET %d", $per_page, $offset);
-
- // Count query (without limit clause)
- $count_sql = "SELECT COUNT(s.term_id)" . $sql_from . $sql_where;
- $total_items = $wpdb->get_var($count_sql);
-
- // Final query with all components
- $sql = $sql_select . $sql_from . $sql_where . $sql_orderby . $sql_limit;
-
- // Execute the query
- $shop_term_ids = $wpdb->get_col($sql);
-
- // Now get the full term objects for these IDs
- $items = [];
- foreach ($shop_term_ids as $shop_term_id) {
- $items[] = $this->formatItem($shop_term_id);
- }
-
- return [
- 'items' => $items,
- 'has_more' => ($total_items > ($offset + $per_page)),
- 'total_items' => (int)$total_items,
- 'total_pages' => ceil($total_items / $per_page)
- ];
- }
-
- /**
- * @param array $args array returned by buildParams
- *
- * @return array
- */
- protected function getPostItems(array $args):array
- {
- $args['fields'] = 'ids';
- $args['post_status'] = ['draft', 'trash', 'publish'];
-
- $query = new WP_Query($args);
- $items = array_map([$this, 'formatItem'], $query->posts);
-
- $results = [
- 'items' => $items,
- 'has_more' => $query->max_num_pages > $args['paged'],
- 'total_items' => $query->found_posts,
- 'total_pages' => $query->max_num_pages
- ];
- return $results;
- }
-
- /**
- * @param int $ID the ID of the item to format
- *
- * @return array
- */
- protected function formatItem(int $ID):array
- {
- $meta = new MetaManager($ID, $this->metaType);
- $item = [
- 'id' => $ID,
- 'public' => !($this->metaType === 'post') || get_post_status($ID) === 'publish',
- ];
-
- $hierarchical = false;
- if ($this->metaType === 'term') {
- $term = get_term($ID);
- if ($term) {
- $hierarchical = is_taxonomy_hierarchical($term->taxonomy);
- }
- }
-
- foreach ($this->fields as $key => $config) {
- switch ($key) {
- case 'type':
- case 'city':
- case 'shop':
- $terms = get_the_terms($ID, BASE.$key);
- $value = [];
- if ($terms && !is_wp_error($terms)) {
- foreach ($terms as $term) {
- $value[] = htmlspecialchars_decode($term->name);
- }
- }
- $item[$key] = implode(', ', $value);
- break;
- default:
- $item[$key] = $meta->getValue($key);
- break;
- }
-
- switch ($config['type']) {
- case 'repeater':
- if (empty($item[$key]) || !is_array($item[$key])) {
- $item[$key] = '';
- } else {
- $temp = '';
- foreach ($item[$key] as $row) {
- if (is_array($row)) {
- // Format each row as [value1,value2,value3]
- $rowValues = array_values($row);
- $temp .= '[' . implode(',', $rowValues) . ']';
- } else {
- // Handle simpler cases where rows might not be arrays
- $temp .= '[' . $row . ']';
- }
- }
- $item[$key] = $temp;
- }
- break;
- case 'location':
- $item[$key] = $item[$key]['address'];
- break;
- }
- if ($hierarchical && $key === 'term_name') {
- $item[$key.'_path'] = JVB()->routes('term')->getTermPath($ID, $term->name, $term->taxonomy);
- }
- }
-
- error_log('Item: '.print_r($item, true));
- return $item;
- }
+ default:
+ return new \WP_REST_Response([
+ 'success' => false,
+ 'message' => 'Invalid action'
+ ], 400);
+ }
+ }
}
--
Gitblit v1.10.0