Improvement: Settings page (Tools > Easy Labels) now always renders in the WordPress site language — the plugin_language option now controls only the operational interface (content labels, filter bar, notes, modals, dashboard widgets)
Fix: Removed redundant switch_to_locale() call in prepare_view_data() — post-type names on the settings page now correctly follow the WordPress site locale
Improvement: Updated Language tab description and i18n strings to accurately reflect the new two-locale behaviour (settings = WP locale, operational UI = plugin language)
UI: Several layout and visual improvements to the settings page — all main tab containers (support, backup, language, permissions, post-types) set to full-width layout; post-types grid updated to a 3-column layout; intro card headers and descriptions standardised for consistent two-line appearance across all tabs
UI: Label and widget editor cards are now collapsible — each card has a toggle arrow button next to the delete button; existing cards load collapsed by default, newly created cards start open
UI: Post-type badges now appear to the right of the coloured label badge in the collapsed label card header, showing which content types the label is assigned to; badges update dynamically when checkboxes are changed
UI: Widget editor card collapsed header now shows the configured content type and visualization type as info badges; badges update dynamically when the respective selects are changed
UX: Clicking anywhere on the label or widget card header bar now toggles the collapsed state (the arrow button still works as before); cursor: pointer added to header bars for clarity
UI: All card/section hover effects across the settings page now use a consistent style — base border standardised to 1px solid #c3c4c7 and hover border to 1px solid #2271b1 with box-shadow: 0 4px 12px rgba(0,0,0,0.08); removed transform: translateY animations and non-standard border thicknesses/colours from post-type cards, language cards, support cards and setting sections
Fix: Extended phpcs:disable/enable block in redshape-easy-labels.php to correctly suppress NonceVerification.Recommended across the multi-line $is_settings_page expression (reading-only $_GET[‘page’] to determine admin context)
Fix: Renamed template variables in admin-page.php to use the $redshape_easylabels_ plugin prefix, resolving PrefixAllGlobals PHPCS warnings
Improvement: Labels created via the quick-create modal (from post list or meta box) are now automatically configured to be visible only on the current content type (post type), instead of all types; the modal info text updated accordingly
Version bump: 1.5.0 → 1.5.1
1.5.0
Maintenance: Full sync with WordPress.org SVN repository — all plugin files correctly added and distributed
Version bump: 1.4.4 → 1.5.0
1.4.4
Maintenance: Full sync with WordPress.org repository — no code changes, version bump to ensure all files are correctly distributed
Version bump: 1.4.3 → 1.4.4
1.4.3
Fix: Fatal “Class not found” error when plugin is loaded with missing files after a partial deploy — the previous fix (1.4.2) placed the file check inside class-redshape-easylabels.php which caused an early return that left Redshape_Easylabels undefined, then plugins_loaded still tried to instantiate it and crashed; check is now in the main entry file redshape-easy-labels.php so if any file is missing the plugins_loaded hook is never registered — WordPress shows a clear admin notice listing the missing files
Version bump: 1.4.2 → 1.4.3
1.4.2
Fix: Fatal error on activation when any core class file is missing from a partial deploy (class-redshape-easylabels-helpers.php, etc.) — class-redshape-easylabels.php now checks all 10 required files with file_exists() before loading them; if any are missing a clear admin notice lists them and the plugin exits cleanly instead of crashing WordPress
Fix: PHPCS NonPrefixedVariableFound warning — removed global variable $_redshape_easylabels_lang_gen in redshape-easy-labels.php, replaced with an inline file_exists() call
Version bump: 1.4.1 → 1.4.2
1.4.1
Fix: Fatal error on activation/update when class-redshape-easylabels-language-generator.php was missing from a partial deploy — require_once is now conditional on file_exists(); all call-sites guarded with class_exists(‘Redshape_Easylabels_Language_Generator’)
Fix: Data loss after saving settings — save_settings() accessed $current_options[‘default_labels’] and $current_options[‘role_settings’] without isset; on PHP 8 a missing key returns null, causing update_option to overwrite labels and widgets with null/empty values; replaced with defensive isset reads and added automatic migration from the legacy labels key to default_labels
Fix: Post type selector in “Add New Label” showed only post and page — enqueue_settings_page_scripts() read $settings[‘role_settings’][‘enabled_post_types’] which is always null because get_settings() flattens role_settings keys to root level; corrected to read $settings[‘enabled_post_types’] directly
Fix: Dropdown close in post editor / Gutenberg — replaced jQuery $(document).on(‘click’) bubbling (ineffective inside Gutenberg’s iframe) and capture-phase attempt with a transparent full-screen backdrop div (z-index 99998) that intercepts any click outside the dropdown; added centralised closeAllDropdowns() helper used by all 8 close paths
Fix: Missing ‘Label name is required’ translation key in 8 non-Italian locales (fr_FR, de_DE, es_ES, ru_RU, zh_CN, ja_JP, ko_KR, hi_IN) — JS validation error was always displayed in English regardless of plugin language setting
New: Added “Check for updates” link in the plugin description row on the Plugins page — clicking it triggers a WordPress update check (update-core.php?force-check=1) without leaving the admin
Code: Main Redshape_Easylabels class is now a lean coordinator that instantiates sub-classes and wires up shared hooks
Fix: Corrected hardcoded Italian strings in admin.js (Clicca per rimuovere, Aggiungi etichetta, Errore critico. Ricarica la pagina., Errore di elaborazione risposta) — all now routed through the __() JS helper using English keys; translations added for all 10 supported languages
Improvement: Migrated translation system from hardcoded PHP arrays to standard WordPress .po/.mo files — now fully compatible with Loco Translate, GlotPress, WPML, and WP-CLI i18n tools
New: Added Redshape_Easylabels_Language_Generator class that builds .po and .mo files from the existing translation data (pure PHP, no external dependencies)
New: Added bin/generate-languages.php CLI script to regenerate all language files from the command line during development
New: load_textdomain() now loads the correct .mo based on the per-plugin language setting (plugin_language option), independently of the WordPress site locale
New: Language files are automatically regenerated on plugin activation and lazily on first use if missing
Code: Removed dead-code duplicate class-redshape-easylabels-content-i18n.php (~2300 lines, ~70% identical to the main i18n class, never loaded, using a stale option key content_labels_options)
Improvement: Migrated label storage from a single serialized array (_content_labels) to one post-meta row per label (_content_label) — meta queries now use exact-match = instead of LIKE ‘%…%’, enabling MySQL index usage
New: maybe_upgrade_storage() one-time migration function converts existing data transparently on first admin load after update
New: Added get_post_label_ids() and set_post_label_ids() private helpers to centralise all label read/write operations
Fix: All filter_posts_by_label(), add_quick_filter_bar(), and counter queries updated to use the new storage format
Fix: Cache class (Redshape_Easylabels_Cache) updated to use the new meta key and exact-match queries
Fix: uninstall.php now cleans up both _content_label (new) and _content_labels (legacy) meta keys
Code: Separated logic from template in admin-page.php — all DB reads, locale switching, wp_localize_script, and static data arrays extracted into a new prepare_view_data() private method in Redshape_Easylabels_Settings; the template is now pure display HTML/PHP with no business logic
Fix: Eliminated duplicate column hook registrations — only manage_{$pt}_posts_columns / manage_{$pt}_posts_custom_column are now registered (fires for all post types); the redundant manage_{$pt}s_columns / manage_{$pt}s_custom_column hooks that caused double-fire on built-in types have been removed, along with the workaround guards they required
Performance: Replaced per-label COUNT queries with a single GROUP BY meta_value query in Redshape_Easylabels_Helpers::get_label_counts_for_post_type() — used by both the AJAX filter-count endpoint and the dashboard widget renderer; eliminates the N-query loop that previously ran one SELECT COUNT(DISTINCT) per label; no maybe_unserialize() needed since _content_label stores flat string values
Code: Extracted ~65 lines of inline JS (bulk label selector) from a PHP string with manual ‘ escaping into a proper file assets/js/admin-bulk-actions.js; translated alert strings passed via wp_localize_script as redshapeEasylabelsBulk.i18n
Fix: redshape_easylabels_cl_e() docblock now explicitly states it strips HTML; added companion redshape_easylabels_cl_html_e() that passes the translated string through wp_kses() with a minimal inline-tag allowlist (strong, em, code, span, br, a) so legitimate markup in translations is preserved instead of silently entity-encoded
Fix: Redshape_Easylabels_Cache::invalidate_all() — replaced the version-number trick (broken without persistent object cache: each PHP process starts with empty memory, so the counter was never shared between requests) with wp_cache_flush_group() (WP 6.1+ / Redis / Memcached) plus a per-label fallback for standard setups; also removed the cache_version lookup from generate_cache_key() which added an extra wp_cache_get() on every cache read/write
Fix: initializeInlineLabels() in admin.js — replaced setTimeout retry polling (two blind delays of 300–500 ms) with a MutationObserver that watches document.body and fires exactly once when .wp-list-table .row-title appears, then disconnects; eliminates missed renders and unnecessary CPU wake-ups
Fix: redshape_easylabels_deactivate() was empty; now calls Redshape_Easylabels_Cache::invalidate_all() on deactivation so stale label counts don’t persist in Redis / Memcached between sessions
Fix: get_cache_stats() was reading from the wrong option key (labels instead of default_labels) — always returned total_labels: 0; removed stale cache_version entry from the returned array (that key was deleted earlier in 1.4.0); loop now uses the associative key as label ID instead of $label[‘id’]
Fix: ajax_add_label_to_post() now validates that the requested label ID exists in the plugin configuration before writing to post meta, preventing arbitrary strings from being stored via AJAX by any user with edit_post capability
Fix: get_all_post_labels() SQL query fetched all _content_label rows across the entire database with no post-type filter; query now JOINs wp_posts and filters by post_type, significantly reducing data volume on multi-post-type sites
Fix: Two hardcoded Italian __() keys (‘Il nome dell’etichetta è obbligatorio’) in the Quick Create Label handlers in admin.js replaced with the existing English key ‘Label name is required’ so all 10 locales translate correctly
Fix: DOMNodeInserted event (deprecated, removed in Chrome 124+) replaced with a MutationObserver that watches for new .content-label-badge elements and adds the draggable class on insertion
Fix: initializeDragAndDrop() and initFilterDragAndDrop() were started via 4 chained setTimeout calls (500 ms, 800 ms, 1500 ms, 3000 ms + $(window).on(‘load’)); replaced with a single $(window).on(‘load’) for the sortable initializer and a MutationObserver for the filter container — eliminates blind waits and missed renders
Code: Corrected @since 1.4.1 tag to @since 1.4.0 in all 9 class file docblocks (coordinator, helpers, ajax, settings, admin-columns, bulk-actions, filter-bar, meta-box, dashboard-widget)
Code: Removed redundant !defined(‘ABSPATH’) guard in uninstall.php — WordPress defines ABSPATH and WP_UNINSTALL_PLUGIN simultaneously; the second check was unreachable dead code
Version bump: 1.3.0 → 1.4.0
1.3.0
Maintenance: Version bump to 1.3.0
Compatibility: Tested up to WordPress 6.9
New: Multi-select filters now support AND/OR relation modes
Enhancement: Quick filters now apply instantly via AJAX (no Apply button)