=== REDSHAPE Easy Labels === Contributors: redshape Tags: labels, organization, dashboard, workflow, productivity Requires at least: 5.0 Tested up to: 6.9 Requires PHP: 7.0 Stable tag: 1.4.0 License: GPLv2 or later License URI: https://www.gnu.org/licenses/gpl-2.0.html Organize content with colored labels, notes, and dashboard widgets with 5 visualization types. == Description == Easy Labels is a comprehensive WordPress plugin for organizing and visualizing your content workflow. Create custom colored labels, add private notes, and gain insights through interactive dashboard widgets with pie charts, bar graphs, and statistics - all visible only in the backend for seamless team collaboration. = Main Features = * **Customizable colored labels**: Create labels with name and color of your choice * **Default labels**: Manage special labels "All" and "No Label" with custom colors and borders * **Custom borders**: Add borders to labels (solid, dashed, dotted, double) with custom colors * **Internal notes**: Add private notes for each content, visible only in the backend * **Dashboard widgets**: 5 visualization types (pie, donut, bar, list, stats) with click-to-filter * **Drag & drop ordering**: Customize label order in widgets with intuitive drag & drop interface * **Interactive charts**: Click on any chart segment or list item to filter content by that label * **Multi-select filtering**: Toggle between single and multiple label selection with AND logic * **Backup & Restore**: Export and import all plugin settings in JSON format * **Quick filters**: Quickly filter content by label with drag & drop to reorder * **Label search**: Integrated search field in popup to quickly find labels * **Real-time counts**: Label counts update automatically without page refresh * **Multi-language**: Support for 10 languages (IT, EN, FR, DE, ES, RU, ZH, JA, KO, HI) * **Granular permissions**: Control who can view and edit labels and notes * **Custom Post Types**: Enable the system for any content type * **Smart cache**: Cache system for optimal performance * **100% Backend**: Labels and notes are visible only in the admin area = Ideal for = * Editorial teams who need to coordinate content management * Sites with many posts that need internal organization * Agencies managing content on behalf of clients * Editorial offices using complex workflows == Installation == 1. Upload the `redshape-easylabels` folder to the `/wp-content/plugins/` directory 2. Activate the plugin from the WordPress 'Plugins' menu 3. Go to Tools > Easy Labels to configure labels 4. Start organizing your content! == Frequently Asked Questions == = Are labels visible on the frontend? = No, labels and notes are visible only in the WordPress backend for internal content organization. = Can I use Easy Labels with Custom Post Types? = Yes, you can enable the system for any post type from the settings page. = Can I control who can see the labels? = Yes, you can configure permissions by user role from the Permissions settings section. = How many labels can I create? = There is no limit to the number of labels you can create. = Is the plugin translated into other languages? = Yes, the plugin ships with standard WordPress `.po`/`.mo` translation files for 10 languages (IT, EN, FR, DE, ES, RU, ZH, JA, KO, HI). The files live in the `languages/` folder and follow the conventional naming `redshape-easy-labels-{locale}.mo`, making the plugin fully compatible with **Loco Translate**, **GlotPress**, **WPML**, **WP-CLI i18n** tools, and any other standard WordPress translation workflow. Translation files are also regenerated automatically on plugin activation. = Can I transfer settings between different sites? = Yes, from the Backup & Restore section you can export all settings to a JSON file and import them on another site. The system automatically filters content types that don't exist on the destination site. = How does multi-select filtering work? = Toggle the Multi switch in the quick filters to enable multi-select mode. Click label badges to apply filters immediately (AJAX) without page reload, and choose AND or OR mode. AND returns posts that match all selected labels, while OR returns posts that match at least one selected label. == Screenshots == 1. View of labels in the posts list 2. Label configuration panel 3. Meta box for assigning labels to content 4. Quick filters with multi-select mode toggle and visual selection indicators 5. Multi-select filtering with AND logic - filter posts with multiple labels together 6. Permission management by role 7. Dashboard widgets with pie/donut charts and click-to-filter 8. Bar chart visualization with horizontal and vertical orientations 9. Drag & drop interface for customizing label order in widgets 10. Stats cards and list visualization types == Changelog == = 1.4.0 = * Code: Refactored monolithic God Object (`class-redshape-easylabels.php`, 4619 lines) into 8 focused single-responsibility classes — `Redshape_Easylabels_Helpers` (static shared utilities), `Redshape_Easylabels_Admin_Columns`, `Redshape_Easylabels_Bulk_Actions`, `Redshape_Easylabels_Filter_Bar`, `Redshape_Easylabels_Meta_Box`, `Redshape_Easylabels_Ajax`, `Redshape_Easylabels_Dashboard_Widget`, `Redshape_Easylabels_Settings` * 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) * Fix: Removed duplicated uninstall cleanup blocks (cache/meta/transient) * Fix: Aligned cache post type source with role_settings[enabled_post_types] and backward-compatible fallback * Fix: Removed duplicate initializeLabelEvents() call in admin JavaScript = 1.2.0 = * New: Multi-Select Filter Mode - Toggle between single and multiple label selection in quick filters * New: Multi-select mode uses AND logic - filter posts that have ALL selected labels together * New: Apply button for multi-select - apply multiple label filters at once * New: Visual selection indicators - green checkmarks on selected labels in multi-select mode * New: State persistence - multi-select mode and selections maintained via URL parameters * New: Dashboard Widgets - Create unlimited custom widgets with 5 visualization types * New: Pie Chart visualization with interactive legend and click-to-filter functionality * New: Donut Chart visualization with center stats display * New: Bar Chart with horizontal/vertical orientation and multiple display modes (percentage, numeric, both) * New: List visualization with clickable items for content filtering * New: Stats Cards showing key metrics with click-to-filter (max 3 per row for optimal layout) * New: Drag & Drop Label Ordering - Customize label sequence in each widget independently * New: Click-to-Filter - Click any chart segment, bar, list item, or stat card to filter content by that label * New: Widget Configuration - Select post type, visualization type, labels, and display options per widget * New: "No Label" Support - Include posts without labels in widgets with custom positioning in sort order * Enhancement: Bar charts display proportional heights based on total count with accurate pixel scaling * Enhancement: Bar charts include left-side scale for easy value reading * Enhancement: All default label names (including "No Label") now use customized names from settings * Enhancement: Widgets Settings tab with intuitive drag & drop interface for label reordering * Enhancement: Debug mode - Console logs now only active when WP_DEBUG is enabled * Enhancement: WordPress Coding Standards compliance for all variable naming conventions * Fix: Label order now properly saved and persisted across page reloads * Fix: Sortable list visibility maintained after save operations * Fix: "No Label" positioning now respects custom order in all chart types * Fix: Focus outlines removed from interactive chart elements for cleaner UI * Fix: Stats cards layout limited to 3 per row for better visual balance * Enhancement: Multi-select toggle hides "All" badge when active * Enhancement: Toggle and Apply button only show when labels exist * Enhancement: Vertical separators between quick filter sections for better visual organization * Enhancement: Multi-select mode translations for all 10 supported languages = 1.1.0 = * New: Quick Create Label - Create new labels directly from content editor without going to settings * New: Universal modal for label creation works in both post list and meta box * New: Quick Create button always visible, even when no labels exist yet * New: Post type names translation - Post types (Posts, Pages, Products, etc.) now display in plugin's language for all 10 supported languages * Enhancement: Streamlined workflow for content organization * Enhancement: Auto-assign option when creating labels from content * Enhancement: Improved multilingual support with custom post type name mapping * Enhancement: Direct database queries for real-time counters to ensure accuracy on production sites * Enhancement: Debounced counter updates to prevent multiple simultaneous requests * Fix: Post type names now consistent with plugin language settings in all admin pages * Fix: Real-time counter accuracy on live sites with persistent cache systems (Redis, Memcached) * Fix: Counter increments now properly synchronized across multiple UI contexts (table, inline, metabox) * Fix: Dropdown state properly restored after closing Quick Create modal without creating label * Fix: PHPCS compliance for intentional direct database queries in counter calculations = 1.0.1 = * Fix: Added index.php files to all directories to prevent directory listing on misconfigured servers * Fix: Replaced wp_redirect() with wp_safe_redirect() for enhanced security * Fix: Added plugin prefix to all global variables in admin-page.php and uninstall.php to comply with WordPress Coding Standards * Fix: Renamed helper functions cl__() and cl_e() to redshape_easylabels_cl__() and redshape_easylabels_cl_e() for proper namespacing * Fix: Bulk action "Apply label" now correctly applies labels to selected posts * Fix: Metabox label display - labels now show correctly with name and color immediately after assignment * Fix: Metabox label removal - resolved permission errors when removing labels without page refresh * Fix: Dropdown refresh - label dropdown now correctly updates after adding or removing labels in metabox * Fix: Notes auto-save - each note field now has independent timeout to prevent data loss when editing multiple notes * Fix: Notes persistence - all pending notes are now saved before page unload to prevent loss of unsaved changes * Security: Enhanced directory protection following WordPress.org best practices = 1.0.0 = * First public release * Colored labels system with automatic key generation from label name * Customizable default labels ("All" and "No Label") * Custom borders for labels (5 styles: solid, dashed, dotted, double, none) * Search field in label popup for quick label finding * Drag & drop to reorder filters * Real-time counts without page refresh * Internal notes for content * Quick filters and search * Backup & Restore: export/import settings in JSON * Multi-language support (10 languages: IT, EN, FR, DE, ES, RU, ZH, JA, KO, HI) * Optimized cache system * Granular permission management * Custom Post Types support * System tab with plugin information * Smart label filtering: dropdown shows only unassigned labels * Improved popup positioning without visual jumps * WordPress.org compliance: all inline scripts/styles converted to wp_enqueue * Code comments translated to English for international standards == Upgrade Notice == = 1.4.0 = Performance & architecture release. Label storage migrated to indexed meta (automatic silent migration). Translations use standard .po/.mo files, compatible with Loco Translate, WPML and GlotPress. Code split into 8 focused classes. No data loss. = 1.3.0 = Maintenance release: metadata update (tested up to 6.9), AND/OR multi-select filtering support, and technical cleanup for uninstall, cache option consistency, and admin JS initialization. = 1.2.0 = Major feature update: Adds dashboard widgets with 5 visualization types and interactive click-to-filter functionality. Includes drag & drop label ordering for complete customization. = 1.0.1 = Security enhancement: Adds directory protection files. Recommended update for all users. = 1.0.0 = First release of the Easy Labels plugin.