From 3d25ad7de4fdbb3eba2cde2a62422e6be5d79a0a Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Tue, 25 Aug 2026 22:57:22 +0000
Subject: [PATCH] =It's been a minute. I went through the Routes and associated Managers and ensured they played together well. Reworked the Cache.php, and I think I caught all the references. Moving away from JVBase() root class, to individuall classes that are Instanced. Double checked for the ABSPATH check in every file, and added index.php to every directory that didn't already have it. Also still working on the MenuBlock to work with WooCommerce for now for Northeh
---
inc/rest/routes/AdminRoutes.php | 747 ++++++++++-----------------------------------------------
1 files changed, 136 insertions(+), 611 deletions(-)
diff --git a/inc/rest/routes/AdminRoutes.php b/inc/rest/routes/AdminRoutes.php
index a32211c..c69a32e 100644
--- a/inc/rest/routes/AdminRoutes.php
+++ b/inc/rest/routes/AdminRoutes.php
@@ -1,9 +1,13 @@
<?php
namespace JVBase\rest\routes;
+use JVBase\Instance;
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,61 +17,35 @@
exit; // Exit if accessed directly
}
-class AdminRoutes extends RestRouteManager
+class AdminRoutes extends Rest
{
- protected array $fields;
- protected $meta;
- protected string $metaType;
- protected string $content;
+ use Instance;
public function __construct()
{
- $this->cache_name = 'itsme';
+// $this->cacheName = 'itsme';
parent::__construct();
- $this->action = 'itsme';
+// $this->cache = Cache::for($this->cacheName, null, $this->cacheTtl);
}
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,590 +69,137 @@
);
}
- /**
- * @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'
- ]);
- }
+ /**
+ * Handle cache-related actions
+ */
+ public function handleCacheAction(\WP_REST_Request $request): \WP_REST_Response
+ {
+ $action = sanitize_text_field($request->get_param('action'));
- $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));
+ switch ($action) {
+ case 'flush-all':
+ $total = Cache::flushAll();
+ return new \WP_REST_Response([
+ 'success' => true,
+ 'message' => $total.' caches flushed successfully'
+ ]);
- 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];
+ 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);
+ }
- 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']);
+ Cache::for($group)?->flush();
- //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));
+ return new \WP_REST_Response([
+ 'success' => true,
+ 'message' => "Cache group '{$group}' flushed successfully"
+ ]);
- } 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
- *
- * @return array
- */
- protected function checkFilters(array $filters)
- {
- global $karma;
- $out = [];
- foreach ($filters as $type => $value) {
- if (!array_key_exists($type, $karma)) {
- continue;
- }
- $out[$type] = jvbSanitizeIDList($value);
- }
- 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,
- ];
- }
-
- 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,
- };
- }
-
- /**
- * @param WP_REST_Request $request The REST Request
- *
- * @return WP_REST_Response
- */
- public function getItems(WP_REST_Request $request):WP_REST_Response
- {
-
- $args = $this->buildParams($request);
- $key = $this->cache->generateKey($args);
-
- $cache = $this->cache->get($key);
- if ($cache) {
- return new WP_REST_Response($cache);
- }
-
- $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);
-
- return [
- 'items' => $items,
- 'has_more' => $query->max_num_pages > $args['paged'],
- 'total_items' => $query->found_posts,
- 'total_pages' => $query->max_num_pages
- ];
- }
-
- /**
- * @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, html_entity_decode($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