{"id":259103,"date":"2025-11-05T14:21:20","date_gmt":"2025-11-05T14:21:20","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/easy-labels\/"},"modified":"2026-02-27T19:44:36","modified_gmt":"2026-02-27T19:44:36","slug":"redshape-easy-labels","status":"publish","type":"plugin","link":"https:\/\/pcd.wordpress.org\/plugins\/redshape-easy-labels\/","author":23367737,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_crdt_document":"","version":"1.5.1","stable_tag":"1.5.1","tested":"6.9.4","requires":"5.0","requires_php":"7.0","requires_plugins":null,"header_name":"REDSHAPE Easy Labels","header_author":"REDSHAPE","header_description":"Colored labels and internal notes system for posts and pages, visible only in backend for content organization. Supports 10 languages (IT, EN, FR, DE, ES, RU, ZH, JA, KO, HI).","assets_banners_color":"6b54d3","last_updated":"2026-02-27 19:44:36","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"","header_author_uri":"https:\/\/redshape.it","rating":5,"author_block_rating":0,"active_installs":10,"downloads":488,"num_ratings":1,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.4.0":{"tag":"1.4.0","author":"redshape","date":"2026-02-24 11:18:33"},"1.5.0":{"tag":"1.5.0","author":"redshape","date":"2026-02-24 12:36:30"},"1.5.1":{"tag":"1.5.1","author":"redshape","date":"2026-02-27 19:44:36"}},"upgrade_notice":{"1.5.1":"<p>Maintenance release. Version bump to 1.5.1.<\/p>","1.5.0":"<p>Maintenance release. Full SVN repository sync \u2014 all plugin files are now correctly distributed. Recommended update for all users.<\/p>","1.4.4":"<p>Maintenance release. Full repository sync to ensure all plugin files are correctly distributed. Recommended update if you encountered missing-file errors after installing 1.4.3.<\/p>","1.4.3":"<p>Bugfix release. Properly fixes the fatal error on partial deploys introduced in 1.4.2 \u2014 missing-file detection is now in the main plugin file so WordPress never crashes, just shows an admin notice. Recommended update for all users.<\/p>","1.4.2":"<p>Bugfix release. Fixes fatal errors on activation when plugin files are missing from a partial deploy \u2014 WordPress now shows a clear admin notice listing the missing files instead of crashing. Recommended update for all users.<\/p>","1.4.1":"<p>Bugfix release. Fixes a fatal error on activation after partial deploys, a data-loss bug when saving settings, and the post type selector showing only post+page for new labels. Adds &quot;Check for updates&quot; link in the plugin row. Recommended update for all 1.4.0 users.<\/p>","1.4.0":"<p>Performance &amp; 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.<\/p>","1.3.0":"<p>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.<\/p>","1.2.0":"<p>Major feature update: Adds dashboard widgets with 5 visualization types and interactive click-to-filter functionality. Includes drag &amp; drop label ordering for complete customization.<\/p>","1.0.1":"<p>Security enhancement: Adds directory protection files. Recommended update for all users.<\/p>","1.0.0":"<p>First release of the Easy Labels plugin.<\/p>"},"ratings":{"1":0,"2":0,"3":0,"4":0,"5":1},"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3398988,"resolution":"128x128","location":"assets","locale":""},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3398988,"resolution":"256x256","location":"assets","locale":""}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3398998,"resolution":"1544x500","location":"assets","locale":""},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3398998,"resolution":"772x250","location":"assets","locale":""}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["1.4.0","1.5.0","1.5.1"],"block_files":[],"assets_screenshots":{"screenshot-1.png":{"filename":"screenshot-1.png","revision":3398988,"resolution":"1","location":"assets","locale":""},"screenshot-10.png":{"filename":"screenshot-10.png","revision":3398988,"resolution":"10","location":"assets","locale":""},"screenshot-2.png":{"filename":"screenshot-2.png","revision":3398988,"resolution":"2","location":"assets","locale":""},"screenshot-3.png":{"filename":"screenshot-3.png","revision":3398988,"resolution":"3","location":"assets","locale":""},"screenshot-4.png":{"filename":"screenshot-4.png","revision":3398988,"resolution":"4","location":"assets","locale":""},"screenshot-5.png":{"filename":"screenshot-5.png","revision":3398988,"resolution":"5","location":"assets","locale":""},"screenshot-6.png":{"filename":"screenshot-6.png","revision":3398988,"resolution":"6","location":"assets","locale":""},"screenshot-7.png":{"filename":"screenshot-7.png","revision":3398988,"resolution":"7","location":"assets","locale":""},"screenshot-8.png":{"filename":"screenshot-8.png","revision":3398988,"resolution":"8","location":"assets","locale":""},"screenshot-9.png":{"filename":"screenshot-9.png","revision":3398988,"resolution":"9","location":"assets","locale":""}},"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 &amp; drop interface for customizing label order in widgets","10":"Stats cards and list visualization types"},"jetpack_post_was_ever_published":false},"plugin_section":[],"plugin_tags":[434,3808,5884,2345,8197],"plugin_category":[],"plugin_contributors":[250324],"plugin_business_model":[],"class_list":["post-259103","plugin","type-plugin","status-publish","hentry","plugin_tags-dashboard","plugin_tags-labels","plugin_tags-organization","plugin_tags-productivity","plugin_tags-workflow","plugin_contributors-redshape","plugin_committers-redshape"],"banners":{"banner":"https:\/\/ps.w.org\/redshape-easy-labels\/assets\/banner-772x250.png?rev=3398998","banner_2x":"https:\/\/ps.w.org\/redshape-easy-labels\/assets\/banner-1544x500.png?rev=3398998","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/redshape-easy-labels\/assets\/icon-128x128.png?rev=3398988","icon_2x":"https:\/\/ps.w.org\/redshape-easy-labels\/assets\/icon-256x256.png?rev=3398988","generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/redshape-easy-labels\/assets\/screenshot-1.png?rev=3398988","caption":"View of labels in the posts list"},{"src":"https:\/\/ps.w.org\/redshape-easy-labels\/assets\/screenshot-2.png?rev=3398988","caption":"Label configuration panel"},{"src":"https:\/\/ps.w.org\/redshape-easy-labels\/assets\/screenshot-3.png?rev=3398988","caption":"Meta box for assigning labels to content"},{"src":"https:\/\/ps.w.org\/redshape-easy-labels\/assets\/screenshot-4.png?rev=3398988","caption":"Quick filters with multi-select mode toggle and visual selection indicators"},{"src":"https:\/\/ps.w.org\/redshape-easy-labels\/assets\/screenshot-5.png?rev=3398988","caption":"Multi-select filtering with AND logic - filter posts with multiple labels together"},{"src":"https:\/\/ps.w.org\/redshape-easy-labels\/assets\/screenshot-6.png?rev=3398988","caption":"Permission management by role"},{"src":"https:\/\/ps.w.org\/redshape-easy-labels\/assets\/screenshot-7.png?rev=3398988","caption":"Dashboard widgets with pie\/donut charts and click-to-filter"},{"src":"https:\/\/ps.w.org\/redshape-easy-labels\/assets\/screenshot-8.png?rev=3398988","caption":"Bar chart visualization with horizontal and vertical orientations"},{"src":"https:\/\/ps.w.org\/redshape-easy-labels\/assets\/screenshot-9.png?rev=3398988","caption":"Drag &amp; drop interface for customizing label order in widgets"},{"src":"https:\/\/ps.w.org\/redshape-easy-labels\/assets\/screenshot-10.png?rev=3398988","caption":"Stats cards and list visualization types"}],"raw_content":"<!--section=description-->\n<p>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.<\/p>\n\n<h4>Main Features<\/h4>\n\n<ul>\n<li><strong>Customizable colored labels<\/strong>: Create labels with name and color of your choice<\/li>\n<li><strong>Default labels<\/strong>: Manage special labels \"All\" and \"No Label\" with custom colors and borders<\/li>\n<li><strong>Custom borders<\/strong>: Add borders to labels (solid, dashed, dotted, double) with custom colors<\/li>\n<li><strong>Internal notes<\/strong>: Add private notes for each content, visible only in the backend<\/li>\n<li><strong>Dashboard widgets<\/strong>: 5 visualization types (pie, donut, bar, list, stats) with click-to-filter<\/li>\n<li><strong>Drag &amp; drop ordering<\/strong>: Customize label order in widgets with intuitive drag &amp; drop interface<\/li>\n<li><strong>Interactive charts<\/strong>: Click on any chart segment or list item to filter content by that label<\/li>\n<li><strong>Multi-select filtering<\/strong>: Toggle between single and multiple label selection with AND logic<\/li>\n<li><strong>Backup &amp; Restore<\/strong>: Export and import all plugin settings in JSON format<\/li>\n<li><strong>Quick filters<\/strong>: Quickly filter content by label with drag &amp; drop to reorder<\/li>\n<li><strong>Label search<\/strong>: Integrated search field in popup to quickly find labels<\/li>\n<li><strong>Real-time counts<\/strong>: Label counts update automatically without page refresh<\/li>\n<li><strong>Multi-language<\/strong>: Support for 10 languages (IT, EN, FR, DE, ES, RU, ZH, JA, KO, HI)<\/li>\n<li><strong>Granular permissions<\/strong>: Control who can view and edit labels and notes<\/li>\n<li><strong>Custom Post Types<\/strong>: Enable the system for any content type<\/li>\n<li><strong>Smart cache<\/strong>: Cache system for optimal performance<\/li>\n<li><strong>100% Backend<\/strong>: Labels and notes are visible only in the admin area<\/li>\n<\/ul>\n\n<h4>Ideal for<\/h4>\n\n<ul>\n<li>Editorial teams who need to coordinate content management<\/li>\n<li>Sites with many posts that need internal organization<\/li>\n<li>Agencies managing content on behalf of clients<\/li>\n<li>Editorial offices using complex workflows<\/li>\n<\/ul>\n\n<!--section=installation-->\n<ol>\n<li>Upload the <code>redshape-easylabels<\/code> folder to the <code>\/wp-content\/plugins\/<\/code> directory<\/li>\n<li>Activate the plugin from the WordPress 'Plugins' menu<\/li>\n<li>Go to Tools &gt; Easy Labels to configure labels<\/li>\n<li>Start organizing your content!<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"are%20labels%20visible%20on%20the%20frontend%3F\"><h3>Are labels visible on the frontend?<\/h3><\/dt>\n<dd><p>No, labels and notes are visible only in the WordPress backend for internal content organization.<\/p><\/dd>\n<dt id=\"can%20i%20use%20easy%20labels%20with%20custom%20post%20types%3F\"><h3>Can I use Easy Labels with Custom Post Types?<\/h3><\/dt>\n<dd><p>Yes, you can enable the system for any post type from the settings page.<\/p><\/dd>\n<dt id=\"can%20i%20control%20who%20can%20see%20the%20labels%3F\"><h3>Can I control who can see the labels?<\/h3><\/dt>\n<dd><p>Yes, you can configure permissions by user role from the Permissions settings section.<\/p><\/dd>\n<dt id=\"how%20many%20labels%20can%20i%20create%3F\"><h3>How many labels can I create?<\/h3><\/dt>\n<dd><p>There is no limit to the number of labels you can create.<\/p><\/dd>\n<dt id=\"is%20the%20plugin%20translated%20into%20other%20languages%3F\"><h3>Is the plugin translated into other languages?<\/h3><\/dt>\n<dd><p>Yes, the plugin ships with standard WordPress <code>.po<\/code>\/<code>.mo<\/code> translation files for 10 languages (IT, EN, FR, DE, ES, RU, ZH, JA, KO, HI). The files live in the <code>languages\/<\/code> folder and follow the conventional naming <code>redshape-easy-labels-{locale}.mo<\/code>, making the plugin fully compatible with <strong>Loco Translate<\/strong>, <strong>GlotPress<\/strong>, <strong>WPML<\/strong>, <strong>WP-CLI i18n<\/strong> tools, and any other standard WordPress translation workflow. Translation files are also regenerated automatically on plugin activation.<\/p><\/dd>\n<dt id=\"can%20i%20transfer%20settings%20between%20different%20sites%3F\"><h3>Can I transfer settings between different sites?<\/h3><\/dt>\n<dd><p>Yes, from the Backup &amp; 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.<\/p><\/dd>\n<dt id=\"how%20does%20multi-select%20filtering%20work%3F\"><h3>How does multi-select filtering work?<\/h3><\/dt>\n<dd><p>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.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.5.1<\/h4>\n\n<ul>\n<li>Improvement: Settings page (Tools &gt; Easy Labels) now always renders in the WordPress site language \u2014 the <code>plugin_language<\/code> option now controls only the operational interface (content labels, filter bar, notes, modals, dashboard widgets)<\/li>\n<li>Fix: Removed redundant <code>switch_to_locale()<\/code> call in <code>prepare_view_data()<\/code> \u2014 post-type names on the settings page now correctly follow the WordPress site locale<\/li>\n<li>Improvement: Updated Language tab description and i18n strings to accurately reflect the new two-locale behaviour (settings = WP locale, operational UI = plugin language)<\/li>\n<li>UI: Several layout and visual improvements to the settings page \u2014 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<\/li>\n<li>UI: Label and widget editor cards are now collapsible \u2014 each card has a toggle arrow button next to the delete button; existing cards load collapsed by default, newly created cards start open<\/li>\n<li>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<\/li>\n<li>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<\/li>\n<li>UX: Clicking anywhere on the label or widget card header bar now toggles the collapsed state (the arrow button still works as before); <code>cursor: pointer<\/code> added to header bars for clarity<\/li>\n<li>UI: All card\/section hover effects across the settings page now use a consistent style \u2014 base border standardised to <code>1px solid #c3c4c7<\/code> and hover border to <code>1px solid #2271b1<\/code> with <code>box-shadow: 0 4px 12px rgba(0,0,0,0.08)<\/code>; removed <code>transform: translateY<\/code> animations and non-standard border thicknesses\/colours from post-type cards, language cards, support cards and setting sections<\/li>\n<li>Fix: Extended <code>phpcs:disable\/enable<\/code> block in <code>redshape-easy-labels.php<\/code> to correctly suppress <code>NonceVerification.Recommended<\/code> across the multi-line <code>$is_settings_page<\/code> expression (reading-only <code>$_GET['page']<\/code> to determine admin context)<\/li>\n<li>Fix: Renamed template variables in <code>admin-page.php<\/code> to use the <code>$redshape_easylabels_<\/code> plugin prefix, resolving <code>PrefixAllGlobals<\/code> PHPCS warnings<\/li>\n<li>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<\/li>\n<li>Version bump: 1.5.0 \u2192 1.5.1<\/li>\n<\/ul>\n\n<h4>1.5.0<\/h4>\n\n<ul>\n<li>Maintenance: Full sync with WordPress.org SVN repository \u2014 all plugin files correctly added and distributed<\/li>\n<li>Version bump: 1.4.4 \u2192 1.5.0<\/li>\n<\/ul>\n\n<h4>1.4.4<\/h4>\n\n<ul>\n<li>Maintenance: Full sync with WordPress.org repository \u2014 no code changes, version bump to ensure all files are correctly distributed<\/li>\n<li>Version bump: 1.4.3 \u2192 1.4.4<\/li>\n<\/ul>\n\n<h4>1.4.3<\/h4>\n\n<ul>\n<li>Fix: Fatal \"Class not found\" error when plugin is loaded with missing files after a partial deploy \u2014 the previous fix (1.4.2) placed the file check inside <code>class-redshape-easylabels.php<\/code> which caused an early <code>return<\/code> that left <code>Redshape_Easylabels<\/code> undefined, then <code>plugins_loaded<\/code> still tried to instantiate it and crashed; check is now in the main entry file <code>redshape-easy-labels.php<\/code> so if any file is missing the <code>plugins_loaded<\/code> hook is never registered \u2014 WordPress shows a clear admin notice listing the missing files<\/li>\n<li>Version bump: 1.4.2 \u2192 1.4.3<\/li>\n<\/ul>\n\n<h4>1.4.2<\/h4>\n\n<ul>\n<li>Fix: Fatal error on activation when any core class file is missing from a partial deploy (<code>class-redshape-easylabels-helpers.php<\/code>, etc.) \u2014 <code>class-redshape-easylabels.php<\/code> now checks all 10 required files with <code>file_exists()<\/code> before loading them; if any are missing a clear admin notice lists them and the plugin exits cleanly instead of crashing WordPress<\/li>\n<li>Fix: PHPCS <code>NonPrefixedVariableFound<\/code> warning \u2014 removed global variable <code>$_redshape_easylabels_lang_gen<\/code> in <code>redshape-easy-labels.php<\/code>, replaced with an inline <code>file_exists()<\/code> call<\/li>\n<li>Version bump: 1.4.1 \u2192 1.4.2<\/li>\n<\/ul>\n\n<h4>1.4.1<\/h4>\n\n<ul>\n<li>Fix: Fatal error on activation\/update when <code>class-redshape-easylabels-language-generator.php<\/code> was missing from a partial deploy \u2014 <code>require_once<\/code> is now conditional on <code>file_exists()<\/code>; all call-sites guarded with <code>class_exists('Redshape_Easylabels_Language_Generator')<\/code><\/li>\n<li>Fix: Data loss after saving settings \u2014 <code>save_settings()<\/code> accessed <code>$current_options['default_labels']<\/code> and <code>$current_options['role_settings']<\/code> without <code>isset<\/code>; on PHP 8 a missing key returns <code>null<\/code>, causing <code>update_option<\/code> to overwrite labels and widgets with null\/empty values; replaced with defensive <code>isset<\/code> reads and added automatic migration from the legacy <code>labels<\/code> key to <code>default_labels<\/code><\/li>\n<li>Fix: Post type selector in \"Add New Label\" showed only <code>post<\/code> and <code>page<\/code> \u2014 <code>enqueue_settings_page_scripts()<\/code> read <code>$settings['role_settings']['enabled_post_types']<\/code> which is always <code>null<\/code> because <code>get_settings()<\/code> flattens <code>role_settings<\/code> keys to root level; corrected to read <code>$settings['enabled_post_types']<\/code> directly<\/li>\n<li>Fix: Dropdown close in post editor \/ Gutenberg \u2014 replaced jQuery <code>$(document).on('click')<\/code> 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 <code>closeAllDropdowns()<\/code> helper used by all 8 close paths<\/li>\n<li>Fix: Missing <code>'Label name is required'<\/code> translation key in 8 non-Italian locales (<code>fr_FR<\/code>, <code>de_DE<\/code>, <code>es_ES<\/code>, <code>ru_RU<\/code>, <code>zh_CN<\/code>, <code>ja_JP<\/code>, <code>ko_KR<\/code>, <code>hi_IN<\/code>) \u2014 JS validation error was always displayed in English regardless of plugin language setting<\/li>\n<li>New: Added \"Check for updates\" link in the plugin description row on the Plugins page \u2014 clicking it triggers a WordPress update check (<code>update-core.php?force-check=1<\/code>) without leaving the admin<\/li>\n<li>Version bump: 1.4.0 \u2192 1.4.1<\/li>\n<\/ul>\n\n<h4>1.4.0<\/h4>\n\n<ul>\n<li>Code: Refactored monolithic God Object (<code>class-redshape-easylabels.php<\/code>, 4619 lines) into 8 focused single-responsibility classes \u2014 <code>Redshape_Easylabels_Helpers<\/code> (static shared utilities), <code>Redshape_Easylabels_Admin_Columns<\/code>, <code>Redshape_Easylabels_Bulk_Actions<\/code>, <code>Redshape_Easylabels_Filter_Bar<\/code>, <code>Redshape_Easylabels_Meta_Box<\/code>, <code>Redshape_Easylabels_Ajax<\/code>, <code>Redshape_Easylabels_Dashboard_Widget<\/code>, <code>Redshape_Easylabels_Settings<\/code><\/li>\n<li>Code: Main <code>Redshape_Easylabels<\/code> class is now a lean coordinator that instantiates sub-classes and wires up shared hooks<\/li>\n<li>Fix: Corrected hardcoded Italian strings in <code>admin.js<\/code> (<code>Clicca per rimuovere<\/code>, <code>Aggiungi etichetta<\/code>, <code>Errore critico. Ricarica la pagina.<\/code>, <code>Errore di elaborazione risposta<\/code>) \u2014 all now routed through the <code>__()<\/code> JS helper using English keys; translations added for all 10 supported languages<\/li>\n<li>Improvement: Migrated translation system from hardcoded PHP arrays to standard WordPress <code>.po<\/code>\/<code>.mo<\/code> files \u2014 now fully compatible with Loco Translate, GlotPress, WPML, and WP-CLI i18n tools<\/li>\n<li>New: Added <code>Redshape_Easylabels_Language_Generator<\/code> class that builds <code>.po<\/code> and <code>.mo<\/code> files from the existing translation data (pure PHP, no external dependencies)<\/li>\n<li>New: Added <code>bin\/generate-languages.php<\/code> CLI script to regenerate all language files from the command line during development<\/li>\n<li>New: <code>load_textdomain()<\/code> now loads the correct <code>.mo<\/code> based on the per-plugin language setting (<code>plugin_language<\/code> option), independently of the WordPress site locale<\/li>\n<li>New: Language files are automatically regenerated on plugin activation and lazily on first use if missing<\/li>\n<li>Code: Removed dead-code duplicate <code>class-redshape-easylabels-content-i18n.php<\/code> (\\~2300 lines, \\~70% identical to the main i18n class, never loaded, using a stale option key <code>content_labels_options<\/code>)<\/li>\n<li>Improvement: Migrated label storage from a single serialized array (<code>_content_labels<\/code>) to one post-meta row per label (<code>_content_label<\/code>) \u2014 meta queries now use exact-match <code>=<\/code> instead of <code>LIKE '%...%'<\/code>, enabling MySQL index usage<\/li>\n<li>New: <code>maybe_upgrade_storage()<\/code> one-time migration function converts existing data transparently on first admin load after update<\/li>\n<li>New: Added <code>get_post_label_ids()<\/code> and <code>set_post_label_ids()<\/code> private helpers to centralise all label read\/write operations<\/li>\n<li>Fix: All <code>filter_posts_by_label()<\/code>, <code>add_quick_filter_bar()<\/code>, and counter queries updated to use the new storage format<\/li>\n<li>Fix: Cache class (<code>Redshape_Easylabels_Cache<\/code>) updated to use the new meta key and exact-match queries<\/li>\n<li>Fix: <code>uninstall.php<\/code> now cleans up both <code>_content_label<\/code> (new) and <code>_content_labels<\/code> (legacy) meta keys<\/li>\n<li>Code: Separated logic from template in <code>admin-page.php<\/code> \u2014 all DB reads, locale switching, <code>wp_localize_script<\/code>, and static data arrays extracted into a new <code>prepare_view_data()<\/code> private method in <code>Redshape_Easylabels_Settings<\/code>; the template is now pure display HTML\/PHP with no business logic<\/li>\n<li>Fix: Eliminated duplicate column hook registrations \u2014 only <code>manage_{$pt}_posts_columns<\/code> \/ <code>manage_{$pt}_posts_custom_column<\/code> are now registered (fires for all post types); the redundant <code>manage_{$pt}s_columns<\/code> \/ <code>manage_{$pt}s_custom_column<\/code> hooks that caused double-fire on built-in types have been removed, along with the workaround guards they required<\/li>\n<li>Performance: Replaced per-label COUNT queries with a single <code>GROUP BY meta_value<\/code> query in <code>Redshape_Easylabels_Helpers::get_label_counts_for_post_type()<\/code> \u2014 used by both the AJAX filter-count endpoint and the dashboard widget renderer; eliminates the N-query loop that previously ran one <code>SELECT COUNT(DISTINCT)<\/code> per label; no <code>maybe_unserialize()<\/code> needed since <code>_content_label<\/code> stores flat string values<\/li>\n<li>Code: Extracted ~65 lines of inline JS (bulk label selector) from a PHP string with manual <code>\\'<\/code> escaping into a proper file <code>assets\/js\/admin-bulk-actions.js<\/code>; translated alert strings passed via <code>wp_localize_script<\/code> as <code>redshapeEasylabelsBulk.i18n<\/code><\/li>\n<li>Fix: <code>redshape_easylabels_cl_e()<\/code> docblock now explicitly states it strips HTML; added companion <code>redshape_easylabels_cl_html_e()<\/code> that passes the translated string through <code>wp_kses()<\/code> with a minimal inline-tag allowlist (<code>strong<\/code>, <code>em<\/code>, <code>code<\/code>, <code>span<\/code>, <code>br<\/code>, <code>a<\/code>) so legitimate markup in translations is preserved instead of silently entity-encoded<\/li>\n<li>Fix: <code>Redshape_Easylabels_Cache::invalidate_all()<\/code> \u2014 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 <code>wp_cache_flush_group()<\/code> (WP 6.1+ \/ Redis \/ Memcached) plus a per-label fallback for standard setups; also removed the <code>cache_version<\/code> lookup from <code>generate_cache_key()<\/code> which added an extra <code>wp_cache_get()<\/code> on every cache read\/write<\/li>\n<li>Fix: <code>initializeInlineLabels()<\/code> in <code>admin.js<\/code> \u2014 replaced <code>setTimeout<\/code> retry polling (two blind delays of 300\u2013500 ms) with a <code>MutationObserver<\/code> that watches <code>document.body<\/code> and fires exactly once when <code>.wp-list-table .row-title<\/code> appears, then disconnects; eliminates missed renders and unnecessary CPU wake-ups<\/li>\n<li>Fix: <code>redshape_easylabels_deactivate()<\/code> was empty; now calls <code>Redshape_Easylabels_Cache::invalidate_all()<\/code> on deactivation so stale label counts don't persist in Redis \/ Memcached between sessions<\/li>\n<li>Fix: <code>get_cache_stats()<\/code> was reading from the wrong option key (<code>labels<\/code> instead of <code>default_labels<\/code>) \u2014 always returned <code>total_labels: 0<\/code>; removed stale <code>cache_version<\/code> 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 <code>$label['id']<\/code><\/li>\n<li>Fix: <code>ajax_add_label_to_post()<\/code> 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 <code>edit_post<\/code> capability<\/li>\n<li>Fix: <code>get_all_post_labels()<\/code> SQL query fetched all <code>_content_label<\/code> rows across the entire database with no post-type filter; query now JOINs <code>wp_posts<\/code> and filters by <code>post_type<\/code>, significantly reducing data volume on multi-post-type sites<\/li>\n<li>Fix: Two hardcoded Italian <code>__()<\/code> keys (<code>'Il nome dell\\'etichetta \u00e8 obbligatorio'<\/code>) in the Quick Create Label handlers in <code>admin.js<\/code> replaced with the existing English key <code>'Label name is required'<\/code> so all 10 locales translate correctly<\/li>\n<li>Fix: <code>DOMNodeInserted<\/code> event (deprecated, removed in Chrome 124+) replaced with a <code>MutationObserver<\/code> that watches for new <code>.content-label-badge<\/code> elements and adds the <code>draggable<\/code> class on insertion<\/li>\n<li>Fix: <code>initializeDragAndDrop()<\/code> and <code>initFilterDragAndDrop()<\/code> were started via 4 chained <code>setTimeout<\/code> calls (500 ms, 800 ms, 1500 ms, 3000 ms + <code>$(window).on('load')<\/code>); replaced with a single <code>$(window).on('load')<\/code> for the sortable initializer and a <code>MutationObserver<\/code> for the filter container \u2014 eliminates blind waits and missed renders<\/li>\n<li>Code: Corrected <code>@since 1.4.1<\/code> tag to <code>@since 1.4.0<\/code> in all 9 class file docblocks (coordinator, helpers, ajax, settings, admin-columns, bulk-actions, filter-bar, meta-box, dashboard-widget)<\/li>\n<li>Code: Removed redundant <code>!defined('ABSPATH')<\/code> guard in <code>uninstall.php<\/code> \u2014 WordPress defines <code>ABSPATH<\/code> and <code>WP_UNINSTALL_PLUGIN<\/code> simultaneously; the second check was unreachable dead code<\/li>\n<li>Version bump: 1.3.0 \u2192 1.4.0<\/li>\n<\/ul>\n\n<h4>1.3.0<\/h4>\n\n<ul>\n<li>Maintenance: Version bump to 1.3.0<\/li>\n<li>Compatibility: Tested up to WordPress 6.9<\/li>\n<li>New: Multi-select filters now support AND\/OR relation modes<\/li>\n<li>Enhancement: Quick filters now apply instantly via AJAX (no Apply button)<\/li>\n<li>Fix: Removed duplicated uninstall cleanup blocks (cache\/meta\/transient)<\/li>\n<li>Fix: Aligned cache post type source with role_settings[enabled_post_types] and backward-compatible fallback<\/li>\n<li>Fix: Removed duplicate initializeLabelEvents() call in admin JavaScript<\/li>\n<\/ul>\n\n<h4>1.2.0<\/h4>\n\n<ul>\n<li>New: Multi-Select Filter Mode - Toggle between single and multiple label selection in quick filters<\/li>\n<li>New: Multi-select mode uses AND logic - filter posts that have ALL selected labels together<\/li>\n<li>New: Apply button for multi-select - apply multiple label filters at once<\/li>\n<li>New: Visual selection indicators - green checkmarks on selected labels in multi-select mode<\/li>\n<li>New: State persistence - multi-select mode and selections maintained via URL parameters<\/li>\n<li>New: Dashboard Widgets - Create unlimited custom widgets with 5 visualization types<\/li>\n<li>New: Pie Chart visualization with interactive legend and click-to-filter functionality<\/li>\n<li>New: Donut Chart visualization with center stats display<\/li>\n<li>New: Bar Chart with horizontal\/vertical orientation and multiple display modes (percentage, numeric, both)<\/li>\n<li>New: List visualization with clickable items for content filtering<\/li>\n<li>New: Stats Cards showing key metrics with click-to-filter (max 3 per row for optimal layout)<\/li>\n<li>New: Drag &amp; Drop Label Ordering - Customize label sequence in each widget independently<\/li>\n<li>New: Click-to-Filter - Click any chart segment, bar, list item, or stat card to filter content by that label<\/li>\n<li>New: Widget Configuration - Select post type, visualization type, labels, and display options per widget<\/li>\n<li>New: \"No Label\" Support - Include posts without labels in widgets with custom positioning in sort order<\/li>\n<li>Enhancement: Bar charts display proportional heights based on total count with accurate pixel scaling<\/li>\n<li>Enhancement: Bar charts include left-side scale for easy value reading<\/li>\n<li>Enhancement: All default label names (including \"No Label\") now use customized names from settings<\/li>\n<li>Enhancement: Widgets Settings tab with intuitive drag &amp; drop interface for label reordering<\/li>\n<li>Enhancement: Debug mode - Console logs now only active when WP_DEBUG is enabled<\/li>\n<li>Enhancement: WordPress Coding Standards compliance for all variable naming conventions<\/li>\n<li>Fix: Label order now properly saved and persisted across page reloads<\/li>\n<li>Fix: Sortable list visibility maintained after save operations<\/li>\n<li>Fix: \"No Label\" positioning now respects custom order in all chart types<\/li>\n<li>Fix: Focus outlines removed from interactive chart elements for cleaner UI<\/li>\n<li>Fix: Stats cards layout limited to 3 per row for better visual balance<\/li>\n<li>Enhancement: Multi-select toggle hides \"All\" badge when active<\/li>\n<li>Enhancement: Toggle and Apply button only show when labels exist<\/li>\n<li>Enhancement: Vertical separators between quick filter sections for better visual organization<\/li>\n<li>Enhancement: Multi-select mode translations for all 10 supported languages<\/li>\n<\/ul>\n\n<h4>1.1.0<\/h4>\n\n<ul>\n<li>New: Quick Create Label - Create new labels directly from content editor without going to settings<\/li>\n<li>New: Universal modal for label creation works in both post list and meta box<\/li>\n<li>New: Quick Create button always visible, even when no labels exist yet<\/li>\n<li>New: Post type names translation - Post types (Posts, Pages, Products, etc.) now display in plugin's language for all 10 supported languages<\/li>\n<li>Enhancement: Streamlined workflow for content organization<\/li>\n<li>Enhancement: Auto-assign option when creating labels from content<\/li>\n<li>Enhancement: Improved multilingual support with custom post type name mapping<\/li>\n<li>Enhancement: Direct database queries for real-time counters to ensure accuracy on production sites<\/li>\n<li>Enhancement: Debounced counter updates to prevent multiple simultaneous requests<\/li>\n<li>Fix: Post type names now consistent with plugin language settings in all admin pages<\/li>\n<li>Fix: Real-time counter accuracy on live sites with persistent cache systems (Redis, Memcached)<\/li>\n<li>Fix: Counter increments now properly synchronized across multiple UI contexts (table, inline, metabox)<\/li>\n<li>Fix: Dropdown state properly restored after closing Quick Create modal without creating label<\/li>\n<li>Fix: PHPCS compliance for intentional direct database queries in counter calculations<\/li>\n<\/ul>\n\n<h4>1.0.1<\/h4>\n\n<ul>\n<li>Fix: Added index.php files to all directories to prevent directory listing on misconfigured servers<\/li>\n<li>Fix: Replaced wp_redirect() with wp_safe_redirect() for enhanced security<\/li>\n<li>Fix: Added plugin prefix to all global variables in admin-page.php and uninstall.php to comply with WordPress Coding Standards<\/li>\n<li>Fix: Renamed helper functions cl__() and cl_e() to redshape_easylabels_cl__() and redshape_easylabels_cl_e() for proper namespacing<\/li>\n<li>Fix: Bulk action \"Apply label\" now correctly applies labels to selected posts<\/li>\n<li>Fix: Metabox label display - labels now show correctly with name and color immediately after assignment<\/li>\n<li>Fix: Metabox label removal - resolved permission errors when removing labels without page refresh<\/li>\n<li>Fix: Dropdown refresh - label dropdown now correctly updates after adding or removing labels in metabox<\/li>\n<li>Fix: Notes auto-save - each note field now has independent timeout to prevent data loss when editing multiple notes<\/li>\n<li>Fix: Notes persistence - all pending notes are now saved before page unload to prevent loss of unsaved changes<\/li>\n<li>Security: Enhanced directory protection following WordPress.org best practices<\/li>\n<\/ul>\n\n<h4>1.0.0<\/h4>\n\n<ul>\n<li>First public release<\/li>\n<li>Colored labels system with automatic key generation from label name<\/li>\n<li>Customizable default labels (\"All\" and \"No Label\")<\/li>\n<li>Custom borders for labels (5 styles: solid, dashed, dotted, double, none)<\/li>\n<li>Search field in label popup for quick label finding<\/li>\n<li>Drag &amp; drop to reorder filters<\/li>\n<li>Real-time counts without page refresh<\/li>\n<li>Internal notes for content<\/li>\n<li>Quick filters and search<\/li>\n<li>Backup &amp; Restore: export\/import settings in JSON<\/li>\n<li>Multi-language support (10 languages: IT, EN, FR, DE, ES, RU, ZH, JA, KO, HI)<\/li>\n<li>Optimized cache system<\/li>\n<li>Granular permission management<\/li>\n<li>Custom Post Types support<\/li>\n<li>System tab with plugin information<\/li>\n<li>Smart label filtering: dropdown shows only unassigned labels<\/li>\n<li>Improved popup positioning without visual jumps<\/li>\n<li>WordPress.org compliance: all inline scripts\/styles converted to wp_enqueue<\/li>\n<li>Code comments translated to English for international standards<\/li>\n<\/ul>","raw_excerpt":"Organize content with colored labels, notes, and dashboard widgets with 5 visualization types.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/pcd.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/259103","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/pcd.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/pcd.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/pcd.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=259103"}],"author":[{"embeddable":true,"href":"https:\/\/pcd.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/redshape"}],"wp:attachment":[{"href":"https:\/\/pcd.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=259103"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/pcd.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=259103"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/pcd.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=259103"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/pcd.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=259103"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/pcd.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=259103"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/pcd.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=259103"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}