Changeset 3465229
- Timestamp:
- 02/19/2026 04:32:36 PM (5 weeks ago)
- Location:
- redshape-easy-labels
- Files:
-
- 16 edited
- 1 copied
-
tags/1.3.0 (copied) (copied from redshape-easy-labels/trunk)
-
tags/1.3.0/assets/css/admin-settings.css (modified) (5 diffs)
-
tags/1.3.0/assets/js/admin.js (modified) (16 diffs)
-
tags/1.3.0/includes/admin-page.php (modified) (24 diffs)
-
tags/1.3.0/includes/class-redshape-easylabels-cache.php (modified) (3 diffs)
-
tags/1.3.0/includes/class-redshape-easylabels.php (modified) (17 diffs)
-
tags/1.3.0/readme.txt (modified) (4 diffs)
-
tags/1.3.0/redshape-easy-labels.php (modified) (3 diffs)
-
tags/1.3.0/uninstall.php (modified) (1 diff)
-
trunk/assets/css/admin-settings.css (modified) (5 diffs)
-
trunk/assets/js/admin.js (modified) (16 diffs)
-
trunk/includes/admin-page.php (modified) (24 diffs)
-
trunk/includes/class-redshape-easylabels-cache.php (modified) (3 diffs)
-
trunk/includes/class-redshape-easylabels.php (modified) (17 diffs)
-
trunk/readme.txt (modified) (4 diffs)
-
trunk/redshape-easy-labels.php (modified) (3 diffs)
-
trunk/uninstall.php (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
redshape-easy-labels/tags/1.3.0/assets/css/admin-settings.css
r3398988 r3465229 176 176 margin-top: 4px; 177 177 display: block; 178 } 179 180 .field-description-spaced { 181 margin-top: 8px; 182 color: #666; 183 } 184 185 .field-description-indented { 186 margin-left: 24px; 187 display: block; 188 color: #666; 189 } 190 191 .field-description-with-bottom-gap { 192 margin-bottom: 12px; 193 } 194 195 .icon-accent { 196 color: #2271b1; 197 } 198 199 .icon-sm { 200 font-size: 16px; 201 } 202 203 .label-display-options { 204 margin-top: 16px; 205 padding-top: 16px; 206 border-top: 1px solid #e5e5e5; 207 } 208 209 .label-checkbox-option-spaced { 210 margin-bottom: 12px; 211 } 212 213 .default-label-row { 214 display: flex; 215 gap: 8px; 216 align-items: flex-start; 217 } 218 219 .default-label-row .label-name-input { 220 flex: 1; 178 221 } 179 222 … … 800 843 /* Reset button per default labels */ 801 844 .reset-default-label-btn { 845 display: inline-flex; 846 align-items: center; 847 gap: 4px; 848 padding: 8px 12px; 849 background: #f0f0f1; 850 border: 1px solid #c3c4c7; 851 border-radius: 4px; 852 cursor: pointer; 853 font-size: 13px; 854 color: #2c3338; 802 855 transition: all 0.2s ease; 803 856 } … … 816 869 817 870 .reset-default-label-btn .dashicons { 871 font-size: 16px; 872 width: 16px; 873 height: 16px; 818 874 transition: transform 0.3s ease; 819 875 } … … 827 883 .border-style-options { 828 884 width: 100%; 885 } 886 887 .border-style-options-grid { 888 display: grid; 889 grid-template-columns: repeat(5, 1fr); 890 gap: 10px; 829 891 } 830 892 … … 1720 1782 transition: all 0.2s ease; 1721 1783 } 1784 1785 .hidden-file-input, 1786 .is-hidden { 1787 display: none; 1788 } 1789 1790 .widget-preview-badge { 1791 display: inline-flex; 1792 align-items: center; 1793 gap: 8px; 1794 padding: 8px 16px; 1795 background: #2271b1; 1796 color: #fff; 1797 border-radius: 20px; 1798 font-size: 14px; 1799 font-weight: 500; 1800 text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); 1801 box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); 1802 } 1803 1804 .widget-preview-badge .dashicons { 1805 font-size: 16px; 1806 width: 16px; 1807 height: 16px; 1808 } 1809 1810 .widget-two-col-grid { 1811 display: grid; 1812 grid-template-columns: 1fr 1fr; 1813 gap: 15px; 1814 } 1815 1816 .widget-bar-chart-options { 1817 margin-top: 15px; 1818 } 1819 1820 .widget-selected-labels-container { 1821 margin-top: 15px; 1822 } 1823 1824 .widget-selected-labels-title { 1825 font-weight: 600; 1826 margin-bottom: 10px; 1827 color: #23282d; 1828 } 1829 1830 .widget-selected-labels-title .dashicons { 1831 font-size: 16px; 1832 margin-right: 5px; 1833 } 1834 1835 .widget-selected-labels-note { 1836 font-weight: 400; 1837 color: #666; 1838 font-size: 12px; 1839 } 1840 1841 .widget-selected-labels-list { 1842 display: flex; 1843 flex-wrap: wrap; 1844 gap: 8px; 1845 padding: 12px; 1846 background: #f9f9f9; 1847 border-radius: 4px; 1848 min-height: 50px; 1849 } 1850 1851 .widget-sortable-label { 1852 cursor: move; 1853 padding: 6px 12px; 1854 color: #fff; 1855 border-radius: 4px; 1856 display: flex; 1857 align-items: center; 1858 gap: 6px; 1859 box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); 1860 } 1861 1862 .widget-sortable-label .dashicons { 1863 font-size: 14px; 1864 } 1865 1866 .system-info-section { 1867 margin-bottom: 30px; 1868 } 1869 1870 .system-info-title { 1871 margin-bottom: 15px; 1872 font-size: 18px; 1873 } 1874 1875 .system-info-card { 1876 background: #fff; 1877 padding: 20px; 1878 border: 1px solid #ddd; 1879 border-radius: 8px; 1880 } 1881 1882 .system-info-table { 1883 border: none; 1884 } 1885 1886 .system-info-label, 1887 .system-info-value { 1888 padding: 10px; 1889 } 1890 1891 .system-info-label { 1892 font-weight: 600; 1893 } 1894 1895 .system-info-section tbody tr:first-child .system-info-label { 1896 width: 200px; 1897 } 1898 1899 .system-info-row-alt { 1900 background: #f9f9f9; 1901 } 1902 1903 .system-info-path { 1904 font-family: Monaco, Menlo, Ubuntu Mono, monospace; 1905 font-size: 12px; 1906 } 1907 1908 @media (max-width: 782px) { 1909 .widget-two-col-grid { 1910 grid-template-columns: 1fr; 1911 } 1912 } -
redshape-easy-labels/tags/1.3.0/assets/js/admin.js
r3398988 r3465229 31 31 // Global error handler 32 32 error: function(xhr, status, error) { 33 // Log for debugging34 if (redshapeEasylabelsAjax.debug && window.console && console.error) {35 console.error('Easy Labels AJAX Error:', {36 status: status,37 error: error,38 responseText: xhr.responseText,39 statusCode: xhr.status,40 url: this.url,41 data: this.data42 });43 }44 45 33 // User-friendly message based on error type 46 34 let userMessage = __('Error occurred'); … … 90 78 ajaxOptions.success = function(response, status, xhr) { 91 79 try { 92 // Basic response validation93 if (redshapeEasylabelsAjax.debug && typeof response !== 'object') {94 console.warn('Easy Labels: Response is not an object', response);95 }96 97 80 // Call original success handler 98 81 if (originalSuccess && typeof originalSuccess === 'function') { … … 100 83 } 101 84 } catch (e) { 102 // Catch errors in success handler103 if (redshapeEasylabelsAjax.debug) {104 console.error('Easy Labels: Error in success handler', e);105 }106 85 showMessage('Errore nell\'elaborazione della risposta', 'error'); 107 86 } … … 112 91 return $.ajax(ajaxOptions); 113 92 } catch (e) { 114 if (redshapeEasylabelsAjax.debug) {115 console.error('Easy Labels: Exception in AJAX call', e);116 }117 93 showMessage('Errore critico. Ricarica la pagina.', 'error'); 118 94 return $.Deferred().reject(e); 119 95 } 120 96 } 121 122 // First initialize global event listeners123 initializeLabelEvents();124 97 125 98 // Insert labels next to post titles … … 229 202 initializeLabelEvents(); 230 203 initializeInlineLabels(); 204 205 // Re-apply inline labels when list table is refreshed via AJAX 206 $(document).on('redshapeEasylabels:tableUpdated', function() { 207 initializeInlineLabels(); 208 setTimeout(function() { 209 initializeDragAndDrop(); 210 }, 100); 211 }); 231 212 232 213 // Initialize events for labels … … 641 622 return labels; 642 623 } 624 625 function ensurePostLabelsCache(postId) { 626 if (typeof redshapeEasylabelsAjax === 'undefined') { 627 return null; 628 } 629 630 if (typeof redshapeEasylabelsAjax.post_labels === 'undefined' || redshapeEasylabelsAjax.post_labels === null) { 631 redshapeEasylabelsAjax.post_labels = {}; 632 } 633 634 var cacheKey = postId.toString(); 635 if (!Array.isArray(redshapeEasylabelsAjax.post_labels[cacheKey])) { 636 redshapeEasylabelsAjax.post_labels[cacheKey] = []; 637 } 638 639 return redshapeEasylabelsAjax.post_labels[cacheKey]; 640 } 641 642 function syncPostLabelsCacheAdd(postId, labelId, labelName, labelColor) { 643 var labelsCache = ensurePostLabelsCache(postId); 644 if (!labelsCache) { 645 return; 646 } 647 648 var idString = labelId.toString(); 649 var exists = labelsCache.some(function(label) { 650 return label && label.id && label.id.toString() === idString; 651 }); 652 653 if (!exists) { 654 labelsCache.push({ 655 id: idString, 656 name: labelName, 657 color: labelColor 658 }); 659 } 660 } 661 662 function syncPostLabelsCacheRemove(postId, labelId) { 663 var labelsCache = ensurePostLabelsCache(postId); 664 if (!labelsCache) { 665 return; 666 } 667 668 var idString = labelId.toString(); 669 redshapeEasylabelsAjax.post_labels[postId.toString()] = labelsCache.filter(function(label) { 670 return !(label && label.id && label.id.toString() === idString); 671 }); 672 } 643 673 644 674 // Function to add a label to post … … 670 700 // AFTER: Sync with OTHER wrappers (not current) 671 701 syncAddLabelToOtherVersions(postId, labelId, labelName, labelColor, wrapper); 702 703 // Keep frontend cache in sync to avoid stale labels after AJAX list refresh 704 syncPostLabelsCacheAdd(postId, labelId, labelName, labelColor); 672 705 673 706 // REINITIALIZE drag and drop for new elements … … 718 751 // SYNCHRONIZATION: Remove label from BOTH versions (inline and column) for same post 719 752 syncRemoveLabelFromAllVersions(postId, labelId); 753 754 // Keep frontend cache in sync to avoid stale labels after AJAX list refresh 755 syncPostLabelsCacheRemove(postId, labelId); 720 756 721 757 // IMPORTANT: Invalidate ALL dropdowns (including current one) … … 903 939 var allName = allMatch[1]; 904 940 var hasCheckmark = allBadge.hasClass('current'); 905 var checkmarkHtml = hasCheckmark ? '<span style="position: absolute; top: -4px; right: -4px; background: #46b450; color: white; width: 14px; height: 14px; border-radius: 50%; font-size: 10px; line-height: 14px; text-align: center; font-weight: bold; border: 1px solid white;">✓</span>' : '';941 var checkmarkHtml = hasCheckmark ? '<span class="filter-checkmark" style="position: absolute; top: -4px; right: -4px; background: #46b450; color: white; width: 14px; height: 14px; border-radius: 50%; font-size: 10px; line-height: 14px; text-align: center; font-weight: bold; border: 1px solid white;">✓</span>' : ''; 906 942 allBadge.html(allName + ' (' + total + ')' + checkmarkHtml); 907 943 } … … 916 952 var noLabelName = noLabelMatch[1]; 917 953 var hasNoLabelCheckmark = noLabelBadge.hasClass('current'); 918 var noLabelCheckmarkHtml = hasNoLabelCheckmark ? '<span style="position: absolute; top: -4px; right: -4px; background: #46b450; color: white; width: 14px; height: 14px; border-radius: 50%; font-size: 10px; line-height: 14px; text-align: center; font-weight: bold; border: 1px solid white;">✓</span>' : '';954 var noLabelCheckmarkHtml = hasNoLabelCheckmark ? '<span class="filter-checkmark" style="position: absolute; top: -4px; right: -4px; background: #46b450; color: white; width: 14px; height: 14px; border-radius: 50%; font-size: 10px; line-height: 14px; text-align: center; font-weight: bold; border: 1px solid white;">✓</span>' : ''; 919 955 noLabelBadge.html(noLabelName + ' (' + counts.no_label.count + ')' + noLabelCheckmarkHtml); 920 956 } … … 956 992 // ✅ Preserve checkmark if filter is active 957 993 var hasCheckmark = filterBadge.hasClass('current'); 958 var checkmarkHtml = hasCheckmark ? '<span style="position: absolute; top: -4px; right: -4px; background: #46b450; color: white; width: 14px; height: 14px; border-radius: 50%; font-size: 10px; line-height: 14px; text-align: center; font-weight: bold; border: 1px solid white;">✓</span>' : '';994 var checkmarkHtml = hasCheckmark ? '<span class="filter-checkmark" style="position: absolute; top: -4px; right: -4px; background: #46b450; color: white; width: 14px; height: 14px; border-radius: 50%; font-size: 10px; line-height: 14px; text-align: center; font-weight: bold; border: 1px solid white;">✓</span>' : ''; 959 995 filterBadge.html(newText + checkmarkHtml); 960 996 } … … 1874 1910 '<div class="widget-editor-header">' + 1875 1911 '<div class="widget-preview-large">' + 1876 '<span class="widget-preview-badge" style="display: inline-flex; align-items: center; gap: 8px; padding: 8px 16px; background: #2271b1; color: white; border-radius: 20px; font-size: 14px; font-weight: 500; text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);">' +1877 '<span class="dashicons dashicons-chart-pie" style="font-size: 16px; width: 16px; height: 16px;"></span>' +1912 '<span class="widget-preview-badge">' + 1913 '<span class="dashicons dashicons-chart-pie"></span>' + 1878 1914 '<span class="widget-preview-title">' + __('New Widget') + '</span>' + 1879 1915 '</span>' + … … 1893 1929 '</div>' + 1894 1930 '<div class="widget-field-row">' + 1895 '<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 15px;">' +1931 '<div class="widget-two-col-grid">' + 1896 1932 '<div class="widget-field-group">' + 1897 1933 '<label class="widget-field-label">' + __('Content Type') + '</label>' + … … 1912 1948 '</div>' + 1913 1949 '</div>' + 1914 '<div class="widget-bar-chart-options" data-widget-key="' + widgetKey + '" style="display: none; margin-top: 15px;">' +1915 '<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 15px;">' +1950 '<div class="widget-bar-chart-options" data-widget-key="' + widgetKey + '" style="display: none;">' + 1951 '<div class="widget-two-col-grid">' + 1916 1952 '<div class="widget-field-group">' + 1917 1953 '<label class="widget-field-label">' + __('Orientation') + '</label>' + … … 1939 1975 labelsHtml + 1940 1976 '</div>' + 1941 '<div class="widget-selected-labels-container" style=" margin-top: 15px;display: none;">' +1942 '<div style="font-weight: 600; margin-bottom: 10px; color: #23282d;">' +1943 '<span class="dashicons dashicons-sort" style="font-size: 16px; margin-right: 5px;"></span>' +1944 __('Labels Order') + ' <span style="font-weight: normal; color: #666; font-size: 12px;">(' + __('Drag to reorder') + ')</span>' +1977 '<div class="widget-selected-labels-container" style="display: none;">' + 1978 '<div class="widget-selected-labels-title">' + 1979 '<span class="dashicons dashicons-sort"></span>' + 1980 __('Labels Order') + ' <span class="widget-selected-labels-note">(' + __('Drag to reorder') + ')</span>' + 1945 1981 '</div>' + 1946 '<div class="widget-selected-labels-list" data-widget-key="' + widgetKey + '" style="display: flex; flex-wrap: wrap; gap: 8px; padding: 12px; background: #f9f9f9; border-radius: 4px; min-height: 50px;">' +1982 '<div class="widget-selected-labels-list" data-widget-key="' + widgetKey + '">' + 1947 1983 '</div>' + 1948 1984 '</div>' + 1949 '<small class="field-description " style="margin-top: 8px; color: #666;">' +1985 '<small class="field-description field-description-spaced">' + 1950 1986 __('Select which labels to include in this widget. Check "All labels" to include all available labels.') + 1951 1987 '</small>' + … … 2097 2133 if ($(this).is(':checked')) { 2098 2134 // Add to sortable list 2099 var $labelItem = $('<div class="widget-sortable-label" data-label-key="' + labelKey + '" style=" cursor: move; padding: 6px 12px; background: ' + labelColor + '; color: #fff; border-radius: 4px; display: flex; align-items: center; gap: 6px; box-shadow: 0 1px 3px rgba(0,0,0,0.1);">' +2100 '<span class="dashicons dashicons-menu" style="font-size: 14px;"></span>' +2135 var $labelItem = $('<div class="widget-sortable-label" data-label-key="' + labelKey + '" style="background: ' + labelColor + ';">' + 2136 '<span class="dashicons dashicons-menu"></span>' + 2101 2137 labelName + 2102 2138 '<input type="hidden" name="widgets[' + widgetKey + '][label_order][]" value="' + labelKey + '">' + -
redshape-easy-labels/tags/1.3.0/includes/admin-page.php
r3398988 r3465229 357 357 ?> 358 358 </div> 359 <small class="field-description " style="margin-top: 8px; color: #666;">359 <small class="field-description field-description-spaced"> 360 360 <?php redshape_easylabels_cl_e('If no type is selected, the label will be visible on all enabled content types.'); ?> 361 361 </small> … … 363 363 364 364 <!-- NUOVO: Opzioni di visualizzazione nei filtri --> 365 <div class="label-display-options" style="margin-top: 16px; padding-top: 16px; border-top: 1px solid #e5e5e5;">365 <div class="label-display-options"> 366 366 <!-- Checkbox Percentuale --> 367 <label class="label-checkbox-option " style="margin-bottom: 12px;">367 <label class="label-checkbox-option label-checkbox-option-spaced"> 368 368 <input type="checkbox" 369 369 name="labels[<?php echo esc_attr($redshape_easylabels_key); ?>][show_percentage]" … … 371 371 <?php checked(!empty($redshape_easylabels_label['show_percentage'])); ?> /> 372 372 <span class="checkbox-label"> 373 <span class="dashicons dashicons-chart-pie " style="color: #2271b1;"></span>373 <span class="dashicons dashicons-chart-pie icon-accent"></span> 374 374 <strong><?php redshape_easylabels_cl_e('Show percentage in filters'); ?></strong> 375 375 </span> 376 376 </label> 377 <small class="field-description " style="margin-left: 24px; display: block; margin-bottom: 12px; color: #666;">377 <small class="field-description field-description-indented field-description-with-bottom-gap"> 378 378 <?php redshape_easylabels_cl_e('Display percentage (2 decimals) relative to total posts next to count'); ?> 379 379 </small> … … 386 386 <?php checked(!empty($redshape_easylabels_label['show_fraction'])); ?> /> 387 387 <span class="checkbox-label"> 388 <span class="dashicons dashicons-editor-justify " style="color: #2271b1;"></span>388 <span class="dashicons dashicons-editor-justify icon-accent"></span> 389 389 <strong><?php redshape_easylabels_cl_e('Show fraction format (e.g.: 3/5)'); ?></strong> 390 390 </span> 391 391 </label> 392 <small class="field-description " style="margin-left: 24px; display: block; margin-top: 4px; color: #666;">392 <small class="field-description field-description-indented"> 393 393 <?php redshape_easylabels_cl_e('Display count as fraction relative to total posts (e.g.: 3/5 instead of just 3)'); ?> 394 394 </small> … … 504 504 <div class="label-field-group flex-grow"> 505 505 <label class="label-field-label"><?php redshape_easylabels_cl_e('Label name'); ?></label> 506 <div style="display: flex; gap: 8px; align-items: flex-start;">506 <div class="default-label-row"> 507 507 <input type="text" 508 508 name="default_labels[all][name]" … … 510 510 class="label-name-input all-label-input" 511 511 placeholder="<?php redshape_easylabels_cl_e('e.g. All, Everything, View All'); ?>" 512 style="flex: 1;"/>512 /> 513 513 <button type="button" 514 514 class="reset-default-label-btn" … … 519 519 data-default-border-color="#2271b1" 520 520 data-default-enabled="1" 521 title="<?php redshape_easylabels_cl_e('Reset to default'); ?>" 522 style="padding: 8px 12px; background: #f0f0f1; border: 1px solid #c3c4c7; border-radius: 4px; cursor: pointer; display: flex; align-items: center; gap: 4px; font-size: 13px; color: #2c3338; transition: all 0.2s;"> 523 <span class="dashicons dashicons-image-rotate" style="font-size: 16px; width: 16px; height: 16px;"></span> 521 title="<?php redshape_easylabels_cl_e('Reset to default'); ?>"> 522 <span class="dashicons dashicons-image-rotate"></span> 524 523 <?php redshape_easylabels_cl_e('Reset'); ?> 525 524 </button> … … 542 541 <div class="label-field-group"> 543 542 <label class="label-field-label"> 544 <span class="dashicons dashicons-admin-customizer " style="color: #2271b1; font-size: 16px;"></span>543 <span class="dashicons dashicons-admin-customizer icon-accent icon-sm"></span> 545 544 <?php redshape_easylabels_cl_e('Border Style'); ?> 546 545 </label> 547 <div class="border-style-options " style="display: grid; grid-template-columns: repeat(5, 1fr); gap: 10px;">546 <div class="border-style-options border-style-options-grid"> 548 547 <?php 549 548 $redshape_easylabels_current_all_border_style = !empty($redshape_easylabels_default_label_settings['all']['border_style']) ? $redshape_easylabels_default_label_settings['all']['border_style'] : 'none'; … … 574 573 <div class="label-field-group all-border-color-field" style="<?php echo empty($redshape_easylabels_default_label_settings['all']['border_style']) || $redshape_easylabels_default_label_settings['all']['border_style'] === 'none' ? 'display: none;' : ''; ?>"> 575 574 <label class="label-field-label"> 576 <span class="dashicons dashicons-art " style="color: #2271b1; font-size: 16px;"></span>575 <span class="dashicons dashicons-art icon-accent icon-sm"></span> 577 576 <?php redshape_easylabels_cl_e('Border Color'); ?> 578 577 </label> … … 625 624 <div class="label-field-group flex-grow"> 626 625 <label class="label-field-label"><?php redshape_easylabels_cl_e('Label name'); ?></label> 627 <div style="display: flex; gap: 8px; align-items: flex-start;">626 <div class="default-label-row"> 628 627 <input type="text" 629 628 name="default_labels[none][name]" … … 631 630 class="label-name-input none-label-input" 632 631 placeholder="<?php redshape_easylabels_cl_e('e.g. No Label, Unlabeled, Without Labels'); ?>" 633 style="flex: 1;"/>632 /> 634 633 <button type="button" 635 634 class="reset-default-label-btn" … … 640 639 data-default-border-color="#646970" 641 640 data-default-enabled="1" 642 title="<?php redshape_easylabels_cl_e('Reset to default'); ?>" 643 style="padding: 8px 12px; background: #f0f0f1; border: 1px solid #c3c4c7; border-radius: 4px; cursor: pointer; display: flex; align-items: center; gap: 4px; font-size: 13px; color: #2c3338; transition: all 0.2s;"> 644 <span class="dashicons dashicons-image-rotate" style="font-size: 16px; width: 16px; height: 16px;"></span> 641 title="<?php redshape_easylabels_cl_e('Reset to default'); ?>"> 642 <span class="dashicons dashicons-image-rotate"></span> 645 643 <?php redshape_easylabels_cl_e('Reset'); ?> 646 644 </button> … … 663 661 <div class="label-field-group"> 664 662 <label class="label-field-label"> 665 <span class="dashicons dashicons-admin-customizer " style="color: #2271b1; font-size: 16px;"></span>663 <span class="dashicons dashicons-admin-customizer icon-accent icon-sm"></span> 666 664 <?php redshape_easylabels_cl_e('Border Style'); ?> 667 665 </label> 668 <div class="border-style-options " style="display: grid; grid-template-columns: repeat(5, 1fr); gap: 10px;">666 <div class="border-style-options border-style-options-grid"> 669 667 <?php 670 668 $redshape_easylabels_current_border_style = !empty($redshape_easylabels_default_label_settings['none']['border_style']) ? $redshape_easylabels_default_label_settings['none']['border_style'] : 'none'; … … 695 693 <div class="label-field-group none-border-color-field" style="<?php echo empty($redshape_easylabels_default_label_settings['none']['border_style']) || $redshape_easylabels_default_label_settings['none']['border_style'] === 'none' ? 'display: none;' : ''; ?>"> 696 694 <label class="label-field-label"> 697 <span class="dashicons dashicons-art " style="color: #2271b1; font-size: 16px;"></span>695 <span class="dashicons dashicons-art icon-accent icon-sm"></span> 698 696 <?php redshape_easylabels_cl_e('Border Color'); ?> 699 697 </label> … … 1056 1054 <div class="backup-actions"> 1057 1055 <div class="file-upload-wrapper"> 1058 <input type="file" id="import-file" accept=".json" style="display: none;" />1056 <input type="file" id="import-file" accept=".json" class="hidden-file-input" /> 1059 1057 <button type="button" id="select-import-file" class="button button-secondary button-hero"> 1060 1058 <span class="dashicons dashicons-media-default"></span> … … 1064 1062 </div> 1065 1063 1066 <button type="button" id="import-settings" class="button button-primary button-hero " style="display: none;">1064 <button type="button" id="import-settings" class="button button-primary button-hero is-hidden"> 1067 1065 <span class="dashicons dashicons-upload"></span> 1068 1066 <span><?php redshape_easylabels_cl_e('Import Settings'); ?></span> … … 1110 1108 <div class="widget-editor-header"> 1111 1109 <div class="widget-preview-large"> 1112 <span class="widget-preview-badge" style="display: inline-flex; align-items: center; gap: 8px; padding: 8px 16px; background: #2271b1; color: white; border-radius: 20px; font-size: 14px; font-weight: 500; text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);">1113 <span class="dashicons dashicons-chart-pie" style="font-size: 16px; width: 16px; height: 16px;"></span>1110 <span class="widget-preview-badge"> 1111 <span class="dashicons dashicons-chart-pie"></span> 1114 1112 <span class="widget-preview-title"><?php echo esc_html($redshape_easylabels_widget['title']); ?></span> 1115 1113 </span> … … 1133 1131 1134 1132 <div class="widget-field-row"> 1135 <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 15px;">1133 <div class="widget-two-col-grid"> 1136 1134 <div class="widget-field-group"> 1137 1135 <label class="widget-field-label"><?php redshape_easylabels_cl_e('Content Type'); ?></label> … … 1159 1157 1160 1158 <!-- Bar Chart Options --> 1161 <div class="widget-bar-chart-options" data-widget-key="<?php echo esc_attr($redshape_easylabels_widget_key); ?>" style="display: <?php echo ($redshape_easylabels_widget['visualization_type'] === 'bar_chart') ? 'block' : 'none'; ?>; margin-top: 15px;">1162 <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 15px;">1159 <div class="widget-bar-chart-options" data-widget-key="<?php echo esc_attr($redshape_easylabels_widget_key); ?>" style="display: <?php echo ($redshape_easylabels_widget['visualization_type'] === 'bar_chart') ? 'block' : 'none'; ?>;"> 1160 <div class="widget-two-col-grid"> 1163 1161 <div class="widget-field-group"> 1164 1162 <label class="widget-field-label"><?php redshape_easylabels_cl_e('Orientation'); ?></label> … … 1253 1251 1254 1252 <!-- Selected Labels Sortable List --> 1255 <div class="widget-selected-labels-container" style=" margin-top: 15px;display: <?php echo (!empty($redshape_easylabels_labels_for_sortable) && !$redshape_easylabels_all_labels_checked) ? 'block' : 'none'; ?>;">1256 <div style="font-weight: 600; margin-bottom: 10px; color: #23282d;">1257 <span class="dashicons dashicons-sort" style="font-size: 16px; margin-right: 5px;"></span>1258 <?php redshape_easylabels_cl_e('Labels Order'); ?> <span style="font-weight: normal; color: #666; font-size: 12px;">(<?php redshape_easylabels_cl_e('Drag to reorder'); ?>)</span>1259 </div> 1260 <div class="widget-selected-labels-list" data-widget-key="<?php echo esc_attr($redshape_easylabels_widget_key); ?>" style="display: flex; flex-wrap: wrap; gap: 8px; padding: 12px; background: #f9f9f9; border-radius: 4px; min-height: 50px;">1253 <div class="widget-selected-labels-container" style="display: <?php echo (!empty($redshape_easylabels_labels_for_sortable) && !$redshape_easylabels_all_labels_checked) ? 'block' : 'none'; ?>;"> 1254 <div class="widget-selected-labels-title"> 1255 <span class="dashicons dashicons-sort"></span> 1256 <?php redshape_easylabels_cl_e('Labels Order'); ?> <span class="widget-selected-labels-note">(<?php redshape_easylabels_cl_e('Drag to reorder'); ?>)</span> 1257 </div> 1258 <div class="widget-selected-labels-list" data-widget-key="<?php echo esc_attr($redshape_easylabels_widget_key); ?>"> 1261 1259 <?php foreach ($redshape_easylabels_labels_for_sortable as $redshape_easylabels_selected_key): 1262 1260 if ($redshape_easylabels_selected_key === '__no_label__'): … … 1265 1263 $redshape_easylabels_label_color = $redshape_easylabels_no_label_color; 1266 1264 ?> 1267 <div class="widget-sortable-label" data-label-key="__no_label__" style=" cursor: move; padding: 6px 12px; background: <?php echo esc_attr($redshape_easylabels_label_color); ?>; color: #fff; border-radius: 4px; display: flex; align-items: center; gap: 6px; box-shadow: 0 1px 3px rgba(0,0,0,0.1);">1268 <span class="dashicons dashicons-menu" style="font-size: 14px;"></span>1265 <div class="widget-sortable-label" data-label-key="__no_label__" style="background: <?php echo esc_attr($redshape_easylabels_label_color); ?>;"> 1266 <span class="dashicons dashicons-menu"></span> 1269 1267 <?php echo esc_html($redshape_easylabels_label_name); ?> 1270 1268 <input type="hidden" name="widgets[<?php echo esc_attr($redshape_easylabels_widget_key); ?>][label_order][]" value="__no_label__"> … … 1274 1272 $redshape_easylabels_label = $redshape_easylabels_labels[$redshape_easylabels_selected_key]; 1275 1273 ?> 1276 <div class="widget-sortable-label" data-label-key="<?php echo esc_attr($redshape_easylabels_selected_key); ?>" style=" cursor: move; padding: 6px 12px; background: <?php echo esc_attr($redshape_easylabels_label['color']); ?>; color: #fff; border-radius: 4px; display: flex; align-items: center; gap: 6px; box-shadow: 0 1px 3px rgba(0,0,0,0.1);">1277 <span class="dashicons dashicons-menu" style="font-size: 14px;"></span>1274 <div class="widget-sortable-label" data-label-key="<?php echo esc_attr($redshape_easylabels_selected_key); ?>" style="background: <?php echo esc_attr($redshape_easylabels_label['color']); ?>;"> 1275 <span class="dashicons dashicons-menu"></span> 1278 1276 <?php echo esc_html($redshape_easylabels_label['name']); ?> 1279 1277 <input type="hidden" name="widgets[<?php echo esc_attr($redshape_easylabels_widget_key); ?>][label_order][]" value="<?php echo esc_attr($redshape_easylabels_selected_key); ?>"> … … 1284 1282 </div> 1285 1283 </div> 1286 <small class="field-description " style="margin-top: 8px; color: #666;">1284 <small class="field-description field-description-spaced"> 1287 1285 <?php redshape_easylabels_cl_e('Select which labels to include in this widget. Check "All labels" to include all available labels.'); ?> 1288 1286 </small> … … 1322 1320 1323 1321 <!-- Plugin Information --> 1324 <div class="system-info-section" style="margin-bottom: 30px;">1325 <h3 style="margin-bottom: 15px; font-size: 18px;"><?php redshape_easylabels_cl_e('Plugin Information'); ?></h3>1326 <div style="background: white; padding: 20px; border: 1px solid #ddd; border-radius: 8px;">1327 <table class="widefat " style="border: none;">1322 <div class="system-info-section"> 1323 <h3 class="system-info-title"><?php redshape_easylabels_cl_e('Plugin Information'); ?></h3> 1324 <div class="system-info-card"> 1325 <table class="widefat system-info-table"> 1328 1326 <tbody> 1329 1327 <tr> 1330 <td style="padding: 10px; font-weight: 600; width: 200px;"><?php redshape_easylabels_cl_e('Plugin Version'); ?></td>1331 <td style="padding: 10px;"><?php echo esc_html(REDSHAPE_EASYLABELS_VERSION); ?></td>1328 <td class="system-info-label"><?php redshape_easylabels_cl_e('Plugin Version'); ?></td> 1329 <td class="system-info-value"><?php echo esc_html(REDSHAPE_EASYLABELS_VERSION); ?></td> 1332 1330 </tr> 1333 <tr style="background: #f9f9f9;">1334 <td style="padding: 10px; font-weight: 600;"><?php redshape_easylabels_cl_e('WordPress Version'); ?></td>1335 <td style="padding: 10px;"><?php echo esc_html(get_bloginfo('version')); ?></td>1331 <tr class="system-info-row-alt"> 1332 <td class="system-info-label"><?php redshape_easylabels_cl_e('WordPress Version'); ?></td> 1333 <td class="system-info-value"><?php echo esc_html(get_bloginfo('version')); ?></td> 1336 1334 </tr> 1337 1335 <tr> 1338 <td style="padding: 10px; font-weight: 600;"><?php redshape_easylabels_cl_e('PHP Version'); ?></td>1339 <td style="padding: 10px;"><?php echo esc_html(phpversion()); ?></td>1336 <td class="system-info-label"><?php redshape_easylabels_cl_e('PHP Version'); ?></td> 1337 <td class="system-info-value"><?php echo esc_html(phpversion()); ?></td> 1340 1338 </tr> 1341 <tr style="background: #f9f9f9;">1342 <td style="padding: 10px; font-weight: 600;"><?php redshape_easylabels_cl_e('Plugin Path'); ?></td>1343 <td style="padding: 10px; font-family: monospace; font-size: 12px;"><?php echo esc_html(REDSHAPE_EASYLABELS_PLUGIN_PATH); ?></td>1339 <tr class="system-info-row-alt"> 1340 <td class="system-info-label"><?php redshape_easylabels_cl_e('Plugin Path'); ?></td> 1341 <td class="system-info-value system-info-path"><?php echo esc_html(REDSHAPE_EASYLABELS_PLUGIN_PATH); ?></td> 1344 1342 </tr> 1345 1343 </tbody> -
redshape-easy-labels/tags/1.3.0/includes/class-redshape-easylabels-cache.php
r3397460 r3465229 33 33 */ 34 34 const CACHE_DURATION = 3600; 35 36 /** 37 * Ottiene i post types abilitati dalle opzioni plugin con fallback retrocompatibile. 38 * 39 * @return array 40 */ 41 private static function get_enabled_post_types() { 42 $options = get_option('redshape_easylabels_options', array()); 43 44 if (!empty($options['role_settings']['enabled_post_types']) && is_array($options['role_settings']['enabled_post_types'])) { 45 return array_values($options['role_settings']['enabled_post_types']); 46 } 47 48 // Backward compatibility con vecchia struttura opzioni. 49 if (!empty($options['enabled_post_types']) && is_array($options['enabled_post_types'])) { 50 return array_values($options['enabled_post_types']); 51 } 52 53 return array('post', 'page'); 54 } 35 55 36 56 /** … … 68 88 public static function invalidate_label($label_id) { 69 89 // Ottieni tutti i post types abilitati 70 $options = get_option('redshape_easylabels_options', array()); 71 $enabled_post_types = isset($options['enabled_post_types']) ? $options['enabled_post_types'] : array('post'); 90 $enabled_post_types = self::get_enabled_post_types(); 72 91 73 92 $deleted_count = 0; … … 152 171 // Se nessun post type specificato, usa quelli abilitati nelle opzioni 153 172 if (empty($post_types)) { 154 $options = get_option('redshape_easylabels_options', array()); 155 $post_types = isset($options['enabled_post_types']) ? $options['enabled_post_types'] : array('post'); 173 $post_types = self::get_enabled_post_types(); 156 174 } 157 175 -
redshape-easy-labels/tags/1.3.0/includes/class-redshape-easylabels.php
r3398988 r3465229 41 41 add_action('wp_ajax_redshape_easylabels_save_filter_order', array($this, 'ajax_save_filter_order')); 42 42 add_action('wp_ajax_redshape_easylabels_get_filter_counts', array($this, 'ajax_get_filter_counts')); // NEW: Filter counts 43 add_action('wp_ajax_redshape_easylabels_debug_post_types', array($this, 'ajax_debug_post_types'));44 43 add_action('wp_ajax_redshape_easylabels_export_settings', array($this, 'ajax_export_settings')); // NEW: Export 45 44 add_action('wp_ajax_redshape_easylabels_import_settings', array($this, 'ajax_import_settings')); // NEW: Import … … 58 57 59 58 private $columns_rendered = array(); // Flag to avoid double rendering 60 private $columns_added = array(); // Flag to avoid double column addition per post type61 59 62 60 // Universal system - register hooks for ALL post types and check dynamically … … 94 92 // Reset flags when screen changes 95 93 public function reset_column_flags() { 96 $this->columns_added = array();97 94 $this->columns_rendered = array(); 98 95 } … … 242 239 // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.MissingUnslash 243 240 $filter_value = sanitize_text_field(wp_unslash($_GET['content_label_filter'])); 241 242 // Read relation for multi-filter mode (default: AND) 243 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Filter parameter, no data modification 244 $filter_relation = isset($_GET['content_label_relation']) ? strtolower(sanitize_text_field(wp_unslash($_GET['content_label_relation']))) : 'and'; 245 if (!in_array($filter_relation, array('and', 'or'), true)) { 246 $filter_relation = 'and'; 247 } 244 248 245 249 // Check if multiple filters (comma-separated) 246 $filter_values = array_ map('trim', explode(',', $filter_value));250 $filter_values = array_filter(array_map('trim', explode(',', $filter_value))); 247 251 $has_multiple = count($filter_values) > 1; 248 252 … … 253 257 254 258 if ($has_multiple) { 255 // Multiple filters with AND relation256 $sub_queries = array('relation' => 'AND');259 // Multiple filters with configurable relation (AND/OR) 260 $sub_queries = array('relation' => strtoupper($filter_relation)); 257 261 258 262 foreach ($filter_values as $single_filter) { … … 339 343 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Filter parameter, no data modification 340 344 $current_filter = isset($_GET['content_label_filter']) ? sanitize_text_field(wp_unslash($_GET['content_label_filter'])) : ''; 341 $base_url = remove_query_arg('content_label_filter'); 345 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Filter parameter, no data modification 346 $current_filter_relation = isset($_GET['content_label_relation']) ? strtolower(sanitize_text_field(wp_unslash($_GET['content_label_relation']))) : 'and'; 347 if (!in_array($current_filter_relation, array('and', 'or'), true)) { 348 $current_filter_relation = 'and'; 349 } 350 351 $base_url = remove_query_arg(array('content_label_filter', 'content_label_relation')); 342 352 343 353 // NUOVO: Conta i post SENZA etichette e il totale (prima di generare l'HTML) … … 435 445 $all_badge_html .= esc_html($all_name) . ' (' . intval($total_posts_count) . ')'; 436 446 if ($all_class === 'current') { 437 $all_badge_html .= '<span style="position: absolute; top: -4px; right: -4px; background: #46b450; color: white; width: 14px; height: 14px; border-radius: 50%; font-size: 10px; line-height: 14px; text-align: center; font-weight: bold; border: 1px solid white;">✓</span>';447 $all_badge_html .= '<span class="filter-checkmark" style="position: absolute; top: -4px; right: -4px; background: #46b450; color: white; width: 14px; height: 14px; border-radius: 50%; font-size: 10px; line-height: 14px; text-align: center; font-weight: bold; border: 1px solid white;">✓</span>'; 438 448 } 439 449 $all_badge_html .= '</span>'; … … 463 473 $no_label_badge_html .= esc_html($no_label_name) . ' (' . intval($no_label_count) . ')'; 464 474 if ($no_label_class === 'current') { 465 $no_label_badge_html .= '<span style="position: absolute; top: -4px; right: -4px; background: #46b450; color: white; width: 14px; height: 14px; border-radius: 50%; font-size: 10px; line-height: 14px; text-align: center; font-weight: bold; border: 1px solid white;">✓</span>';475 $no_label_badge_html .= '<span class="filter-checkmark" style="position: absolute; top: -4px; right: -4px; background: #46b450; color: white; width: 14px; height: 14px; border-radius: 50%; font-size: 10px; line-height: 14px; text-align: center; font-weight: bold; border: 1px solid white;">✓</span>'; 466 476 } 467 477 $no_label_badge_html .= '</span>'; … … 484 494 $quick_filter_html .= '</div>'; 485 495 486 // Pulsante "Applica" per multi-select (inizialmente nascosto) 487 $quick_filter_html .= '<button type="button" class="multi-select-apply-btn" id="multi-apply-btn">' . esc_html(redshape_easylabels_cl__('Apply')) . '</button>'; 488 489 // Separatore verticale dopo Apply 496 // Selettore relazione AND/OR per multi-select 497 $quick_filter_html .= '<div class="filter-relation-toggle" id="filter-relation-toggle" data-default-relation="' . esc_attr($current_filter_relation) . '">'; 498 $quick_filter_html .= '<button type="button" class="relation-btn relation-btn-and" data-relation="and">AND</button>'; 499 $quick_filter_html .= '<button type="button" class="relation-btn relation-btn-or" data-relation="or">OR</button>'; 500 $quick_filter_html .= '</div>'; 501 502 // Separatore verticale dopo selettore relazione 490 503 $quick_filter_html .= '<span style="width: 1px; height: 16px; background-color: #ddd; margin: 0 4px;"></span>'; 491 504 } … … 593 606 $badge_html .= esc_html($label['name']) . ' ' . $count_display; 594 607 if ($is_active) { 595 $badge_html .= '<span style="position: absolute; top: -4px; right: -4px; background: #46b450; color: white; width: 14px; height: 14px; border-radius: 50%; font-size: 10px; line-height: 14px; text-align: center; font-weight: bold; border: 1px solid white;">✓</span>';608 $badge_html .= '<span class="filter-checkmark" style="position: absolute; top: -4px; right: -4px; background: #46b450; color: white; width: 14px; height: 14px; border-radius: 50%; font-size: 10px; line-height: 14px; text-align: center; font-weight: bold; border: 1px solid white;">✓</span>'; 596 609 } 597 610 $badge_html .= '</span>'; … … 712 725 'post_type_enabled' => $post_type_enabled, // NUOVO: flag per il JavaScript 713 726 'translations' => $translations, // NUOVO: Traduzioni per JavaScript 714 'debug' => defined('WP_DEBUG') && WP_DEBUG, // Debug mode flag715 727 'no_label_name' => $no_label_name, // Nome personalizzato per No Label 716 728 'no_label_color' => $no_label_color // Colore personalizzato per No Label … … 878 890 border: 1px solid white; 879 891 } 880 . multi-select-apply-btn{892 .filter-relation-toggle { 881 893 display: none; 882 background-color: #2271b1; 883 color: white; 884 padding: 4px 12px; 894 align-items: center; 895 gap: 4px; 896 padding: 2px; 897 background: #f0f0f1; 885 898 border-radius: 12px; 899 } 900 .filter-relation-toggle.visible { 901 display: inline-flex; 902 } 903 .relation-btn { 904 border: 1px solid #c3c4c7; 905 background: #fff; 906 color: #50575e; 907 padding: 2px 10px; 908 border-radius: 10px; 886 909 font-size: 11px; 887 font-weight: 500; 888 cursor: grab; 889 transition: all 0.2s ease; 890 position: relative; 891 border: 4px solid #135e96; 892 } 893 .multi-select-apply-btn:hover { 894 transform: scale(1.05); 895 box-shadow: 0 2px 4px rgba(0,0,0,0.2); 896 } 897 .multi-select-apply-btn.visible { 898 display: inline-block; 910 line-height: 1.5; 911 cursor: pointer; 912 } 913 .relation-btn.active { 914 background: #2271b1; 915 border-color: #2271b1; 916 color: #fff; 899 917 } 900 918 '; … … 926 944 var isMultiMode = false; 927 945 var selectedFilters = []; 928 var applyBtn = $("#multi-apply-btn"); 929 930 applyBtn.on("click", function(e) { 946 var filterRelation = "and"; 947 var currentSingleFilter = ""; 948 var relationToggle = $("#filter-relation-toggle"); 949 950 function normalizeFromParams(params) { 951 isMultiMode = params.get("multi_mode") === "1"; 952 selectedFilters = (params.get("content_label_filter") || "").split(",").filter(function(v) { return v !== ""; }); 953 filterRelation = params.get("content_label_relation") === "or" ? "or" : "and"; 954 currentSingleFilter = !isMultiMode && selectedFilters.length > 0 ? selectedFilters[0] : ""; 955 } 956 957 function getCheckmarkHtml() { 958 return "<span class=\"filter-checkmark\" style=\"position: absolute; top: -4px; right: -4px; background: #46b450; color: white; width: 14px; height: 14px; border-radius: 50%; font-size: 10px; line-height: 14px; text-align: center; font-weight: bold; border: 1px solid white;\">✓</span>"; 959 } 960 961 function setCurrentBadge(labelId) { 962 var allBadges = $(".filter-badge, .filter-badge-fixed"); 963 allBadges.removeClass("current"); 964 allBadges.find(".filter-checkmark").remove(); 965 966 var selector = labelId === "" 967 ? ".filter-badge-fixed[data-label-id=\"\"]" 968 : ".filter-badge[data-label-id=\"" + labelId + "\"], .filter-badge-fixed[data-label-id=\"" + labelId + "\"]"; 969 970 var activeBadge = $(selector).first(); 971 if (activeBadge.length > 0) { 972 activeBadge.addClass("current"); 973 if (activeBadge.find(".filter-checkmark").length === 0) { 974 activeBadge.append(getCheckmarkHtml()); 975 } 976 } 977 } 978 979 function updateRelationUI() { 980 relationToggle = $("#filter-relation-toggle"); 981 relationToggle.find(".relation-btn").removeClass("active"); 982 relationToggle.find(".relation-btn[data-relation=\"" + filterRelation + "\"]").addClass("active"); 983 } 984 985 function repositionFilterBar() { 986 var currentFilterBar = $(".content-labels-quick-filter-bar"); 987 if (currentFilterBar.length > 0) { 988 if (currentFilterBar.parent().is("a")) { 989 currentFilterBar.unwrap(); 990 } 991 var topNav = $(".tablenav.top"); 992 if (topNav.length > 0) { 993 currentFilterBar.detach().insertAfter(topNav); 994 } 995 currentFilterBar.css({ 996 "display": "block", 997 "float": "none", 998 "clear": "both", 999 "width": "100%" 1000 }); 1001 } 1002 } 1003 1004 function applyFiltersAjax(params) { 1005 var query = params.toString(); 1006 var targetUrl = window.location.pathname + (query ? "?" + query : ""); 1007 1008 $.ajax({ 1009 url: targetUrl, 1010 type: "GET", 1011 success: function(responseHtml) { 1012 var responseDoc = $("<div>").html(responseHtml); 1013 var newListTable = responseDoc.find("#posts-filter .wp-list-table").first(); 1014 var newTopNav = responseDoc.find("#posts-filter .tablenav.top").first(); 1015 var newBottomNav = responseDoc.find("#posts-filter .tablenav.bottom").first(); 1016 1017 if (newListTable.length === 0) { 1018 window.location.href = targetUrl; 1019 return; 1020 } 1021 1022 var currentListTable = $("#posts-filter .wp-list-table").first(); 1023 if (currentListTable.length > 0) { 1024 currentListTable.replaceWith(newListTable); 1025 } else { 1026 window.location.href = targetUrl; 1027 return; 1028 } 1029 1030 var currentTopNav = $("#posts-filter .tablenav.top").first(); 1031 if (currentTopNav.length > 0 && newTopNav.length > 0) { 1032 currentTopNav.replaceWith(newTopNav); 1033 } 1034 1035 var currentBottomNav = $("#posts-filter .tablenav.bottom").first(); 1036 if (currentBottomNav.length > 0 && newBottomNav.length > 0) { 1037 currentBottomNav.replaceWith(newBottomNav); 1038 } 1039 1040 window.history.replaceState({}, "", targetUrl); 1041 1042 var appliedParams = new URLSearchParams(query); 1043 normalizeFromParams(appliedParams); 1044 1045 updateRelationUI(); 1046 syncMultiVisualState(); 1047 attachBadgeHandlers(); 1048 $(document).trigger("redshapeEasylabels:tableUpdated"); 1049 }, 1050 error: function() { 1051 window.location.href = targetUrl; 1052 } 1053 }); 1054 } 1055 1056 function syncMultiVisualState() { 1057 if (isMultiMode) { 1058 $("#filter-mode-checkbox").prop("checked", true); 1059 $(".filter-mode-slider").css("background-color", "#46b450"); 1060 $(".filter-badge-fixed[data-label-id=\"\"]").hide(); 1061 $("#filter-relation-toggle").addClass("visible"); 1062 $(".filter-badge, .filter-badge-fixed").removeClass("multi-selected current"); 1063 $(".filter-badge, .filter-badge-fixed").find(".filter-checkmark").remove(); 1064 1065 selectedFilters.forEach(function(filterId) { 1066 $(".filter-badge[data-label-id=\"" + filterId + "\"], .filter-badge-fixed[data-label-id=\"" + filterId + "\"]").addClass("multi-selected"); 1067 }); 1068 } else { 1069 $("#filter-mode-checkbox").prop("checked", false); 1070 $(".filter-mode-slider").css("background-color", "#ccc"); 1071 $(".filter-badge-fixed[data-label-id=\"\"]").show(); 1072 $("#filter-relation-toggle").removeClass("visible"); 1073 $(".filter-badge, .filter-badge-fixed").removeClass("multi-selected"); 1074 setCurrentBadge(currentSingleFilter); 1075 } 1076 } 1077 1078 relationToggle.find(".relation-btn").on("click", function(e) { 931 1079 e.preventDefault(); 932 if (selectedFilters.length > 0) { 933 var params = new URLSearchParams(window.location.search); 934 params.set("content_label_filter", selectedFilters.join(",")); 935 window.location.href = window.location.pathname + "?" + params.toString(); 1080 filterRelation = $(this).data("relation") === "or" ? "or" : "and"; 1081 updateRelationUI(); 1082 1083 if (isMultiMode && selectedFilters.length > 0) { 1084 var relationParams = new URLSearchParams(window.location.search); 1085 relationParams.set("multi_mode", "1"); 1086 relationParams.set("content_label_filter", selectedFilters.join(",")); 1087 relationParams.set("content_label_relation", filterRelation); 1088 applyFiltersAjax(relationParams); 936 1089 } 937 1090 }); … … 945 1098 946 1099 if (labelId === "") { 947 window.location.href = filterUrl; 1100 var allParams = new URLSearchParams(window.location.search); 1101 allParams.delete("content_label_filter"); 1102 allParams.delete("content_label_relation"); 1103 allParams.delete("multi_mode"); 1104 applyFiltersAjax(allParams); 948 1105 return false; 949 1106 } 950 1107 951 1108 if (!isMulti) { 952 window.location.href = filterUrl;1109 applyFiltersAjax(new URLSearchParams((filterUrl.split("?")[1] || ""))); 953 1110 return false; 954 1111 } else { … … 965 1122 $(this).addClass("multi-selected"); 966 1123 } 1124 1125 var multiParams = new URLSearchParams(window.location.search); 1126 multiParams.set("multi_mode", "1"); 1127 multiParams.set("content_label_relation", filterRelation); 1128 1129 if (selectedFilters.length > 0) { 1130 multiParams.set("content_label_filter", selectedFilters.join(",")); 1131 } else { 1132 multiParams.delete("content_label_filter"); 1133 } 1134 1135 applyFiltersAjax(multiParams); 967 1136 968 1137 return false; … … 975 1144 // Check if multi-mode is active from URL 976 1145 var params = new URLSearchParams(window.location.search); 977 if (params.get("multi_mode") === "1") { 978 $("#filter-mode-checkbox").prop("checked", true); 979 isMultiMode = true; 980 $(".filter-mode-slider").css("background-color", "#46b450"); 981 $(".filter-badge-fixed[data-label-id=\'\']").hide(); 982 applyBtn.addClass("visible"); 983 984 var activeFilters = params.get("content_label_filter"); 985 if (activeFilters) { 986 selectedFilters = activeFilters.split(","); 987 selectedFilters.forEach(function(filterId) { 988 $(".filter-badge[data-label-id=\'" + filterId + "\'], .filter-badge-fixed[data-label-id=\'" + filterId + "\']").addClass("multi-selected"); 989 }); 990 } 991 } 1146 normalizeFromParams(params); 1147 1148 if (!params.get("content_label_relation") && relationToggle.data("default-relation") === "or") { 1149 filterRelation = "or"; 1150 } 1151 1152 updateRelationUI(); 1153 syncMultiVisualState(); 992 1154 993 1155 // Toggle multi-select mode 994 1156 $("#filter-mode-checkbox").on("change", function() { 1157 var hadActiveFilters = selectedFilters.length > 0; 995 1158 isMultiMode = $(this).is(":checked"); 996 1159 selectedFilters = []; 997 $(".filter-badge, .filter-badge-fixed").removeClass("multi-selected");1160 currentSingleFilter = ""; 998 1161 999 var params = new URLSearchParams(window.location.search); 1000 params.delete("content_label_filter"); 1162 var toggleParams = new URLSearchParams(window.location.search); 1163 toggleParams.delete("content_label_filter"); 1164 toggleParams.delete("content_label_relation"); 1001 1165 1002 1166 if (isMultiMode) { 1003 params.set("multi_mode", "1"); 1167 toggleParams.set("multi_mode", "1"); 1168 toggleParams.set("content_label_relation", filterRelation); 1004 1169 } else { 1005 params.delete("multi_mode");1170 toggleParams.delete("multi_mode"); 1006 1171 } 1007 1008 var newUrl = window.location.pathname + (params.toString() ? "?" + params.toString() : ""); 1009 window.location.href = newUrl; 1172 1173 if (hadActiveFilters) { 1174 applyFiltersAjax(toggleParams); 1175 } else { 1176 window.history.replaceState({}, "", window.location.pathname + (toggleParams.toString() ? "?" + toggleParams.toString() : "")); 1177 syncMultiVisualState(); 1178 updateRelationUI(); 1179 } 1010 1180 }); 1011 1181 }); … … 1503 1673 setTimeout(function() { newCardEl.removeClass('new-label'); }, 300); 1504 1674 labelCounter++; 1505 } catch(error) { 1506 if (typeof redshapeEasylabelsAjax !== 'undefined' && redshapeEasylabelsAjax.debug) { 1507 console.error('Error adding label:', error); 1508 } 1675 } catch(_error) { 1509 1676 } 1510 1677 }); -
redshape-easy-labels/tags/1.3.0/readme.txt
r3409971 r3465229 5 5 Tested up to: 6.9 6 6 Requires PHP: 7.0 7 Stable tag: 1. 2.07 Stable tag: 1.3.0 8 8 License: GPLv2 or later 9 9 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 77 77 = How does multi-select filtering work? = 78 78 79 Toggle the Multi switch in the quick filters to enable multi-select mode. Click multiple label badges to select them (they'll show a green checkmark), then click Apply to filter posts that have ALL the selected labels together. The filter uses AND logic, so only posts with every selected label will be shown.79 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. 80 80 81 81 == Screenshots == … … 93 93 94 94 == Changelog == 95 96 = 1.3.0 = 97 * Maintenance: Version bump to 1.3.0 98 * Compatibility: Tested up to WordPress 6.9 99 * New: Multi-select filters now support AND/OR relation modes 100 * Enhancement: Quick filters now apply instantly via AJAX (no Apply button) 101 * Fix: Removed duplicated uninstall cleanup blocks (cache/meta/transient) 102 * Fix: Aligned cache post type source with role_settings[enabled_post_types] and backward-compatible fallback 103 * Fix: Removed duplicate initializeLabelEvents() call in admin JavaScript 95 104 96 105 = 1.2.0 = … … 178 187 == Upgrade Notice == 179 188 189 = 1.3.0 = 190 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. 191 180 192 = 1.2.0 = 181 193 Major feature update: Adds dashboard widgets with 5 visualization types and interactive click-to-filter functionality. Includes drag & drop label ordering for complete customization. -
redshape-easy-labels/tags/1.3.0/redshape-easy-labels.php
r3398988 r3465229 3 3 * Plugin Name: REDSHAPE Easy Labels 4 4 * 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). 5 * Version: 1. 2.05 * Version: 1.3.0 6 6 * Author: REDSHAPE 7 7 * Author URI: https://redshape.it … … 18 18 19 19 // Define plugin constants 20 define('REDSHAPE_EASYLABELS_VERSION', '1. 2.0');20 define('REDSHAPE_EASYLABELS_VERSION', '1.3.0'); 21 21 define('REDSHAPE_EASYLABELS_PLUGIN_URL', plugin_dir_url(__FILE__)); 22 22 define('REDSHAPE_EASYLABELS_PLUGIN_PATH', plugin_dir_path(__FILE__)); … … 48 48 function redshape_easylabels_cl_e($string) { 49 49 echo esc_html(Redshape_Easylabels_I18n::__($string)); 50 }51 }52 53 /**54 * Helper function for plugin logging55 * Only logs if WP_DEBUG is enabled to avoid production logging56 * Uses WordPress logging system to avoid direct error_log usage57 *58 * @param string $message The message to log59 */60 if (!function_exists('redshape_easylabels_log')) {61 function redshape_easylabels_log($message) {62 // Only log in debug mode to avoid production logging63 if (defined('WP_DEBUG') && WP_DEBUG && defined('WP_DEBUG_LOG') && WP_DEBUG_LOG) {64 // Use WordPress debug system - writes to wp-content/debug.log65 $log_message = 'REDSHAPE Easy Labels: ' . $message;66 67 // Use WordPress logging system - only wp_debug_log to avoid filesystem issues68 if (function_exists('wp_debug_log')) {69 wp_debug_log($log_message);70 }71 // If wp_debug_log is not available, silently skip logging to avoid warnings72 }73 50 } 74 51 } -
redshape-easy-labels/tags/1.3.0/uninstall.php
r3397353 r3465229 54 54 // 6. CLEANUP TRANSIENTS (if any remain) 55 55 delete_transient('redshape_easylabels_version_check'); 56 57 // 3. RIMUOVI CACHE (se presente)58 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching59 $wpdb->query(60 "DELETE FROM {$wpdb->options}61 WHERE option_name LIKE 'redshape_easylabels_counts_%'"62 );63 64 // 4. RIMUOVI TUTTI I META DATI DELLE ETICHETTE65 // Meta key: _content_labels (array di etichette per ogni post)66 delete_post_meta_by_key('_content_labels');67 68 // 5. RIMUOVI TUTTI I META DATI DELLE NOTE69 // Meta key: _content_note (nota testuale per ogni post)70 delete_post_meta_by_key('_content_note');71 72 // 6. CLEANUP TRANSIENTS (if any remain)73 delete_transient('redshape_easylabels_version_check');74 56 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching 75 57 $wpdb->query( -
redshape-easy-labels/trunk/assets/css/admin-settings.css
r3398988 r3465229 176 176 margin-top: 4px; 177 177 display: block; 178 } 179 180 .field-description-spaced { 181 margin-top: 8px; 182 color: #666; 183 } 184 185 .field-description-indented { 186 margin-left: 24px; 187 display: block; 188 color: #666; 189 } 190 191 .field-description-with-bottom-gap { 192 margin-bottom: 12px; 193 } 194 195 .icon-accent { 196 color: #2271b1; 197 } 198 199 .icon-sm { 200 font-size: 16px; 201 } 202 203 .label-display-options { 204 margin-top: 16px; 205 padding-top: 16px; 206 border-top: 1px solid #e5e5e5; 207 } 208 209 .label-checkbox-option-spaced { 210 margin-bottom: 12px; 211 } 212 213 .default-label-row { 214 display: flex; 215 gap: 8px; 216 align-items: flex-start; 217 } 218 219 .default-label-row .label-name-input { 220 flex: 1; 178 221 } 179 222 … … 800 843 /* Reset button per default labels */ 801 844 .reset-default-label-btn { 845 display: inline-flex; 846 align-items: center; 847 gap: 4px; 848 padding: 8px 12px; 849 background: #f0f0f1; 850 border: 1px solid #c3c4c7; 851 border-radius: 4px; 852 cursor: pointer; 853 font-size: 13px; 854 color: #2c3338; 802 855 transition: all 0.2s ease; 803 856 } … … 816 869 817 870 .reset-default-label-btn .dashicons { 871 font-size: 16px; 872 width: 16px; 873 height: 16px; 818 874 transition: transform 0.3s ease; 819 875 } … … 827 883 .border-style-options { 828 884 width: 100%; 885 } 886 887 .border-style-options-grid { 888 display: grid; 889 grid-template-columns: repeat(5, 1fr); 890 gap: 10px; 829 891 } 830 892 … … 1720 1782 transition: all 0.2s ease; 1721 1783 } 1784 1785 .hidden-file-input, 1786 .is-hidden { 1787 display: none; 1788 } 1789 1790 .widget-preview-badge { 1791 display: inline-flex; 1792 align-items: center; 1793 gap: 8px; 1794 padding: 8px 16px; 1795 background: #2271b1; 1796 color: #fff; 1797 border-radius: 20px; 1798 font-size: 14px; 1799 font-weight: 500; 1800 text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); 1801 box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); 1802 } 1803 1804 .widget-preview-badge .dashicons { 1805 font-size: 16px; 1806 width: 16px; 1807 height: 16px; 1808 } 1809 1810 .widget-two-col-grid { 1811 display: grid; 1812 grid-template-columns: 1fr 1fr; 1813 gap: 15px; 1814 } 1815 1816 .widget-bar-chart-options { 1817 margin-top: 15px; 1818 } 1819 1820 .widget-selected-labels-container { 1821 margin-top: 15px; 1822 } 1823 1824 .widget-selected-labels-title { 1825 font-weight: 600; 1826 margin-bottom: 10px; 1827 color: #23282d; 1828 } 1829 1830 .widget-selected-labels-title .dashicons { 1831 font-size: 16px; 1832 margin-right: 5px; 1833 } 1834 1835 .widget-selected-labels-note { 1836 font-weight: 400; 1837 color: #666; 1838 font-size: 12px; 1839 } 1840 1841 .widget-selected-labels-list { 1842 display: flex; 1843 flex-wrap: wrap; 1844 gap: 8px; 1845 padding: 12px; 1846 background: #f9f9f9; 1847 border-radius: 4px; 1848 min-height: 50px; 1849 } 1850 1851 .widget-sortable-label { 1852 cursor: move; 1853 padding: 6px 12px; 1854 color: #fff; 1855 border-radius: 4px; 1856 display: flex; 1857 align-items: center; 1858 gap: 6px; 1859 box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); 1860 } 1861 1862 .widget-sortable-label .dashicons { 1863 font-size: 14px; 1864 } 1865 1866 .system-info-section { 1867 margin-bottom: 30px; 1868 } 1869 1870 .system-info-title { 1871 margin-bottom: 15px; 1872 font-size: 18px; 1873 } 1874 1875 .system-info-card { 1876 background: #fff; 1877 padding: 20px; 1878 border: 1px solid #ddd; 1879 border-radius: 8px; 1880 } 1881 1882 .system-info-table { 1883 border: none; 1884 } 1885 1886 .system-info-label, 1887 .system-info-value { 1888 padding: 10px; 1889 } 1890 1891 .system-info-label { 1892 font-weight: 600; 1893 } 1894 1895 .system-info-section tbody tr:first-child .system-info-label { 1896 width: 200px; 1897 } 1898 1899 .system-info-row-alt { 1900 background: #f9f9f9; 1901 } 1902 1903 .system-info-path { 1904 font-family: Monaco, Menlo, Ubuntu Mono, monospace; 1905 font-size: 12px; 1906 } 1907 1908 @media (max-width: 782px) { 1909 .widget-two-col-grid { 1910 grid-template-columns: 1fr; 1911 } 1912 } -
redshape-easy-labels/trunk/assets/js/admin.js
r3398988 r3465229 31 31 // Global error handler 32 32 error: function(xhr, status, error) { 33 // Log for debugging34 if (redshapeEasylabelsAjax.debug && window.console && console.error) {35 console.error('Easy Labels AJAX Error:', {36 status: status,37 error: error,38 responseText: xhr.responseText,39 statusCode: xhr.status,40 url: this.url,41 data: this.data42 });43 }44 45 33 // User-friendly message based on error type 46 34 let userMessage = __('Error occurred'); … … 90 78 ajaxOptions.success = function(response, status, xhr) { 91 79 try { 92 // Basic response validation93 if (redshapeEasylabelsAjax.debug && typeof response !== 'object') {94 console.warn('Easy Labels: Response is not an object', response);95 }96 97 80 // Call original success handler 98 81 if (originalSuccess && typeof originalSuccess === 'function') { … … 100 83 } 101 84 } catch (e) { 102 // Catch errors in success handler103 if (redshapeEasylabelsAjax.debug) {104 console.error('Easy Labels: Error in success handler', e);105 }106 85 showMessage('Errore nell\'elaborazione della risposta', 'error'); 107 86 } … … 112 91 return $.ajax(ajaxOptions); 113 92 } catch (e) { 114 if (redshapeEasylabelsAjax.debug) {115 console.error('Easy Labels: Exception in AJAX call', e);116 }117 93 showMessage('Errore critico. Ricarica la pagina.', 'error'); 118 94 return $.Deferred().reject(e); 119 95 } 120 96 } 121 122 // First initialize global event listeners123 initializeLabelEvents();124 97 125 98 // Insert labels next to post titles … … 229 202 initializeLabelEvents(); 230 203 initializeInlineLabels(); 204 205 // Re-apply inline labels when list table is refreshed via AJAX 206 $(document).on('redshapeEasylabels:tableUpdated', function() { 207 initializeInlineLabels(); 208 setTimeout(function() { 209 initializeDragAndDrop(); 210 }, 100); 211 }); 231 212 232 213 // Initialize events for labels … … 641 622 return labels; 642 623 } 624 625 function ensurePostLabelsCache(postId) { 626 if (typeof redshapeEasylabelsAjax === 'undefined') { 627 return null; 628 } 629 630 if (typeof redshapeEasylabelsAjax.post_labels === 'undefined' || redshapeEasylabelsAjax.post_labels === null) { 631 redshapeEasylabelsAjax.post_labels = {}; 632 } 633 634 var cacheKey = postId.toString(); 635 if (!Array.isArray(redshapeEasylabelsAjax.post_labels[cacheKey])) { 636 redshapeEasylabelsAjax.post_labels[cacheKey] = []; 637 } 638 639 return redshapeEasylabelsAjax.post_labels[cacheKey]; 640 } 641 642 function syncPostLabelsCacheAdd(postId, labelId, labelName, labelColor) { 643 var labelsCache = ensurePostLabelsCache(postId); 644 if (!labelsCache) { 645 return; 646 } 647 648 var idString = labelId.toString(); 649 var exists = labelsCache.some(function(label) { 650 return label && label.id && label.id.toString() === idString; 651 }); 652 653 if (!exists) { 654 labelsCache.push({ 655 id: idString, 656 name: labelName, 657 color: labelColor 658 }); 659 } 660 } 661 662 function syncPostLabelsCacheRemove(postId, labelId) { 663 var labelsCache = ensurePostLabelsCache(postId); 664 if (!labelsCache) { 665 return; 666 } 667 668 var idString = labelId.toString(); 669 redshapeEasylabelsAjax.post_labels[postId.toString()] = labelsCache.filter(function(label) { 670 return !(label && label.id && label.id.toString() === idString); 671 }); 672 } 643 673 644 674 // Function to add a label to post … … 670 700 // AFTER: Sync with OTHER wrappers (not current) 671 701 syncAddLabelToOtherVersions(postId, labelId, labelName, labelColor, wrapper); 702 703 // Keep frontend cache in sync to avoid stale labels after AJAX list refresh 704 syncPostLabelsCacheAdd(postId, labelId, labelName, labelColor); 672 705 673 706 // REINITIALIZE drag and drop for new elements … … 718 751 // SYNCHRONIZATION: Remove label from BOTH versions (inline and column) for same post 719 752 syncRemoveLabelFromAllVersions(postId, labelId); 753 754 // Keep frontend cache in sync to avoid stale labels after AJAX list refresh 755 syncPostLabelsCacheRemove(postId, labelId); 720 756 721 757 // IMPORTANT: Invalidate ALL dropdowns (including current one) … … 903 939 var allName = allMatch[1]; 904 940 var hasCheckmark = allBadge.hasClass('current'); 905 var checkmarkHtml = hasCheckmark ? '<span style="position: absolute; top: -4px; right: -4px; background: #46b450; color: white; width: 14px; height: 14px; border-radius: 50%; font-size: 10px; line-height: 14px; text-align: center; font-weight: bold; border: 1px solid white;">✓</span>' : '';941 var checkmarkHtml = hasCheckmark ? '<span class="filter-checkmark" style="position: absolute; top: -4px; right: -4px; background: #46b450; color: white; width: 14px; height: 14px; border-radius: 50%; font-size: 10px; line-height: 14px; text-align: center; font-weight: bold; border: 1px solid white;">✓</span>' : ''; 906 942 allBadge.html(allName + ' (' + total + ')' + checkmarkHtml); 907 943 } … … 916 952 var noLabelName = noLabelMatch[1]; 917 953 var hasNoLabelCheckmark = noLabelBadge.hasClass('current'); 918 var noLabelCheckmarkHtml = hasNoLabelCheckmark ? '<span style="position: absolute; top: -4px; right: -4px; background: #46b450; color: white; width: 14px; height: 14px; border-radius: 50%; font-size: 10px; line-height: 14px; text-align: center; font-weight: bold; border: 1px solid white;">✓</span>' : '';954 var noLabelCheckmarkHtml = hasNoLabelCheckmark ? '<span class="filter-checkmark" style="position: absolute; top: -4px; right: -4px; background: #46b450; color: white; width: 14px; height: 14px; border-radius: 50%; font-size: 10px; line-height: 14px; text-align: center; font-weight: bold; border: 1px solid white;">✓</span>' : ''; 919 955 noLabelBadge.html(noLabelName + ' (' + counts.no_label.count + ')' + noLabelCheckmarkHtml); 920 956 } … … 956 992 // ✅ Preserve checkmark if filter is active 957 993 var hasCheckmark = filterBadge.hasClass('current'); 958 var checkmarkHtml = hasCheckmark ? '<span style="position: absolute; top: -4px; right: -4px; background: #46b450; color: white; width: 14px; height: 14px; border-radius: 50%; font-size: 10px; line-height: 14px; text-align: center; font-weight: bold; border: 1px solid white;">✓</span>' : '';994 var checkmarkHtml = hasCheckmark ? '<span class="filter-checkmark" style="position: absolute; top: -4px; right: -4px; background: #46b450; color: white; width: 14px; height: 14px; border-radius: 50%; font-size: 10px; line-height: 14px; text-align: center; font-weight: bold; border: 1px solid white;">✓</span>' : ''; 959 995 filterBadge.html(newText + checkmarkHtml); 960 996 } … … 1874 1910 '<div class="widget-editor-header">' + 1875 1911 '<div class="widget-preview-large">' + 1876 '<span class="widget-preview-badge" style="display: inline-flex; align-items: center; gap: 8px; padding: 8px 16px; background: #2271b1; color: white; border-radius: 20px; font-size: 14px; font-weight: 500; text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);">' +1877 '<span class="dashicons dashicons-chart-pie" style="font-size: 16px; width: 16px; height: 16px;"></span>' +1912 '<span class="widget-preview-badge">' + 1913 '<span class="dashicons dashicons-chart-pie"></span>' + 1878 1914 '<span class="widget-preview-title">' + __('New Widget') + '</span>' + 1879 1915 '</span>' + … … 1893 1929 '</div>' + 1894 1930 '<div class="widget-field-row">' + 1895 '<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 15px;">' +1931 '<div class="widget-two-col-grid">' + 1896 1932 '<div class="widget-field-group">' + 1897 1933 '<label class="widget-field-label">' + __('Content Type') + '</label>' + … … 1912 1948 '</div>' + 1913 1949 '</div>' + 1914 '<div class="widget-bar-chart-options" data-widget-key="' + widgetKey + '" style="display: none; margin-top: 15px;">' +1915 '<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 15px;">' +1950 '<div class="widget-bar-chart-options" data-widget-key="' + widgetKey + '" style="display: none;">' + 1951 '<div class="widget-two-col-grid">' + 1916 1952 '<div class="widget-field-group">' + 1917 1953 '<label class="widget-field-label">' + __('Orientation') + '</label>' + … … 1939 1975 labelsHtml + 1940 1976 '</div>' + 1941 '<div class="widget-selected-labels-container" style=" margin-top: 15px;display: none;">' +1942 '<div style="font-weight: 600; margin-bottom: 10px; color: #23282d;">' +1943 '<span class="dashicons dashicons-sort" style="font-size: 16px; margin-right: 5px;"></span>' +1944 __('Labels Order') + ' <span style="font-weight: normal; color: #666; font-size: 12px;">(' + __('Drag to reorder') + ')</span>' +1977 '<div class="widget-selected-labels-container" style="display: none;">' + 1978 '<div class="widget-selected-labels-title">' + 1979 '<span class="dashicons dashicons-sort"></span>' + 1980 __('Labels Order') + ' <span class="widget-selected-labels-note">(' + __('Drag to reorder') + ')</span>' + 1945 1981 '</div>' + 1946 '<div class="widget-selected-labels-list" data-widget-key="' + widgetKey + '" style="display: flex; flex-wrap: wrap; gap: 8px; padding: 12px; background: #f9f9f9; border-radius: 4px; min-height: 50px;">' +1982 '<div class="widget-selected-labels-list" data-widget-key="' + widgetKey + '">' + 1947 1983 '</div>' + 1948 1984 '</div>' + 1949 '<small class="field-description " style="margin-top: 8px; color: #666;">' +1985 '<small class="field-description field-description-spaced">' + 1950 1986 __('Select which labels to include in this widget. Check "All labels" to include all available labels.') + 1951 1987 '</small>' + … … 2097 2133 if ($(this).is(':checked')) { 2098 2134 // Add to sortable list 2099 var $labelItem = $('<div class="widget-sortable-label" data-label-key="' + labelKey + '" style=" cursor: move; padding: 6px 12px; background: ' + labelColor + '; color: #fff; border-radius: 4px; display: flex; align-items: center; gap: 6px; box-shadow: 0 1px 3px rgba(0,0,0,0.1);">' +2100 '<span class="dashicons dashicons-menu" style="font-size: 14px;"></span>' +2135 var $labelItem = $('<div class="widget-sortable-label" data-label-key="' + labelKey + '" style="background: ' + labelColor + ';">' + 2136 '<span class="dashicons dashicons-menu"></span>' + 2101 2137 labelName + 2102 2138 '<input type="hidden" name="widgets[' + widgetKey + '][label_order][]" value="' + labelKey + '">' + -
redshape-easy-labels/trunk/includes/admin-page.php
r3398988 r3465229 357 357 ?> 358 358 </div> 359 <small class="field-description " style="margin-top: 8px; color: #666;">359 <small class="field-description field-description-spaced"> 360 360 <?php redshape_easylabels_cl_e('If no type is selected, the label will be visible on all enabled content types.'); ?> 361 361 </small> … … 363 363 364 364 <!-- NUOVO: Opzioni di visualizzazione nei filtri --> 365 <div class="label-display-options" style="margin-top: 16px; padding-top: 16px; border-top: 1px solid #e5e5e5;">365 <div class="label-display-options"> 366 366 <!-- Checkbox Percentuale --> 367 <label class="label-checkbox-option " style="margin-bottom: 12px;">367 <label class="label-checkbox-option label-checkbox-option-spaced"> 368 368 <input type="checkbox" 369 369 name="labels[<?php echo esc_attr($redshape_easylabels_key); ?>][show_percentage]" … … 371 371 <?php checked(!empty($redshape_easylabels_label['show_percentage'])); ?> /> 372 372 <span class="checkbox-label"> 373 <span class="dashicons dashicons-chart-pie " style="color: #2271b1;"></span>373 <span class="dashicons dashicons-chart-pie icon-accent"></span> 374 374 <strong><?php redshape_easylabels_cl_e('Show percentage in filters'); ?></strong> 375 375 </span> 376 376 </label> 377 <small class="field-description " style="margin-left: 24px; display: block; margin-bottom: 12px; color: #666;">377 <small class="field-description field-description-indented field-description-with-bottom-gap"> 378 378 <?php redshape_easylabels_cl_e('Display percentage (2 decimals) relative to total posts next to count'); ?> 379 379 </small> … … 386 386 <?php checked(!empty($redshape_easylabels_label['show_fraction'])); ?> /> 387 387 <span class="checkbox-label"> 388 <span class="dashicons dashicons-editor-justify " style="color: #2271b1;"></span>388 <span class="dashicons dashicons-editor-justify icon-accent"></span> 389 389 <strong><?php redshape_easylabels_cl_e('Show fraction format (e.g.: 3/5)'); ?></strong> 390 390 </span> 391 391 </label> 392 <small class="field-description " style="margin-left: 24px; display: block; margin-top: 4px; color: #666;">392 <small class="field-description field-description-indented"> 393 393 <?php redshape_easylabels_cl_e('Display count as fraction relative to total posts (e.g.: 3/5 instead of just 3)'); ?> 394 394 </small> … … 504 504 <div class="label-field-group flex-grow"> 505 505 <label class="label-field-label"><?php redshape_easylabels_cl_e('Label name'); ?></label> 506 <div style="display: flex; gap: 8px; align-items: flex-start;">506 <div class="default-label-row"> 507 507 <input type="text" 508 508 name="default_labels[all][name]" … … 510 510 class="label-name-input all-label-input" 511 511 placeholder="<?php redshape_easylabels_cl_e('e.g. All, Everything, View All'); ?>" 512 style="flex: 1;"/>512 /> 513 513 <button type="button" 514 514 class="reset-default-label-btn" … … 519 519 data-default-border-color="#2271b1" 520 520 data-default-enabled="1" 521 title="<?php redshape_easylabels_cl_e('Reset to default'); ?>" 522 style="padding: 8px 12px; background: #f0f0f1; border: 1px solid #c3c4c7; border-radius: 4px; cursor: pointer; display: flex; align-items: center; gap: 4px; font-size: 13px; color: #2c3338; transition: all 0.2s;"> 523 <span class="dashicons dashicons-image-rotate" style="font-size: 16px; width: 16px; height: 16px;"></span> 521 title="<?php redshape_easylabels_cl_e('Reset to default'); ?>"> 522 <span class="dashicons dashicons-image-rotate"></span> 524 523 <?php redshape_easylabels_cl_e('Reset'); ?> 525 524 </button> … … 542 541 <div class="label-field-group"> 543 542 <label class="label-field-label"> 544 <span class="dashicons dashicons-admin-customizer " style="color: #2271b1; font-size: 16px;"></span>543 <span class="dashicons dashicons-admin-customizer icon-accent icon-sm"></span> 545 544 <?php redshape_easylabels_cl_e('Border Style'); ?> 546 545 </label> 547 <div class="border-style-options " style="display: grid; grid-template-columns: repeat(5, 1fr); gap: 10px;">546 <div class="border-style-options border-style-options-grid"> 548 547 <?php 549 548 $redshape_easylabels_current_all_border_style = !empty($redshape_easylabels_default_label_settings['all']['border_style']) ? $redshape_easylabels_default_label_settings['all']['border_style'] : 'none'; … … 574 573 <div class="label-field-group all-border-color-field" style="<?php echo empty($redshape_easylabels_default_label_settings['all']['border_style']) || $redshape_easylabels_default_label_settings['all']['border_style'] === 'none' ? 'display: none;' : ''; ?>"> 575 574 <label class="label-field-label"> 576 <span class="dashicons dashicons-art " style="color: #2271b1; font-size: 16px;"></span>575 <span class="dashicons dashicons-art icon-accent icon-sm"></span> 577 576 <?php redshape_easylabels_cl_e('Border Color'); ?> 578 577 </label> … … 625 624 <div class="label-field-group flex-grow"> 626 625 <label class="label-field-label"><?php redshape_easylabels_cl_e('Label name'); ?></label> 627 <div style="display: flex; gap: 8px; align-items: flex-start;">626 <div class="default-label-row"> 628 627 <input type="text" 629 628 name="default_labels[none][name]" … … 631 630 class="label-name-input none-label-input" 632 631 placeholder="<?php redshape_easylabels_cl_e('e.g. No Label, Unlabeled, Without Labels'); ?>" 633 style="flex: 1;"/>632 /> 634 633 <button type="button" 635 634 class="reset-default-label-btn" … … 640 639 data-default-border-color="#646970" 641 640 data-default-enabled="1" 642 title="<?php redshape_easylabels_cl_e('Reset to default'); ?>" 643 style="padding: 8px 12px; background: #f0f0f1; border: 1px solid #c3c4c7; border-radius: 4px; cursor: pointer; display: flex; align-items: center; gap: 4px; font-size: 13px; color: #2c3338; transition: all 0.2s;"> 644 <span class="dashicons dashicons-image-rotate" style="font-size: 16px; width: 16px; height: 16px;"></span> 641 title="<?php redshape_easylabels_cl_e('Reset to default'); ?>"> 642 <span class="dashicons dashicons-image-rotate"></span> 645 643 <?php redshape_easylabels_cl_e('Reset'); ?> 646 644 </button> … … 663 661 <div class="label-field-group"> 664 662 <label class="label-field-label"> 665 <span class="dashicons dashicons-admin-customizer " style="color: #2271b1; font-size: 16px;"></span>663 <span class="dashicons dashicons-admin-customizer icon-accent icon-sm"></span> 666 664 <?php redshape_easylabels_cl_e('Border Style'); ?> 667 665 </label> 668 <div class="border-style-options " style="display: grid; grid-template-columns: repeat(5, 1fr); gap: 10px;">666 <div class="border-style-options border-style-options-grid"> 669 667 <?php 670 668 $redshape_easylabels_current_border_style = !empty($redshape_easylabels_default_label_settings['none']['border_style']) ? $redshape_easylabels_default_label_settings['none']['border_style'] : 'none'; … … 695 693 <div class="label-field-group none-border-color-field" style="<?php echo empty($redshape_easylabels_default_label_settings['none']['border_style']) || $redshape_easylabels_default_label_settings['none']['border_style'] === 'none' ? 'display: none;' : ''; ?>"> 696 694 <label class="label-field-label"> 697 <span class="dashicons dashicons-art " style="color: #2271b1; font-size: 16px;"></span>695 <span class="dashicons dashicons-art icon-accent icon-sm"></span> 698 696 <?php redshape_easylabels_cl_e('Border Color'); ?> 699 697 </label> … … 1056 1054 <div class="backup-actions"> 1057 1055 <div class="file-upload-wrapper"> 1058 <input type="file" id="import-file" accept=".json" style="display: none;" />1056 <input type="file" id="import-file" accept=".json" class="hidden-file-input" /> 1059 1057 <button type="button" id="select-import-file" class="button button-secondary button-hero"> 1060 1058 <span class="dashicons dashicons-media-default"></span> … … 1064 1062 </div> 1065 1063 1066 <button type="button" id="import-settings" class="button button-primary button-hero " style="display: none;">1064 <button type="button" id="import-settings" class="button button-primary button-hero is-hidden"> 1067 1065 <span class="dashicons dashicons-upload"></span> 1068 1066 <span><?php redshape_easylabels_cl_e('Import Settings'); ?></span> … … 1110 1108 <div class="widget-editor-header"> 1111 1109 <div class="widget-preview-large"> 1112 <span class="widget-preview-badge" style="display: inline-flex; align-items: center; gap: 8px; padding: 8px 16px; background: #2271b1; color: white; border-radius: 20px; font-size: 14px; font-weight: 500; text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);">1113 <span class="dashicons dashicons-chart-pie" style="font-size: 16px; width: 16px; height: 16px;"></span>1110 <span class="widget-preview-badge"> 1111 <span class="dashicons dashicons-chart-pie"></span> 1114 1112 <span class="widget-preview-title"><?php echo esc_html($redshape_easylabels_widget['title']); ?></span> 1115 1113 </span> … … 1133 1131 1134 1132 <div class="widget-field-row"> 1135 <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 15px;">1133 <div class="widget-two-col-grid"> 1136 1134 <div class="widget-field-group"> 1137 1135 <label class="widget-field-label"><?php redshape_easylabels_cl_e('Content Type'); ?></label> … … 1159 1157 1160 1158 <!-- Bar Chart Options --> 1161 <div class="widget-bar-chart-options" data-widget-key="<?php echo esc_attr($redshape_easylabels_widget_key); ?>" style="display: <?php echo ($redshape_easylabels_widget['visualization_type'] === 'bar_chart') ? 'block' : 'none'; ?>; margin-top: 15px;">1162 <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 15px;">1159 <div class="widget-bar-chart-options" data-widget-key="<?php echo esc_attr($redshape_easylabels_widget_key); ?>" style="display: <?php echo ($redshape_easylabels_widget['visualization_type'] === 'bar_chart') ? 'block' : 'none'; ?>;"> 1160 <div class="widget-two-col-grid"> 1163 1161 <div class="widget-field-group"> 1164 1162 <label class="widget-field-label"><?php redshape_easylabels_cl_e('Orientation'); ?></label> … … 1253 1251 1254 1252 <!-- Selected Labels Sortable List --> 1255 <div class="widget-selected-labels-container" style=" margin-top: 15px;display: <?php echo (!empty($redshape_easylabels_labels_for_sortable) && !$redshape_easylabels_all_labels_checked) ? 'block' : 'none'; ?>;">1256 <div style="font-weight: 600; margin-bottom: 10px; color: #23282d;">1257 <span class="dashicons dashicons-sort" style="font-size: 16px; margin-right: 5px;"></span>1258 <?php redshape_easylabels_cl_e('Labels Order'); ?> <span style="font-weight: normal; color: #666; font-size: 12px;">(<?php redshape_easylabels_cl_e('Drag to reorder'); ?>)</span>1259 </div> 1260 <div class="widget-selected-labels-list" data-widget-key="<?php echo esc_attr($redshape_easylabels_widget_key); ?>" style="display: flex; flex-wrap: wrap; gap: 8px; padding: 12px; background: #f9f9f9; border-radius: 4px; min-height: 50px;">1253 <div class="widget-selected-labels-container" style="display: <?php echo (!empty($redshape_easylabels_labels_for_sortable) && !$redshape_easylabels_all_labels_checked) ? 'block' : 'none'; ?>;"> 1254 <div class="widget-selected-labels-title"> 1255 <span class="dashicons dashicons-sort"></span> 1256 <?php redshape_easylabels_cl_e('Labels Order'); ?> <span class="widget-selected-labels-note">(<?php redshape_easylabels_cl_e('Drag to reorder'); ?>)</span> 1257 </div> 1258 <div class="widget-selected-labels-list" data-widget-key="<?php echo esc_attr($redshape_easylabels_widget_key); ?>"> 1261 1259 <?php foreach ($redshape_easylabels_labels_for_sortable as $redshape_easylabels_selected_key): 1262 1260 if ($redshape_easylabels_selected_key === '__no_label__'): … … 1265 1263 $redshape_easylabels_label_color = $redshape_easylabels_no_label_color; 1266 1264 ?> 1267 <div class="widget-sortable-label" data-label-key="__no_label__" style=" cursor: move; padding: 6px 12px; background: <?php echo esc_attr($redshape_easylabels_label_color); ?>; color: #fff; border-radius: 4px; display: flex; align-items: center; gap: 6px; box-shadow: 0 1px 3px rgba(0,0,0,0.1);">1268 <span class="dashicons dashicons-menu" style="font-size: 14px;"></span>1265 <div class="widget-sortable-label" data-label-key="__no_label__" style="background: <?php echo esc_attr($redshape_easylabels_label_color); ?>;"> 1266 <span class="dashicons dashicons-menu"></span> 1269 1267 <?php echo esc_html($redshape_easylabels_label_name); ?> 1270 1268 <input type="hidden" name="widgets[<?php echo esc_attr($redshape_easylabels_widget_key); ?>][label_order][]" value="__no_label__"> … … 1274 1272 $redshape_easylabels_label = $redshape_easylabels_labels[$redshape_easylabels_selected_key]; 1275 1273 ?> 1276 <div class="widget-sortable-label" data-label-key="<?php echo esc_attr($redshape_easylabels_selected_key); ?>" style=" cursor: move; padding: 6px 12px; background: <?php echo esc_attr($redshape_easylabels_label['color']); ?>; color: #fff; border-radius: 4px; display: flex; align-items: center; gap: 6px; box-shadow: 0 1px 3px rgba(0,0,0,0.1);">1277 <span class="dashicons dashicons-menu" style="font-size: 14px;"></span>1274 <div class="widget-sortable-label" data-label-key="<?php echo esc_attr($redshape_easylabels_selected_key); ?>" style="background: <?php echo esc_attr($redshape_easylabels_label['color']); ?>;"> 1275 <span class="dashicons dashicons-menu"></span> 1278 1276 <?php echo esc_html($redshape_easylabels_label['name']); ?> 1279 1277 <input type="hidden" name="widgets[<?php echo esc_attr($redshape_easylabels_widget_key); ?>][label_order][]" value="<?php echo esc_attr($redshape_easylabels_selected_key); ?>"> … … 1284 1282 </div> 1285 1283 </div> 1286 <small class="field-description " style="margin-top: 8px; color: #666;">1284 <small class="field-description field-description-spaced"> 1287 1285 <?php redshape_easylabels_cl_e('Select which labels to include in this widget. Check "All labels" to include all available labels.'); ?> 1288 1286 </small> … … 1322 1320 1323 1321 <!-- Plugin Information --> 1324 <div class="system-info-section" style="margin-bottom: 30px;">1325 <h3 style="margin-bottom: 15px; font-size: 18px;"><?php redshape_easylabels_cl_e('Plugin Information'); ?></h3>1326 <div style="background: white; padding: 20px; border: 1px solid #ddd; border-radius: 8px;">1327 <table class="widefat " style="border: none;">1322 <div class="system-info-section"> 1323 <h3 class="system-info-title"><?php redshape_easylabels_cl_e('Plugin Information'); ?></h3> 1324 <div class="system-info-card"> 1325 <table class="widefat system-info-table"> 1328 1326 <tbody> 1329 1327 <tr> 1330 <td style="padding: 10px; font-weight: 600; width: 200px;"><?php redshape_easylabels_cl_e('Plugin Version'); ?></td>1331 <td style="padding: 10px;"><?php echo esc_html(REDSHAPE_EASYLABELS_VERSION); ?></td>1328 <td class="system-info-label"><?php redshape_easylabels_cl_e('Plugin Version'); ?></td> 1329 <td class="system-info-value"><?php echo esc_html(REDSHAPE_EASYLABELS_VERSION); ?></td> 1332 1330 </tr> 1333 <tr style="background: #f9f9f9;">1334 <td style="padding: 10px; font-weight: 600;"><?php redshape_easylabels_cl_e('WordPress Version'); ?></td>1335 <td style="padding: 10px;"><?php echo esc_html(get_bloginfo('version')); ?></td>1331 <tr class="system-info-row-alt"> 1332 <td class="system-info-label"><?php redshape_easylabels_cl_e('WordPress Version'); ?></td> 1333 <td class="system-info-value"><?php echo esc_html(get_bloginfo('version')); ?></td> 1336 1334 </tr> 1337 1335 <tr> 1338 <td style="padding: 10px; font-weight: 600;"><?php redshape_easylabels_cl_e('PHP Version'); ?></td>1339 <td style="padding: 10px;"><?php echo esc_html(phpversion()); ?></td>1336 <td class="system-info-label"><?php redshape_easylabels_cl_e('PHP Version'); ?></td> 1337 <td class="system-info-value"><?php echo esc_html(phpversion()); ?></td> 1340 1338 </tr> 1341 <tr style="background: #f9f9f9;">1342 <td style="padding: 10px; font-weight: 600;"><?php redshape_easylabels_cl_e('Plugin Path'); ?></td>1343 <td style="padding: 10px; font-family: monospace; font-size: 12px;"><?php echo esc_html(REDSHAPE_EASYLABELS_PLUGIN_PATH); ?></td>1339 <tr class="system-info-row-alt"> 1340 <td class="system-info-label"><?php redshape_easylabels_cl_e('Plugin Path'); ?></td> 1341 <td class="system-info-value system-info-path"><?php echo esc_html(REDSHAPE_EASYLABELS_PLUGIN_PATH); ?></td> 1344 1342 </tr> 1345 1343 </tbody> -
redshape-easy-labels/trunk/includes/class-redshape-easylabels-cache.php
r3397460 r3465229 33 33 */ 34 34 const CACHE_DURATION = 3600; 35 36 /** 37 * Ottiene i post types abilitati dalle opzioni plugin con fallback retrocompatibile. 38 * 39 * @return array 40 */ 41 private static function get_enabled_post_types() { 42 $options = get_option('redshape_easylabels_options', array()); 43 44 if (!empty($options['role_settings']['enabled_post_types']) && is_array($options['role_settings']['enabled_post_types'])) { 45 return array_values($options['role_settings']['enabled_post_types']); 46 } 47 48 // Backward compatibility con vecchia struttura opzioni. 49 if (!empty($options['enabled_post_types']) && is_array($options['enabled_post_types'])) { 50 return array_values($options['enabled_post_types']); 51 } 52 53 return array('post', 'page'); 54 } 35 55 36 56 /** … … 68 88 public static function invalidate_label($label_id) { 69 89 // Ottieni tutti i post types abilitati 70 $options = get_option('redshape_easylabels_options', array()); 71 $enabled_post_types = isset($options['enabled_post_types']) ? $options['enabled_post_types'] : array('post'); 90 $enabled_post_types = self::get_enabled_post_types(); 72 91 73 92 $deleted_count = 0; … … 152 171 // Se nessun post type specificato, usa quelli abilitati nelle opzioni 153 172 if (empty($post_types)) { 154 $options = get_option('redshape_easylabels_options', array()); 155 $post_types = isset($options['enabled_post_types']) ? $options['enabled_post_types'] : array('post'); 173 $post_types = self::get_enabled_post_types(); 156 174 } 157 175 -
redshape-easy-labels/trunk/includes/class-redshape-easylabels.php
r3398988 r3465229 41 41 add_action('wp_ajax_redshape_easylabels_save_filter_order', array($this, 'ajax_save_filter_order')); 42 42 add_action('wp_ajax_redshape_easylabels_get_filter_counts', array($this, 'ajax_get_filter_counts')); // NEW: Filter counts 43 add_action('wp_ajax_redshape_easylabels_debug_post_types', array($this, 'ajax_debug_post_types'));44 43 add_action('wp_ajax_redshape_easylabels_export_settings', array($this, 'ajax_export_settings')); // NEW: Export 45 44 add_action('wp_ajax_redshape_easylabels_import_settings', array($this, 'ajax_import_settings')); // NEW: Import … … 58 57 59 58 private $columns_rendered = array(); // Flag to avoid double rendering 60 private $columns_added = array(); // Flag to avoid double column addition per post type61 59 62 60 // Universal system - register hooks for ALL post types and check dynamically … … 94 92 // Reset flags when screen changes 95 93 public function reset_column_flags() { 96 $this->columns_added = array();97 94 $this->columns_rendered = array(); 98 95 } … … 242 239 // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.MissingUnslash 243 240 $filter_value = sanitize_text_field(wp_unslash($_GET['content_label_filter'])); 241 242 // Read relation for multi-filter mode (default: AND) 243 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Filter parameter, no data modification 244 $filter_relation = isset($_GET['content_label_relation']) ? strtolower(sanitize_text_field(wp_unslash($_GET['content_label_relation']))) : 'and'; 245 if (!in_array($filter_relation, array('and', 'or'), true)) { 246 $filter_relation = 'and'; 247 } 244 248 245 249 // Check if multiple filters (comma-separated) 246 $filter_values = array_ map('trim', explode(',', $filter_value));250 $filter_values = array_filter(array_map('trim', explode(',', $filter_value))); 247 251 $has_multiple = count($filter_values) > 1; 248 252 … … 253 257 254 258 if ($has_multiple) { 255 // Multiple filters with AND relation256 $sub_queries = array('relation' => 'AND');259 // Multiple filters with configurable relation (AND/OR) 260 $sub_queries = array('relation' => strtoupper($filter_relation)); 257 261 258 262 foreach ($filter_values as $single_filter) { … … 339 343 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Filter parameter, no data modification 340 344 $current_filter = isset($_GET['content_label_filter']) ? sanitize_text_field(wp_unslash($_GET['content_label_filter'])) : ''; 341 $base_url = remove_query_arg('content_label_filter'); 345 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Filter parameter, no data modification 346 $current_filter_relation = isset($_GET['content_label_relation']) ? strtolower(sanitize_text_field(wp_unslash($_GET['content_label_relation']))) : 'and'; 347 if (!in_array($current_filter_relation, array('and', 'or'), true)) { 348 $current_filter_relation = 'and'; 349 } 350 351 $base_url = remove_query_arg(array('content_label_filter', 'content_label_relation')); 342 352 343 353 // NUOVO: Conta i post SENZA etichette e il totale (prima di generare l'HTML) … … 435 445 $all_badge_html .= esc_html($all_name) . ' (' . intval($total_posts_count) . ')'; 436 446 if ($all_class === 'current') { 437 $all_badge_html .= '<span style="position: absolute; top: -4px; right: -4px; background: #46b450; color: white; width: 14px; height: 14px; border-radius: 50%; font-size: 10px; line-height: 14px; text-align: center; font-weight: bold; border: 1px solid white;">✓</span>';447 $all_badge_html .= '<span class="filter-checkmark" style="position: absolute; top: -4px; right: -4px; background: #46b450; color: white; width: 14px; height: 14px; border-radius: 50%; font-size: 10px; line-height: 14px; text-align: center; font-weight: bold; border: 1px solid white;">✓</span>'; 438 448 } 439 449 $all_badge_html .= '</span>'; … … 463 473 $no_label_badge_html .= esc_html($no_label_name) . ' (' . intval($no_label_count) . ')'; 464 474 if ($no_label_class === 'current') { 465 $no_label_badge_html .= '<span style="position: absolute; top: -4px; right: -4px; background: #46b450; color: white; width: 14px; height: 14px; border-radius: 50%; font-size: 10px; line-height: 14px; text-align: center; font-weight: bold; border: 1px solid white;">✓</span>';475 $no_label_badge_html .= '<span class="filter-checkmark" style="position: absolute; top: -4px; right: -4px; background: #46b450; color: white; width: 14px; height: 14px; border-radius: 50%; font-size: 10px; line-height: 14px; text-align: center; font-weight: bold; border: 1px solid white;">✓</span>'; 466 476 } 467 477 $no_label_badge_html .= '</span>'; … … 484 494 $quick_filter_html .= '</div>'; 485 495 486 // Pulsante "Applica" per multi-select (inizialmente nascosto) 487 $quick_filter_html .= '<button type="button" class="multi-select-apply-btn" id="multi-apply-btn">' . esc_html(redshape_easylabels_cl__('Apply')) . '</button>'; 488 489 // Separatore verticale dopo Apply 496 // Selettore relazione AND/OR per multi-select 497 $quick_filter_html .= '<div class="filter-relation-toggle" id="filter-relation-toggle" data-default-relation="' . esc_attr($current_filter_relation) . '">'; 498 $quick_filter_html .= '<button type="button" class="relation-btn relation-btn-and" data-relation="and">AND</button>'; 499 $quick_filter_html .= '<button type="button" class="relation-btn relation-btn-or" data-relation="or">OR</button>'; 500 $quick_filter_html .= '</div>'; 501 502 // Separatore verticale dopo selettore relazione 490 503 $quick_filter_html .= '<span style="width: 1px; height: 16px; background-color: #ddd; margin: 0 4px;"></span>'; 491 504 } … … 593 606 $badge_html .= esc_html($label['name']) . ' ' . $count_display; 594 607 if ($is_active) { 595 $badge_html .= '<span style="position: absolute; top: -4px; right: -4px; background: #46b450; color: white; width: 14px; height: 14px; border-radius: 50%; font-size: 10px; line-height: 14px; text-align: center; font-weight: bold; border: 1px solid white;">✓</span>';608 $badge_html .= '<span class="filter-checkmark" style="position: absolute; top: -4px; right: -4px; background: #46b450; color: white; width: 14px; height: 14px; border-radius: 50%; font-size: 10px; line-height: 14px; text-align: center; font-weight: bold; border: 1px solid white;">✓</span>'; 596 609 } 597 610 $badge_html .= '</span>'; … … 712 725 'post_type_enabled' => $post_type_enabled, // NUOVO: flag per il JavaScript 713 726 'translations' => $translations, // NUOVO: Traduzioni per JavaScript 714 'debug' => defined('WP_DEBUG') && WP_DEBUG, // Debug mode flag715 727 'no_label_name' => $no_label_name, // Nome personalizzato per No Label 716 728 'no_label_color' => $no_label_color // Colore personalizzato per No Label … … 878 890 border: 1px solid white; 879 891 } 880 . multi-select-apply-btn{892 .filter-relation-toggle { 881 893 display: none; 882 background-color: #2271b1; 883 color: white; 884 padding: 4px 12px; 894 align-items: center; 895 gap: 4px; 896 padding: 2px; 897 background: #f0f0f1; 885 898 border-radius: 12px; 899 } 900 .filter-relation-toggle.visible { 901 display: inline-flex; 902 } 903 .relation-btn { 904 border: 1px solid #c3c4c7; 905 background: #fff; 906 color: #50575e; 907 padding: 2px 10px; 908 border-radius: 10px; 886 909 font-size: 11px; 887 font-weight: 500; 888 cursor: grab; 889 transition: all 0.2s ease; 890 position: relative; 891 border: 4px solid #135e96; 892 } 893 .multi-select-apply-btn:hover { 894 transform: scale(1.05); 895 box-shadow: 0 2px 4px rgba(0,0,0,0.2); 896 } 897 .multi-select-apply-btn.visible { 898 display: inline-block; 910 line-height: 1.5; 911 cursor: pointer; 912 } 913 .relation-btn.active { 914 background: #2271b1; 915 border-color: #2271b1; 916 color: #fff; 899 917 } 900 918 '; … … 926 944 var isMultiMode = false; 927 945 var selectedFilters = []; 928 var applyBtn = $("#multi-apply-btn"); 929 930 applyBtn.on("click", function(e) { 946 var filterRelation = "and"; 947 var currentSingleFilter = ""; 948 var relationToggle = $("#filter-relation-toggle"); 949 950 function normalizeFromParams(params) { 951 isMultiMode = params.get("multi_mode") === "1"; 952 selectedFilters = (params.get("content_label_filter") || "").split(",").filter(function(v) { return v !== ""; }); 953 filterRelation = params.get("content_label_relation") === "or" ? "or" : "and"; 954 currentSingleFilter = !isMultiMode && selectedFilters.length > 0 ? selectedFilters[0] : ""; 955 } 956 957 function getCheckmarkHtml() { 958 return "<span class=\"filter-checkmark\" style=\"position: absolute; top: -4px; right: -4px; background: #46b450; color: white; width: 14px; height: 14px; border-radius: 50%; font-size: 10px; line-height: 14px; text-align: center; font-weight: bold; border: 1px solid white;\">✓</span>"; 959 } 960 961 function setCurrentBadge(labelId) { 962 var allBadges = $(".filter-badge, .filter-badge-fixed"); 963 allBadges.removeClass("current"); 964 allBadges.find(".filter-checkmark").remove(); 965 966 var selector = labelId === "" 967 ? ".filter-badge-fixed[data-label-id=\"\"]" 968 : ".filter-badge[data-label-id=\"" + labelId + "\"], .filter-badge-fixed[data-label-id=\"" + labelId + "\"]"; 969 970 var activeBadge = $(selector).first(); 971 if (activeBadge.length > 0) { 972 activeBadge.addClass("current"); 973 if (activeBadge.find(".filter-checkmark").length === 0) { 974 activeBadge.append(getCheckmarkHtml()); 975 } 976 } 977 } 978 979 function updateRelationUI() { 980 relationToggle = $("#filter-relation-toggle"); 981 relationToggle.find(".relation-btn").removeClass("active"); 982 relationToggle.find(".relation-btn[data-relation=\"" + filterRelation + "\"]").addClass("active"); 983 } 984 985 function repositionFilterBar() { 986 var currentFilterBar = $(".content-labels-quick-filter-bar"); 987 if (currentFilterBar.length > 0) { 988 if (currentFilterBar.parent().is("a")) { 989 currentFilterBar.unwrap(); 990 } 991 var topNav = $(".tablenav.top"); 992 if (topNav.length > 0) { 993 currentFilterBar.detach().insertAfter(topNav); 994 } 995 currentFilterBar.css({ 996 "display": "block", 997 "float": "none", 998 "clear": "both", 999 "width": "100%" 1000 }); 1001 } 1002 } 1003 1004 function applyFiltersAjax(params) { 1005 var query = params.toString(); 1006 var targetUrl = window.location.pathname + (query ? "?" + query : ""); 1007 1008 $.ajax({ 1009 url: targetUrl, 1010 type: "GET", 1011 success: function(responseHtml) { 1012 var responseDoc = $("<div>").html(responseHtml); 1013 var newListTable = responseDoc.find("#posts-filter .wp-list-table").first(); 1014 var newTopNav = responseDoc.find("#posts-filter .tablenav.top").first(); 1015 var newBottomNav = responseDoc.find("#posts-filter .tablenav.bottom").first(); 1016 1017 if (newListTable.length === 0) { 1018 window.location.href = targetUrl; 1019 return; 1020 } 1021 1022 var currentListTable = $("#posts-filter .wp-list-table").first(); 1023 if (currentListTable.length > 0) { 1024 currentListTable.replaceWith(newListTable); 1025 } else { 1026 window.location.href = targetUrl; 1027 return; 1028 } 1029 1030 var currentTopNav = $("#posts-filter .tablenav.top").first(); 1031 if (currentTopNav.length > 0 && newTopNav.length > 0) { 1032 currentTopNav.replaceWith(newTopNav); 1033 } 1034 1035 var currentBottomNav = $("#posts-filter .tablenav.bottom").first(); 1036 if (currentBottomNav.length > 0 && newBottomNav.length > 0) { 1037 currentBottomNav.replaceWith(newBottomNav); 1038 } 1039 1040 window.history.replaceState({}, "", targetUrl); 1041 1042 var appliedParams = new URLSearchParams(query); 1043 normalizeFromParams(appliedParams); 1044 1045 updateRelationUI(); 1046 syncMultiVisualState(); 1047 attachBadgeHandlers(); 1048 $(document).trigger("redshapeEasylabels:tableUpdated"); 1049 }, 1050 error: function() { 1051 window.location.href = targetUrl; 1052 } 1053 }); 1054 } 1055 1056 function syncMultiVisualState() { 1057 if (isMultiMode) { 1058 $("#filter-mode-checkbox").prop("checked", true); 1059 $(".filter-mode-slider").css("background-color", "#46b450"); 1060 $(".filter-badge-fixed[data-label-id=\"\"]").hide(); 1061 $("#filter-relation-toggle").addClass("visible"); 1062 $(".filter-badge, .filter-badge-fixed").removeClass("multi-selected current"); 1063 $(".filter-badge, .filter-badge-fixed").find(".filter-checkmark").remove(); 1064 1065 selectedFilters.forEach(function(filterId) { 1066 $(".filter-badge[data-label-id=\"" + filterId + "\"], .filter-badge-fixed[data-label-id=\"" + filterId + "\"]").addClass("multi-selected"); 1067 }); 1068 } else { 1069 $("#filter-mode-checkbox").prop("checked", false); 1070 $(".filter-mode-slider").css("background-color", "#ccc"); 1071 $(".filter-badge-fixed[data-label-id=\"\"]").show(); 1072 $("#filter-relation-toggle").removeClass("visible"); 1073 $(".filter-badge, .filter-badge-fixed").removeClass("multi-selected"); 1074 setCurrentBadge(currentSingleFilter); 1075 } 1076 } 1077 1078 relationToggle.find(".relation-btn").on("click", function(e) { 931 1079 e.preventDefault(); 932 if (selectedFilters.length > 0) { 933 var params = new URLSearchParams(window.location.search); 934 params.set("content_label_filter", selectedFilters.join(",")); 935 window.location.href = window.location.pathname + "?" + params.toString(); 1080 filterRelation = $(this).data("relation") === "or" ? "or" : "and"; 1081 updateRelationUI(); 1082 1083 if (isMultiMode && selectedFilters.length > 0) { 1084 var relationParams = new URLSearchParams(window.location.search); 1085 relationParams.set("multi_mode", "1"); 1086 relationParams.set("content_label_filter", selectedFilters.join(",")); 1087 relationParams.set("content_label_relation", filterRelation); 1088 applyFiltersAjax(relationParams); 936 1089 } 937 1090 }); … … 945 1098 946 1099 if (labelId === "") { 947 window.location.href = filterUrl; 1100 var allParams = new URLSearchParams(window.location.search); 1101 allParams.delete("content_label_filter"); 1102 allParams.delete("content_label_relation"); 1103 allParams.delete("multi_mode"); 1104 applyFiltersAjax(allParams); 948 1105 return false; 949 1106 } 950 1107 951 1108 if (!isMulti) { 952 window.location.href = filterUrl;1109 applyFiltersAjax(new URLSearchParams((filterUrl.split("?")[1] || ""))); 953 1110 return false; 954 1111 } else { … … 965 1122 $(this).addClass("multi-selected"); 966 1123 } 1124 1125 var multiParams = new URLSearchParams(window.location.search); 1126 multiParams.set("multi_mode", "1"); 1127 multiParams.set("content_label_relation", filterRelation); 1128 1129 if (selectedFilters.length > 0) { 1130 multiParams.set("content_label_filter", selectedFilters.join(",")); 1131 } else { 1132 multiParams.delete("content_label_filter"); 1133 } 1134 1135 applyFiltersAjax(multiParams); 967 1136 968 1137 return false; … … 975 1144 // Check if multi-mode is active from URL 976 1145 var params = new URLSearchParams(window.location.search); 977 if (params.get("multi_mode") === "1") { 978 $("#filter-mode-checkbox").prop("checked", true); 979 isMultiMode = true; 980 $(".filter-mode-slider").css("background-color", "#46b450"); 981 $(".filter-badge-fixed[data-label-id=\'\']").hide(); 982 applyBtn.addClass("visible"); 983 984 var activeFilters = params.get("content_label_filter"); 985 if (activeFilters) { 986 selectedFilters = activeFilters.split(","); 987 selectedFilters.forEach(function(filterId) { 988 $(".filter-badge[data-label-id=\'" + filterId + "\'], .filter-badge-fixed[data-label-id=\'" + filterId + "\']").addClass("multi-selected"); 989 }); 990 } 991 } 1146 normalizeFromParams(params); 1147 1148 if (!params.get("content_label_relation") && relationToggle.data("default-relation") === "or") { 1149 filterRelation = "or"; 1150 } 1151 1152 updateRelationUI(); 1153 syncMultiVisualState(); 992 1154 993 1155 // Toggle multi-select mode 994 1156 $("#filter-mode-checkbox").on("change", function() { 1157 var hadActiveFilters = selectedFilters.length > 0; 995 1158 isMultiMode = $(this).is(":checked"); 996 1159 selectedFilters = []; 997 $(".filter-badge, .filter-badge-fixed").removeClass("multi-selected");1160 currentSingleFilter = ""; 998 1161 999 var params = new URLSearchParams(window.location.search); 1000 params.delete("content_label_filter"); 1162 var toggleParams = new URLSearchParams(window.location.search); 1163 toggleParams.delete("content_label_filter"); 1164 toggleParams.delete("content_label_relation"); 1001 1165 1002 1166 if (isMultiMode) { 1003 params.set("multi_mode", "1"); 1167 toggleParams.set("multi_mode", "1"); 1168 toggleParams.set("content_label_relation", filterRelation); 1004 1169 } else { 1005 params.delete("multi_mode");1170 toggleParams.delete("multi_mode"); 1006 1171 } 1007 1008 var newUrl = window.location.pathname + (params.toString() ? "?" + params.toString() : ""); 1009 window.location.href = newUrl; 1172 1173 if (hadActiveFilters) { 1174 applyFiltersAjax(toggleParams); 1175 } else { 1176 window.history.replaceState({}, "", window.location.pathname + (toggleParams.toString() ? "?" + toggleParams.toString() : "")); 1177 syncMultiVisualState(); 1178 updateRelationUI(); 1179 } 1010 1180 }); 1011 1181 }); … … 1503 1673 setTimeout(function() { newCardEl.removeClass('new-label'); }, 300); 1504 1674 labelCounter++; 1505 } catch(error) { 1506 if (typeof redshapeEasylabelsAjax !== 'undefined' && redshapeEasylabelsAjax.debug) { 1507 console.error('Error adding label:', error); 1508 } 1675 } catch(_error) { 1509 1676 } 1510 1677 }); -
redshape-easy-labels/trunk/readme.txt
r3409971 r3465229 5 5 Tested up to: 6.9 6 6 Requires PHP: 7.0 7 Stable tag: 1. 2.07 Stable tag: 1.3.0 8 8 License: GPLv2 or later 9 9 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 77 77 = How does multi-select filtering work? = 78 78 79 Toggle the Multi switch in the quick filters to enable multi-select mode. Click multiple label badges to select them (they'll show a green checkmark), then click Apply to filter posts that have ALL the selected labels together. The filter uses AND logic, so only posts with every selected label will be shown.79 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. 80 80 81 81 == Screenshots == … … 93 93 94 94 == Changelog == 95 96 = 1.3.0 = 97 * Maintenance: Version bump to 1.3.0 98 * Compatibility: Tested up to WordPress 6.9 99 * New: Multi-select filters now support AND/OR relation modes 100 * Enhancement: Quick filters now apply instantly via AJAX (no Apply button) 101 * Fix: Removed duplicated uninstall cleanup blocks (cache/meta/transient) 102 * Fix: Aligned cache post type source with role_settings[enabled_post_types] and backward-compatible fallback 103 * Fix: Removed duplicate initializeLabelEvents() call in admin JavaScript 95 104 96 105 = 1.2.0 = … … 178 187 == Upgrade Notice == 179 188 189 = 1.3.0 = 190 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. 191 180 192 = 1.2.0 = 181 193 Major feature update: Adds dashboard widgets with 5 visualization types and interactive click-to-filter functionality. Includes drag & drop label ordering for complete customization. -
redshape-easy-labels/trunk/redshape-easy-labels.php
r3398988 r3465229 3 3 * Plugin Name: REDSHAPE Easy Labels 4 4 * 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). 5 * Version: 1. 2.05 * Version: 1.3.0 6 6 * Author: REDSHAPE 7 7 * Author URI: https://redshape.it … … 18 18 19 19 // Define plugin constants 20 define('REDSHAPE_EASYLABELS_VERSION', '1. 2.0');20 define('REDSHAPE_EASYLABELS_VERSION', '1.3.0'); 21 21 define('REDSHAPE_EASYLABELS_PLUGIN_URL', plugin_dir_url(__FILE__)); 22 22 define('REDSHAPE_EASYLABELS_PLUGIN_PATH', plugin_dir_path(__FILE__)); … … 48 48 function redshape_easylabels_cl_e($string) { 49 49 echo esc_html(Redshape_Easylabels_I18n::__($string)); 50 }51 }52 53 /**54 * Helper function for plugin logging55 * Only logs if WP_DEBUG is enabled to avoid production logging56 * Uses WordPress logging system to avoid direct error_log usage57 *58 * @param string $message The message to log59 */60 if (!function_exists('redshape_easylabels_log')) {61 function redshape_easylabels_log($message) {62 // Only log in debug mode to avoid production logging63 if (defined('WP_DEBUG') && WP_DEBUG && defined('WP_DEBUG_LOG') && WP_DEBUG_LOG) {64 // Use WordPress debug system - writes to wp-content/debug.log65 $log_message = 'REDSHAPE Easy Labels: ' . $message;66 67 // Use WordPress logging system - only wp_debug_log to avoid filesystem issues68 if (function_exists('wp_debug_log')) {69 wp_debug_log($log_message);70 }71 // If wp_debug_log is not available, silently skip logging to avoid warnings72 }73 50 } 74 51 } -
redshape-easy-labels/trunk/uninstall.php
r3397353 r3465229 54 54 // 6. CLEANUP TRANSIENTS (if any remain) 55 55 delete_transient('redshape_easylabels_version_check'); 56 57 // 3. RIMUOVI CACHE (se presente)58 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching59 $wpdb->query(60 "DELETE FROM {$wpdb->options}61 WHERE option_name LIKE 'redshape_easylabels_counts_%'"62 );63 64 // 4. RIMUOVI TUTTI I META DATI DELLE ETICHETTE65 // Meta key: _content_labels (array di etichette per ogni post)66 delete_post_meta_by_key('_content_labels');67 68 // 5. RIMUOVI TUTTI I META DATI DELLE NOTE69 // Meta key: _content_note (nota testuale per ogni post)70 delete_post_meta_by_key('_content_note');71 72 // 6. CLEANUP TRANSIENTS (if any remain)73 delete_transient('redshape_easylabels_version_check');74 56 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching 75 57 $wpdb->query(
Note: See TracChangeset
for help on using the changeset viewer.