From a9b3b28d001941921aa70d37fdc87c758a163a44 Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Fri, 05 Jun 2026 16:47:03 +0000
Subject: [PATCH] =Some hefty changes to FeedBlock. Transitioning to loading first page in php to save on extra requests. Got a bit to do yet, but I have to work on Northeh for a bit here.
---
inc/managers/IconsManager.php | 731 +++++++++++++++++++++++++++++++++++++-------------------
1 files changed, 482 insertions(+), 249 deletions(-)
diff --git a/inc/managers/IconsManager.php b/inc/managers/IconsManager.php
index 8278763..f54120b 100644
--- a/inc/managers/IconsManager.php
+++ b/inc/managers/IconsManager.php
@@ -1,7 +1,8 @@
<?php
namespace JVBase\managers;
-use JVBase\utility\Features;
+use JVBase\registrar\Registrar;
+use JVBase\base\Site;
if (!defined('ABSPATH')) {
exit;
@@ -9,79 +10,145 @@
class IconsManager
{
- protected static ?IconsManager $instance = null;
- protected CacheManager $cache;
+ // Static array holding all source instances
+ protected static array $instances = [];
+
+ // Static storage for all custom icons across sources
+ protected static array $customIconsRegistry = [];
+
+ // Instance-specific properties
+ protected string $source;
+ protected array $icons = []; // Icons for THIS source [style => [names]]
+ protected Cache $cache;
protected string $style = 'regular';
protected array $styles = ['regular', 'bold', 'duotone', 'fill', 'light', 'thin'];
- // Custom icons registered via filter
- protected array $customIcons = [];
- protected array $usedIcons = [];
+ protected array $customIcons = []; // Custom icons for THIS source
protected array $map = [];
protected const MAX_VERSIONS = 5;
/**
- * Get singleton instance
+ * Factory method - get or create instance for a source
*/
- public static function getInstance(): IconsManager
+ public static function for(string $source = 'icons'): IconsManager
{
- if (self::$instance === null) {
- self::$instance = new self();
+ if (!isset(self::$instances[$source])) {
+ self::$instances[$source] = new self($source);
}
- return self::$instance;
+ return self::$instances[$source];
}
- private function __construct()
- {
- $this->cache = CacheManager::for('icons', WEEK_IN_SECONDS);
- $this->style = (array_key_exists('icons', JVB_SITE) && in_array(JVB_SITE['icons'], $this->styles))
- ? JVB_SITE['icons']
- : 'regular';
+ /**
+ * Constructor now takes source parameter
+ */
+ private function __construct(string $source)
+ {
+ $this->source = $source;
+ $this->cache = Cache::for('icons_' . $source, WEEK_IN_SECONDS);
+ $this->style = Site::icon();
$this->addMap();
- // Allow custom icon registration
- $this->customIcons = apply_filters('jvbRegisterCustomIcons', [
- 'syncing' => JVB_DIR .'/assets/icons/cloud-sync-thin.svg',
- 'alphabetical' => JVB_DIR.'/assets/icons/alphabetical.svg'
- ]);
+ // Register custom icons only once for all sources
+ if ($source === 'icons') {
+ $this->registerCustomIcons();
+ }
+ // Load custom icons for THIS source
+ $this->loadCustomIconsForSource();
- $this->usedIcons = get_option(BASE.'usedIcons', []);
- $this->includeIcons();
- // Track custom icons for CSS generation
- $this->trackCustomIcons();
- // Register hooks only once
- $this->registerHooks();
+ // Load stored icons for this source
+ $this->loadStoredIcons();
+
+ if (empty($this->icons)) {
+ $this->includeIcons();
+ }
+
+ // Register global hooks only once (first instance)
+ if (count(self::$instances) === 1) {
+ $this->registerGlobalHooks();
+ }
+
+ // Register instance's hooks (every instance)
+ $this->registerInstanceHooks();
}
+
+
/**
- * Ensure custom icons are tracked for CSS generation
+ * Register all custom icons (runs once)
*/
- protected function trackCustomIcons(): void
+ protected function registerCustomIcons(): void
{
- if (empty($this->customIcons)) {
- return;
- }
+ $icons = array_merge(apply_filters('jvbRegisterCustomIcons', []), ['syncing' => JVB_DIR . '/assets/icons/cloud-sync-thin.svg',
+ 'alphabetical' => JVB_DIR . '/assets/icons/alphabetical.svg']);
- foreach ($this->customIcons as $name => $path) {
- $this->trackIconUsage($name, $this->style);
- }
+ // Process and store in static property so all instances can access
+ self::$customIconsRegistry = $this->processCustomIconsArray($icons);
}
/**
- * Include icons via filter (for JS usage, etc.)
+ * Process custom icons array into source-grouped format
*/
+ protected function processCustomIconsArray(array $icons): array
+ {
+ $out = [];
+ foreach ($icons as $name => $source) {
+ if (!file_exists($source)) {
+ error_log('[IconsManager] No file exists for custom Icon: '.$name);
+ continue;
+ }
+ $out[$name] = $source;
+ }
+
+ return $out;
+ }
+
+ /**
+ * Load custom icons for this instance's source
+ */
+ protected function loadCustomIconsForSource(): void
+ {
+ $this->customIcons = self::$customIconsRegistry;
+// foreach ($this->customIcons as $name => $path) {
+// if (!isset($this->icons[$this->style])) {
+// $this->icons[$this->style] = [];
+// }
+// if (!in_array($name, $this->icons[$this->style])) {
+// $this->icons[$this->style][] = $name;
+// }
+// }
+ }
+
+ /**
+ * Load previously stored icons for this source
+ */
+ protected function loadStoredIcons(): void
+ {
+ $allIcons = get_option(BASE.'usedIcons', []);
+ $storedIcons = $allIcons[$this->source] ?? [];
+
+ // Merge stored icons with any existing icons (like custom icons)
+ foreach ($storedIcons as $style => $names) {
+ if (!isset($this->icons[$style])) {
+ $this->icons[$style] = [];
+ }
+ $this->icons[$style] = array_unique(array_merge($this->icons[$style], $names));
+ }
+ }
+
protected function includeIcons():void
{
- $icons = get_option(BASE.'includeIcons');
-
- if (!$icons) {
- $icons = [
+ $defaults = [
+ 'icons' => [
+ 'google-logo',
+ 'apple-logo',
'check-circle',
'close-circle',
+ 'faders-horizontal',
'cloud-slash',
'exclamation-mark',
'cloud-arrow-down',
+ 'caret-down',
'cloud-arrow-up',
'cloud-check',
'cloud-slash',
@@ -92,9 +159,11 @@
'share-fat',
'trash',
'star',
+ 'alphabetical',
['name' => 'star-half', 'style' => 'fill'],
['name' => 'star', 'style' => 'fill'],
- //FORMATTING
+ ],
+ 'forms' => [
'copy',
'paragraph',
'text-h-one',
@@ -120,105 +189,177 @@
'file-doc',
'file-txt',
'file-xls',
- ];
+ ],
+// 'dash' => [
+//
+// ]
+ ];
- $check = [JVB_CONTENT, JVB_TAXONOMY, JVB_USER];
- foreach ($check as $constant) {
- foreach ($constant as $key => $value) {
- if (array_key_exists('icon', $value) && !in_array($value['icon'], $icons)) {
- $icons[] = $value['icon'];
- }
- }
- }
- $icons = apply_filters('jvbIncludeIcons', $icons);
- $icons = $this->maybePrefixIcons($icons);
- update_option(BASE.'includeIcons', $icons);
+
+ // Add icons from content/taxonomy/user configs (like old behavior)
+ $configIcons = $this->getIconsFromConfigs();
+ if (!empty($configIcons)) {
+ $defaults['icons'] = array_merge($defaults['icons'], $configIcons);
}
- // Ensure icons are in the correct format (handle legacy data)
- if (!$this->isIconsArrayPrefixed($icons)) {
- $icons = $this->maybePrefixIcons($icons);
- update_option(BASE.'includeIcons', $icons);
+ // Allow filtering per source (extensibility)
+ $icons = apply_filters("jvbIncludeIcons_{$this->source}", $defaults[$this->source] ?? []);
+
+ // Also allow filtering all sources at once
+ $allIcons = apply_filters('jvbIncludeIcons', $defaults);
+ if (isset($allIcons[$this->source])) {
+ $icons = array_merge($icons, $allIcons[$this->source]);
}
-
- $additional = apply_filters('jvbIncludeIcons', []);
- if (!empty($additional)) {
- $additional = $this->maybePrefixIcons($additional);
- $merged = $this->mergeUsedIcons($icons, $additional);
-
- if ($icons != $merged) {
- update_option(BASE.'includeIcons', $merged);
- $icons = $merged;
- }
- }
-
- foreach ($icons as $style => $theIcons) {
- foreach($theIcons as $icon) {
- $this->trackIconUsage($icon, $style);
- }
+ if (!empty($icons)) {
+ $this->include($icons);
}
}
/**
- * Check if icons array is in the prefixed format [style => [icons]]
+ * Get icons from Registrar instances
+ *
*/
- protected function isIconsArrayPrefixed(array $icons): bool
+ protected function getIconsFromConfigs(): array
{
- if (empty($icons)) {
- return true;
+ $icons = [];
+ $registered = Registrar::getRegistered();
+
+ foreach ($registered as $type) {
+ $registrar = Registrar::getInstance($type);
+ $icons[] = $registrar->getIcon();
}
- // Check if first key is a valid style name
- $first_key = array_key_first($icons);
- if (!in_array($first_key, $this->styles)) {
- return false;
- }
- // Check if first value is an array
- return is_array($icons[$first_key]);
+ return array_unique(array_filter($icons));
}
- protected function maybePrefixIcons(array $icons):array
+ /**
+ * Public method to include icons in this source
+ */
+ public function include(array $icons): self
{
- $out = [];
- foreach ($icons as $icon) {
- if (is_array($icon) && array_key_exists('style', $icon)) {
- if (!array_key_exists($icon['style'], $out)) {
- $out[$icon['style']] = [];
- }
- if (!in_array($icon['name'], $out[$icon['style']])) {
- $out[$icon['style']][] = $icon['name'];
- }
- } elseif(is_array($icon)) {
- $icon = $icon['name'];
+ $processed = $this->processIconArray($icons);
+ $changed = false;
+
+ foreach ($processed as $style => $names) {
+ if (!isset($this->icons[$style])) {
+ $this->icons[$style] = [];
}
- if (!is_array($icon)) {
- if (!array_key_exists($this->style, $out)) {
- $out[$this->style] = [];
+
+ foreach ($names as $name) {
+ // Skip if already in this source
+ if (in_array($name, $this->icons[$style])) {
+ continue;
}
- if (!in_array($icon, $out[$this->style])){
- $out[$this->style][] = $icon;
+
+ // Skip if already in main 'icons' source
+ if ($this->iconExistsInMainSource($name, $style)) {
+ error_log("[IconsManager] Skipping '{$name}' in '{$this->source}' - already in 'icons' source");
+ continue;
}
+
+ $this->icons[$style][] = $name;
+ $changed = true;
}
}
+
+ // Only save if something actually changed
+ if ($changed) {
+ $this->saveIcons();
+ }
+
+ return $this;
+ }
+
+ /**
+ * Process icon array into [style => [names]] format
+ */
+ protected function processIconArray(array $icons): array
+ {
+ $out = [];
+
+ foreach ($icons as $icon) {
+ if (is_array($icon) && isset($icon['style'])) {
+ $style = $icon['style'];
+ $name = $icon['name'];
+ } else {
+ $style = $this->style;
+ $name = is_array($icon) ? $icon['name'] : $icon;
+ }
+
+ if (!isset($out[$style])) {
+ $out[$style] = [];
+ }
+
+ if (!in_array($name, $out[$style])) {
+ $out[$style][] = $name;
+ }
+ }
+
return $out;
}
- protected function addMap():void
+ /**
+ * Save all icons across all instances
+ */
+ protected function saveIcons(): void
+ {
+ $allIcons = [];
+ foreach (self::$instances as $source => $instance) {
+ $allIcons[$source] = $instance->icons;
+ }
+
+ update_option(BASE.'usedIcons', $allIcons);
+
+ // Track WHICH source needs updating
+ $needsUpdate = get_option(BASE.'icons_needs_update', []);
+ if (!is_array($needsUpdate)) {
+ $needsUpdate = [];
+ }
+ $needsUpdate[$this->source] = true;
+ update_option(BASE.'icons_needs_update', $needsUpdate);
+ }
+
+ /**
+ * Check if icon exists in other sources
+ */
+ protected function checkDuplicateAcrossInstances(string $name, string $style): void
+ {
+ $foundIn = [];
+
+ foreach (self::$instances as $source => $instance) {
+ if (isset($instance->icons[$style]) && in_array($name, $instance->icons[$style])) {
+ $foundIn[] = $source;
+ }
+ }
+
+ if (count($foundIn) > 1) {
+ error_log(sprintf(
+ '[IconsManager] Warning: Icon "%s" (%s) is registered in multiple sources: %s. Consider consolidating to avoid duplicate CSS output.',
+ $name,
+ $style,
+ implode(', ', $foundIn)
+ ));
+ }
+ }
+
+ protected function addMap(): void
{
$map = get_option(BASE.'iconMap');
if (!$map) {
- $map = [];
- if (Features::forSite()->has('referrals')){
+ $map = [
+ 'seo' => 'robot'
+ ];
+ if (Site::has('referrals')) {
$map['referrals'] = 'hand-heart';
}
- if (Features::forSite()->has('dashboard')){
+ if (Site::has('dashboard')) {
$map['dash'] = 'door';
}
- if (Features::forSite()->has('magicLink')){
+ if (Site::has('magicLink')) {
$map['magicLink'] = 'magic-wand';
}
- if (Features::hasAnyIntegration()) {
+ if (Site::hasAnyIntegration()) {
$map['integrations'] = 'plugs-connected';
}
update_option(BASE.'iconMap', $map);
@@ -228,44 +369,128 @@
}
/**
- * Register WordPress hooks
+ * Register global hooks (only once)
*/
- protected function registerHooks(): void
+ protected function registerGlobalHooks(): void
{
- add_action('init', [$this, 'includeIcons'], 1);
- add_action('init', [$this, 'checkCSS'], 10);
- add_action('wp_enqueue_scripts', [$this, 'enqueueIconStyles']);
+ add_action('wp_loaded', [self::class, 'checkCSS']);
+ add_action('shutdown', [self::class, 'checkCSS']);
+ }
+
+ /**
+ * Register instance-specific hooks (every instance)
+ */
+ protected function registerInstanceHooks(): void
+ {
+ // Register this source's stylesheet
+ add_action('init', [$this, 'registerStyle'], 11);
+
+ // Auto-enqueue base icons on front-end
+ if ($this->source === 'icons') {
+ add_action('wp_enqueue_scripts', [$this, 'enqueueIconStyles']);
+ }
+
+ // Auto-enqueue all in admin
add_action('admin_enqueue_scripts', [$this, 'enqueueIconStyles']);
}
- public function checkCSS():void
+ public function enqueueIconStyles():void
{
-// update_option(BASE.'icons_needs_update', true);
- if (get_option(BASE.'icons_needs_update', false)) {
- error_log('Regenerating CSS');
+// if (file_exists(JVB_CHILD_URL . "assets/css/{$this->source}.css")){
+ wp_enqueue_style('jvb-icons-'.$this->source);
+// }
+
+ }
+
+ public static function checkCSS(): void
+ {
+ $needsUpdate = get_option(BASE.'icons_needs_update', []);
+ if (!empty($needsUpdate)) {
+ error_log('Regenerating CSS for sources: ' . implode(', ', array_keys($needsUpdate)));
delete_option(BASE.'icons_needs_update');
- $this->regenerateCSS();
+ self::regenerateAllCSS($needsUpdate);
}
}
- protected function regenerateCSS(): void
+ public static function regenerateAllCSS(array $sourcesToUpdate = []): void
{
error_log('[IconsManager]:regenerateCSS');
- $css = $this->generateIconCSS();
- $css_path = JVB_CHILD_DIR.'/assets/css/';
- if (!file_exists($css_path)) {
- wp_mkdir_p($css_path);
+ $css_dir = JVB_CHILD_DIR.'/assets/css/';
+
+ if (!file_exists($css_dir)) {
+ wp_mkdir_p($css_dir);
}
- $css_path .= '/icons.css';
+ // Load all icons from database option
+ $allIcons = get_option(BASE.'usedIcons', []);
- // Archive current version before overwriting
- $this->archiveCurrentVersion($css);
+ // If no specific sources provided, regenerate all
+ if (empty($sourcesToUpdate)) {
+ $sourcesToUpdate = array_fill_keys(array_keys($allIcons), true);
+ }
- if (file_put_contents($css_path, $css) !== false) {
- CacheManager::updateTimestamp('icons');
- } else {
- error_log('[IconsManager]Could not write css.');
+ // Generate CSS for each source that needs it
+ foreach ($sourcesToUpdate as $source => $needsUpdate) {
+ if (!$needsUpdate || !isset($allIcons[$source])) {
+ continue;
+ }
+
+ // Get or create instance for this source
+ $instance = self::for($source);
+
+ // Temporarily set icons from database
+ $originalIcons = $instance->icons;
+ $instance->icons = $allIcons[$source];
+
+ $css = $instance->generateIconCSS();
+ $css_path = $css_dir . $source . '.css';
+
+ $instance->archiveCurrentVersion($css);
+
+ if (file_put_contents($css_path, $css) !== false) {
+ Cache::touch('icons_' . $source);
+ error_log("[IconsManager] Updated {$source}.css");
+ } else {
+ error_log("[IconsManager] Could not write {$source}.css");
+ }
+
+ // Restore original icons
+ $instance->icons = $originalIcons;
+ }
+ }
+
+ protected function regenerateCSS(array $sourcesToUpdate = []): void
+ {
+ error_log('[IconsManager]:regenerateCSS');
+ $css_dir = JVB_CHILD_DIR.'/assets/css/';
+
+ if (!file_exists($css_dir)) {
+ wp_mkdir_p($css_dir);
+ }
+
+ // If no specific sources provided, regenerate all
+ if (empty($sourcesToUpdate)) {
+ $sourcesToUpdate = array_fill_keys(array_keys(self::$instances), true);
+ }
+
+ // Generate CSS only for sources that need it
+ foreach (self::$instances as $source => $instance) {
+ if (!isset($sourcesToUpdate[$source])) {
+ continue; // Skip this source
+ }
+
+ $css = $instance->generateIconCSS();
+ $css_path = $css_dir . $source . '.css';
+
+ // Archive current version before overwriting
+ $instance->archiveCurrentVersion($css);
+
+ if (file_put_contents($css_path, $css) !== false) {
+ Cache::touch('icons_' . $source);
+ error_log("[IconsManager] Updated {$source}.css");
+ } else {
+ error_log("[IconsManager] Could not write {$source}.css");
+ }
}
}
@@ -294,10 +519,14 @@
* - 'size' => 24 (for custom sizing via inline style)
* @return string HTML icon element
*/
- public function getIcon(string $name, array $options = []): string
+ public function get(string $name, array $options = []): string
{
- $style = array_key_exists('style', $options) ? $options['style'] :$this->style;
- $name = (array_key_exists($name, $this->map)) ? $this->map[$name] : $name;
+ if (empty($name)) {
+ //No icon requested
+ return '';
+ }
+ $style = $options['style'] ?? $this->style;
+ $name = $this->map[$name] ?? $name;
// Validate icon exists
if (!$this->iconExists($name, $style)) {
@@ -305,56 +534,51 @@
return '';
}
+ // Track usage - only if not already tracked
+ if (!isset($this->icons[$style])) {
+ $this->icons[$style] = [];
+ }
+ if (!in_array($name, $this->icons[$style])) {
+ // Check if it's already in main source (for non-main sources)
+ if ($this->iconExistsInMainSource($name, $style)) {
+ // Don't add to this source, but still render the icon
+ // The CSS from icons.css will handle it
+ } else {
+ // Add to this source
+ $this->icons[$style][] = $name;
+ $this->checkDuplicateAcrossInstances($name, $style);
+ $this->saveIcons();
+ }
+ }
- // Track icon usage
- $this->trackIconUsage($name, $style);
-
- $styleClass = ($style !== $this->style) ? '-'.substr($style, 0,2) : '';
- // Build classes
+ // Build icon HTML (same as before)
+ $styleClass = ($style !== $this->style) ? '-'.substr($style, 0, 2) : '';
$classes = ['icon', 'icon-' . $name.$styleClass];
- if (!empty($options['class'])) {
+
+ if (isset($options['class'])) {
$classes[] = $options['class'];
}
+ $attrs = ['class' => implode(' ', $classes)];
- $attrs = ['class="' . esc_attr(implode(' ', $classes)) . '"'];
- $attrs[] = 'aria-hidden="true"';
-
-
-
- return '<i ' . implode(' ', $attrs) . '></i>';
- }
-
- /**
- * Track icon usage for CSS generation
- */
- protected function trackIconUsage(string $name, string $style): void
- {
- $needsUpdate = false;
-
- if (!array_key_exists($style, $this->usedIcons)) {
- $this->usedIcons[$style] = [];
- $needsUpdate = true;
+ if (isset($options['label'])) {
+ $attrs['aria-label'] = esc_attr($options['label']);
+ $attrs['role'] = 'img';
+ } elseif (isset($options['decorative']) && $options['decorative']) {
+ $attrs['aria-hidden'] = 'true';
}
- if (!in_array($name, $this->usedIcons[$style])) {
- $this->usedIcons[$style][] = $name;
- $needsUpdate = true;
+ if (isset($options['size'])) {
+ $attrs['style'] = sprintf('--icon-size: %dpx;', absint($options['size']));
}
- if ($needsUpdate) {
- // Merge with existing option to never lose icons
- $existing = get_option(BASE.'usedIcons', []);
- $merged = $this->mergeUsedIcons($existing, $this->usedIcons);
- update_option(BASE.'usedIcons', $merged);
-
- // Flag for regeneration on next init
- update_option(BASE.'icons_needs_update', true);
-
- // Clear cache
- $this->cache->delete('icon_styles_css');
+ $attr_string = '';
+ foreach ($attrs as $key => $value) {
+ $attr_string .= sprintf(' %s="%s"', $key, $value);
}
+
+ return sprintf('<i%s></i>', $attr_string);
}
/**
@@ -401,7 +625,7 @@
/**
* Get raw SVG content for CSS mask-image
*/
- protected function getRawSvg(string $name, ?string $style = null): ?string
+ public function getRawSvg(string $name, ?string $style = null): ?string
{
if (!$style) {
$style = $this->style;
@@ -420,22 +644,17 @@
// Clean up SVG for CSS usage
$svg = preg_replace("/([\n\t]+)/", ' ', $svg);
$svg = preg_replace('/>\s*</', '><', $svg);
- $svg = trim($svg);
-
- return $svg;
+ return trim($svg);
}
-
- /**
- * Enqueue icon styles via REST endpoint
- */
- public function enqueueIconStyles(): void
+ public function registerStyle(): void
{
- $timestamp = CacheManager::getTimestamp('icons');
+ $timestamp = Cache::lastModified('icons_' . $this->source);
+ $handle = 'jvb-icons-' . $this->source;
- wp_enqueue_style(
- 'jvb-icons',
- JVB_CHILD_URL.'assets/css/icons.css',
+ wp_register_style(
+ $handle,
+ JVB_CHILD_URL . "assets/css/{$this->source}.css",
[],
$timestamp
);
@@ -447,48 +666,29 @@
protected function generateIconCSS(): string
{
$css = '';
- $this->mergeUsedIcons();
- foreach ($this->usedIcons as $style => $icons) {
- $styleClass = ($style !== $this->style) ? '-'.substr($style, 0,2) : '';
- foreach ($icons as $icon) {
+ foreach ($this->icons as $style => $names) {
+ $styleClass = ($style !== $this->style) ? '-'.substr($style, 0, 2) : '';
+ foreach ($names as $icon) {
$svg = $this->getEncodedSVG($icon, $style);
if ($svg !== '') {
+ if ($icon === 'caret-down') {
+ $css .= 'details summary::after,';
+ } elseif ($icon === 'faders-horizontal') {
+ $css .= 'details.all-filters summary::after,';
+ } elseif ($icon === 'link') {
+ $css .= 'input[type=url],';
+ } elseif ($icon === apply_filters('jvbSeparatorLogo', 'logo')) {
+ $css .= 'hr.logo::before,';
+ }
$css .= ".icon-{$icon}{$styleClass}{";
$css .= "--icon:url('data:image/svg+xml;base64,{$svg}');";
$css .= "}";
}
}
}
- return $this->minifyCss($css);
- }
- protected function mergeUsedIcons(array|bool $oldIcons = true, array|bool $newIcons = true):array
- {
- $set = false;
- if ($oldIcons === true) {
- $oldIcons = $this->usedIcons;
- $set = true;
- }
- if ($newIcons === true) {
- $history = $this->getVersionHistory();
- $newIcons = (count($history) > 0) ? $history[0]['iconList'] : [];
- }
- foreach ($newIcons as $style => $icons) {
- if (!isset($oldIcons[$style])) {
- //Style doesn't exist in previous set, add the whole thing
- $oldIcons[$style] = $icons;
- } else {
- $oldIcons[$style] = array_unique(
- array_merge($oldIcons[$style], $icons)
- );
- }
- }
- if ($set) {
- $this->usedIcons = $oldIcons;
- update_option(BASE.'usedIcons', $oldIcons);
- }
- return $oldIcons;
+ return $this->minifyCss($css);
}
protected function minifyCSS(string $css): string
@@ -502,31 +702,40 @@
return trim($css);
}
- public function getCSSIcon(string $icon, ?string $style=null):string
+
+ public function getCSSIcon(string $icon, ?string $style = null): string
{
if (!$style) {
$style = $this->style;
}
+
+ $icon = $this->map[$icon] ?? $icon;
+
+ // Validate icon exists
+ if (!$this->iconExists($icon, $style)) {
+ error_log('[IconsManager] Icon not found: ' . $icon);
+ return '';
+ }
$svg = $this->getEncodedSVG($icon, $style);
if ($svg !== '') {
return "data:image/svg+xml;base64,{$svg}";
}
return '';
}
- public function getEncodedSVG(string $icon, ?string $style = null):string
+
+ public function getEncodedSVG(string $icon, ?string $style = null): string
{
if (!$style) {
$style = $this->style;
}
return $this->cache->remember($style.$icon,
- function () use ($icon, $style) {
- $svg = $this->getRawSvg($icon, $style);
- if ($svg) {
- return base64_encode($svg);
- }
- return '';
- });
-
+ function () use ($icon, $style) {
+ $svg = $this->getRawSvg($icon, $style);
+ if ($svg) {
+ return base64_encode($svg);
+ }
+ return '';
+ });
}
/**
@@ -534,12 +743,14 @@
*/
public function clearIconCache(): void
{
- delete_option(BASE . 'icon_usage_list'); // Clear DB option
+ delete_option(BASE . 'icon_usage_list'); // Legacy
delete_option(BASE.'usedIcons');
- delete_option(BASE.'includeIcons');
delete_option(BASE.'iconMap');
- $this->cache->delete('icon_styles_css');
- CacheManager::updateTimestamp('icons');
+
+ // Clear cache for all sources
+ foreach (self::$instances as $source => $instance) {
+ $instance->cache->forget('icon_styles_css');
+ }
}
protected function archiveCurrentVersion(string $css): void
@@ -547,13 +758,13 @@
$history = $this->getVersionHistory();
$icon_count = 0;
- foreach ($this->usedIcons as $style => $icons) {
- $icon_count += count($icons);
+ foreach ($this->icons as $style => $names) {
+ $icon_count += count($names);
}
$newEntry = [
'css' => $css,
- 'iconList' => $this->usedIcons,
+ 'iconList' => $this->icons,
'timestamp' => time(),
'icon_count' => $icon_count,
'size' => strlen($css),
@@ -566,12 +777,12 @@
$history = array_slice($history, 0, self::MAX_VERSIONS);
}
- update_option(BASE.'icon_css_history', $history);
+ update_option(BASE.'icon_css_history_' . $this->source, $history);
}
public function getVersionHistory(): array
{
- return get_option(BASE.'icon_css_history', []);
+ return get_option(BASE.'icon_css_history_' . $this->source, []);
}
public function restoreVersion(int $timestamp): bool
@@ -580,7 +791,7 @@
foreach ($history as $entry) {
if ($entry['timestamp'] === $timestamp) {
- $css_path = JVB_DIR . '/assets/css/icons.css';
+ $css_path = JVB_CHILD_DIR . '/assets/css/' . $this->source . '.css';
// Archive current before restoring
$current_css = file_get_contents($css_path);
@@ -590,9 +801,9 @@
// Restore the version
if (file_put_contents($css_path, $entry['css']) !== false) {
- $this->usedIcons = $entry['iconList'];
- update_option(BASE.'usedIcons', $this->usedIcons);
- CacheManager::updateTimestamp('icons');
+ $this->icons = $entry['iconList'];
+ $this->saveIcons();
+ Cache::touch('icons_' . $this->source);
return true;
}
@@ -600,15 +811,20 @@
}
}
- error_log("[IconsManager] Version {$timestamp} not found in history");
+ error_log("[IconsManager] Version {$timestamp} not found in history for source {$this->source}");
return false;
}
public function forceRefresh(): void
{
$this->clearIconCache();
- update_option(BASE.'icons_needs_update', true);
- CacheManager::updateTimestamp('icons');
+ $needsUpdate = get_option(BASE.'icons_needs_update', []);
+ if (!is_array($needsUpdate)) {
+ $needsUpdate = [];
+ }
+ $needsUpdate[$this->source] = true;
+ update_option(BASE.'icons_needs_update', $needsUpdate);
+ Cache::touch('icons_' . $this->source);
}
public function mergeVersions(array $timestamps): bool
@@ -617,8 +833,9 @@
return false;
}
- $history = get_option(BASE.'icon_css_history', []);
+ $history = get_option(BASE.'icon_css_history_' . $this->source, []);
$merged_icons = [];
+
// Collect icons from selected versions
foreach ($history as $entry) {
if (in_array($entry['timestamp'], $timestamps)) {
@@ -640,18 +857,34 @@
}
// Archive current version
- $current_css = file_get_contents(JVB_DIR . '/assets/css/icons.css');
+ $current_css = file_get_contents(JVB_CHILD_DIR . '/assets/css/' . $this->source . '.css');
if ($current_css !== false) {
$this->archiveCurrentVersion($current_css);
}
// Update used icons and regenerate
- $this->usedIcons = $merged_icons;
- update_option(BASE.'usedIcons', $this->usedIcons);
-
- // Force regeneration
- $this->regenerateCSS();
+ $this->icons = $merged_icons;
+ $this->saveIcons();
return true;
}
+
+ /**
+ * Check if icon already exists in the main 'icons' source
+ */
+ protected function iconExistsInMainSource(string $name, string $style): bool
+ {
+ // If this IS the main source, no need to check
+ if ($this->source === 'icons') {
+ return false;
+ }
+
+ // Check if main icons source exists
+ if (!isset(self::$instances['icons'])) {
+ return false;
+ }
+
+ $mainIcons = self::$instances['icons']->icons;
+ return isset($mainIcons[$style]) && in_array($name, $mainIcons[$style]);
+ }
}
--
Gitblit v1.10.0