Changeset 3466559
- Timestamp:
- 02/21/2026 07:03:48 PM (5 weeks ago)
- Location:
- series-grid/trunk
- Files:
-
- 5 edited
-
CHANGELOG.txt (modified) (1 diff)
-
assets/css/style.css (modified) (7 diffs)
-
assets/js/script.js (modified) (4 diffs)
-
readme.txt (modified) (1 diff)
-
series-grid.php (modified) (11 diffs)
Legend:
- Unmodified
- Added
- Removed
-
series-grid/trunk/CHANGELOG.txt
r3430317 r3466559 1 1 === Series Grid Changelog === 2 3 = 4.0.3 = 4 * **Fix:** Moved all inline CSS from PHP to style.css (USTAV compliance) 5 * **Fix:** Removed duplicate instance-success-message HTML element (caused JS bugs) 6 * **Fix:** Removed unnecessary require_once for WordPress core files 7 * **Fix:** Corrected wp_parse_args merge order so instance settings properly override global defaults 8 * **Fix:** Removed debug code left in production (slider debug properties) 9 * **Fix:** Component license validation now checks correct 'expires_at' field (was checking 'end_date'). Fixes Download Counter component keys rejection. 2 10 3 11 = 4.0.2 = -
series-grid/trunk/assets/css/style.css
r3387257 r3466559 276 276 ======================== */ 277 277 278 /* Animation Base - ONLY FOR PRO */ 279 .pro-enabled .series-grid-item, 280 .pro-enabled .series-list-item, 281 .pro-enabled .slider-item { 282 opacity: 0; 283 animation-duration: 0.6s; 284 animation-fill-mode: both; 285 } 286 287 /* Fade Animation */ 278 /* Animation Base - items with active animations start hidden, JS adds .is-animated on scroll */ 288 279 .pro-enabled.animation-fade .series-grid-item, 289 280 .pro-enabled.animation-fade .series-list-item, 290 .pro-enabled.animation-fade .slider-item { 291 animation-name: fadeInUp; 281 .pro-enabled.animation-fade .slider-item, 282 .pro-enabled.animation-slide .series-grid-item, 283 .pro-enabled.animation-slide .series-list-item, 284 .pro-enabled.animation-slide .slider-item, 285 .pro-enabled.animation-zoom .series-grid-item, 286 .pro-enabled.animation-zoom .series-list-item, 287 .pro-enabled.animation-zoom .slider-item, 288 .pro-enabled.animation-bounce .series-grid-item, 289 .pro-enabled.animation-bounce .series-list-item, 290 .pro-enabled.animation-bounce .slider-item { 291 opacity: 0; 292 } 293 294 /* animation-none: override injected CSS - elements immediately visible */ 295 .pro-enabled.animation-none .series-grid-item, 296 .pro-enabled.animation-none .series-list-item, 297 .pro-enabled.animation-none .slider-item { 298 opacity: 1; 299 animation: none; 300 transform: none; 301 } 302 303 /* Fallback: unknown animation type - show when JS adds .is-animated */ 304 .pro-enabled .series-grid-item.is-animated, 305 .pro-enabled .series-list-item.is-animated, 306 .pro-enabled .slider-item.is-animated { 307 opacity: 1; 308 } 309 310 /* Fade Animation - JS adds .is-animated when item enters viewport */ 311 .pro-enabled.animation-fade .series-grid-item.is-animated, 312 .pro-enabled.animation-fade .series-list-item.is-animated, 313 .pro-enabled.animation-fade .slider-item.is-animated { 314 animation: fadeInUp 0.6s ease both; 292 315 } 293 316 … … 303 326 } 304 327 305 /* Slide Animation */306 .pro-enabled.animation-slide .series-grid-item ,307 .pro-enabled.animation-slide .series-list-item ,308 .pro-enabled.animation-slide .slider-item {309 animation -name: slideInUp;328 /* Slide Animation - JS adds .is-animated when item enters viewport */ 329 .pro-enabled.animation-slide .series-grid-item.is-animated, 330 .pro-enabled.animation-slide .series-list-item.is-animated, 331 .pro-enabled.animation-slide .slider-item.is-animated { 332 animation: slideInUp 0.6s ease both; 310 333 } 311 334 … … 321 344 } 322 345 323 /* Zoom Animation */324 .pro-enabled.animation-zoom .series-grid-item ,325 .pro-enabled.animation-zoom .series-list-item ,326 .pro-enabled.animation-zoom .slider-item {327 animation -name: zoomIn;346 /* Zoom Animation - JS adds .is-animated when item enters viewport */ 347 .pro-enabled.animation-zoom .series-grid-item.is-animated, 348 .pro-enabled.animation-zoom .series-list-item.is-animated, 349 .pro-enabled.animation-zoom .slider-item.is-animated { 350 animation: zoomIn 0.6s ease both; 328 351 } 329 352 … … 339 362 } 340 363 341 /* Bounce Animation */342 .pro-enabled.animation-bounce .series-grid-item ,343 .pro-enabled.animation-bounce .series-list-item ,344 .pro-enabled.animation-bounce .slider-item {345 animation -name: bounceIn;364 /* Bounce Animation - JS adds .is-animated when item enters viewport */ 365 .pro-enabled.animation-bounce .series-grid-item.is-animated, 366 .pro-enabled.animation-bounce .series-list-item.is-animated, 367 .pro-enabled.animation-bounce .slider-item.is-animated { 368 animation: bounceIn 0.6s both; 346 369 } 347 370 … … 447 470 .pro-enabled.hover-overlay .series-grid-item:hover .hover-overlay { 448 471 opacity: 1; 472 visibility: visible; 449 473 } 450 474 … … 842 866 .series-grid-item.image-position-left .series-grid-title, 843 867 .series-grid-item.image-position-right .series-grid-title { 844 margin-top: 15px; /* Vrati marginu */ 845 } 846 847 .series-grid-item.image-position-left .series-grid-image-wrapper, 848 .series-grid-item.image-position-right .series-grid-image-wrapper { 849 flex: 0 0 120px; 850 height: 120px; 868 margin-top: 15px; 851 869 } 852 870 } … … 893 911 } 894 912 } 913 914 /* ============================================================ 915 Admin Settings Page Styles 916 ============================================================ */ 917 918 /* Tab navigation */ 919 .tab-content { display: none; padding-top: 20px; } 920 .tab-content.active { display: block; } 921 .pro-tag { color: #999; font-size: 11px; } 922 923 /* Instance Manager */ 924 .instance-manager { 925 margin-top: 20px; 926 background: #fff; 927 border: 1px solid #ddd; 928 border-radius: 8px; 929 padding: 20px; 930 } 931 932 .instance-list, 933 .instance-create, 934 .instance-quick-reference { 935 margin-bottom: 25px; 936 } 937 938 .instance-quick-reference { 939 background: #f8f9fa; 940 border: 1px solid #e9ecef; 941 border-radius: 6px; 942 padding: 15px; 943 } 944 945 .instance-quick-reference h4 { 946 margin-top: 0; 947 color: #495057; 948 } 949 950 .shortcodes-list { 951 margin-top: 15px; 952 } 953 954 .shortcode-item { 955 background: white; 956 border: 1px solid #dee2e6; 957 border-radius: 4px; 958 padding: 10px; 959 margin-bottom: 8px; 960 display: flex; 961 align-items: center; 962 } 963 964 .shortcode-item code { 965 flex: 1; 966 font-family: 'Courier New', monospace; 967 background: #f8f9fa; 968 padding: 4px 8px; 969 border-radius: 3px; 970 } 971 972 .instance-table { 973 margin-top: 15px; 974 } 975 976 .instance-search { 977 margin-bottom: 15px; 978 display: flex; 979 align-items: center; 980 } 981 982 .instance-search input, 983 .instance-search select { 984 padding: 5px 8px; 985 border: 1px solid #ccc; 986 border-radius: 3px; 987 } 988 989 .layout-badge { 990 display: inline-block; 991 padding: 4px 8px; 992 border-radius: 12px; 993 font-size: 12px; 994 font-weight: bold; 995 text-transform: uppercase; 996 } 997 998 .layout-grid { background: #e3f2fd; color: #1976d2; } 999 .layout-list { background: #f3e5f5; color: #7b1fa2; } 1000 .layout-slider { background: #e8f5e8; color: #388e3c; } 1001 1002 .action-buttons { 1003 display: flex; 1004 gap: 5px; 1005 flex-wrap: wrap; 1006 } 1007 1008 .action-buttons .button { 1009 font-size: 11px; 1010 padding: 4px 8px; 1011 } 1012 1013 .instance-create-table { 1014 background: #f8f9fa; 1015 border: 1px solid #e9ecef; 1016 border-radius: 6px; 1017 padding: 15px; 1018 } 1019 1020 .loading-indicator { 1021 color: #0073aa; 1022 } 1023 1024 .no-instances { 1025 text-align: center; 1026 padding: 30px; 1027 background: #f8f9fa; 1028 border: 1px solid #e9ecef; 1029 border-radius: 6px; 1030 } 1031 1032 /* Instance success message */ 1033 .instance-success-message { 1034 background: #d4edda; 1035 border: 1px solid #c3e6cb; 1036 padding: 15px; 1037 margin-top: 15px; 1038 border-radius: 4px; 1039 color: #155724; 1040 } 1041 1042 .instance-success-message p { 1043 margin: 0; 1044 } 1045 1046 .instance-success-message .success-shortcode { 1047 background: #f8f9fa; 1048 padding: 5px; 1049 border-radius: 3px; 1050 margin-top: 5px; 1051 display: inline-block; 1052 } -
series-grid/trunk/assets/js/script.js
r3387257 r3466559 23 23 // AJAX load more functionality 24 24 $(document).on('click', '.series-grid-load-more', this.loadMore); 25 26 // Slider navigation 27 $(document).on('click', '.slider-nav-prev', this.sliderPrev); 28 $(document).on('click', '.slider-nav-next', this.sliderNext); 29 25 26 // Note: Slider navigation (.slider-nav-prev/.slider-nav-next) is handled by 27 // onclick="scrollSlider(...)" in the template - no event delegation needed here 28 30 29 // Enhanced hover effects 31 30 this.enhanceHoverEffects(); 32 31 33 32 // Touch support for mobile 34 33 this.addTouchSupport(); … … 46 45 47 46 setTimeout(() => { 48 item.style.opacity = '1'; 49 item.style.transform = 'translateY(0)'; 47 item.classList.add('is-animated'); 50 48 }, parseInt(delay)); 51 49 … … 266 264 // Touch support for mobile sliders 267 265 addTouchSupport: function() { 268 const sliders = document.querySelectorAll('.slider-wrapper'); 269 266 // Only initialize sliders that haven't been set up yet 267 const sliders = document.querySelectorAll('.slider-wrapper:not([data-touch-initialized])'); 268 270 269 sliders.forEach(slider => { 270 slider.setAttribute('data-touch-initialized', 'true'); 271 271 let startX, startY, distX, distY; 272 272 let isScrolling = false; … … 365 365 SeriesGridPro.initProAnimations(); 366 366 SeriesGridPro.initAutoScroll(); 367 SeriesGridPro.addTouchSupport(); 367 368 }); 368 369 -
series-grid/trunk/readme.txt
r3430317 r3466559 3 3 Tags: grid, posts, slider, responsive, gallery 4 4 Requires at least: 5.5 5 Tested up to: 6. 85 Tested up to: 6.9 6 6 Requires PHP: 7.4 7 Stable tag: 4.0. 27 Stable tag: 4.0.3 8 8 License: GPL2 9 9 License URI: https://www.gnu.org/licenses/gpl-2.0.html -
series-grid/trunk/series-grid.php
r3430317 r3466559 3 3 Plugin Name: Series Grid 4 4 Description: Display posts in responsive grid, list, or slider layouts with PRO features: animations, color themes, auto-scroll, social sharing, and advanced customization. 5 Version: 4.0. 25 Version: 4.0.3 6 6 Author: technodrome 7 7 License: GPL2 … … 9 9 Domain Path: /languages 10 10 Requires at least: 5.5 11 Tested up to: 6. 811 Tested up to: 6.9 12 12 Requires PHP: 7.4 13 13 */ … … 18 18 if (!defined('ABSPATH')) exit; 19 19 20 // Include WordPress core files21 if (!defined('ABSPATH')) {22 // ABSPATH should be defined by WordPress, but define it if not available23 define('ABSPATH', dirname(__FILE__) . '/');24 }25 require_once(ABSPATH . 'wp-includes/formatting.php');26 require_once(ABSPATH . 'wp-includes/class-wp-query.php');27 require_once(ABSPATH . 'wp-includes/pluggable.php');28 require_once(ABSPATH . 'wp-includes/functions.php');29 require_once(ABSPATH . 'wp-includes/plugin.php');30 31 20 // Plugin constants 32 define('SERIES_GRID_VERSION', '4.0. 2');21 define('SERIES_GRID_VERSION', '4.0.3'); 33 22 34 23 // Define constants only if not already defined by WordPress … … 181 170 } 182 171 183 // Check if license is expired 184 $end_date = isset($license_data['end_date']) ? $license_data['end_date'] : ''; 185 if (!empty($end_date) && strtotime($end_date) < time()) { 172 // Check if license is expired (v4.0.3: Check expires_at field, which is the correct one) 173 // Note: Download Counter component writes 'expires_at', not 'end_date' 174 $expires_at = isset($license_data['expires_at']) ? $license_data['expires_at'] : ''; 175 if (!empty($expires_at) && strtotime($expires_at) < time()) { 186 176 set_transient($transient_key, 'expired', HOUR_IN_SECONDS); 187 177 return false; 188 178 } 189 179 190 // License is valid 180 // License is valid - clear any stale expiry transient so is_expired() gets fresh data 181 delete_transient('sg_license_expiry_' . md5($license_key)); 191 182 set_transient($transient_key, 'valid', DAY_IN_SECONDS); 192 183 return true; … … 330 321 if (isset($licenses[strtoupper($license_key)])) { 331 322 $license_data = $licenses[strtoupper($license_key)]; 332 $end_date = isset($license_data['end_date']) ? $license_data['end_date'] : ''; 333 if (!empty($end_date)) { 334 $expiry_ts = strtotime($end_date); 323 // Use expires_at (correct field name) - end_date was the old field name 324 $expires_at = isset($license_data['expires_at']) ? $license_data['expires_at'] : ''; 325 if (!empty($expires_at)) { 326 $expiry_ts = strtotime($expires_at); 335 327 set_transient($transient_key, $expiry_ts, DAY_IN_SECONDS); 336 328 return $expiry_ts < time(); … … 419 411 /** 420 412 * Clear all license-related transients - v4.0.2 413 * Uses direct database query for bulk transient deletion by pattern. 414 * No user input is used, so prepared statements are not needed. 421 415 */ 422 416 private static function clear_license_transients() { 423 417 global $wpdb; 418 419 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching 424 420 $wpdb->query("DELETE FROM {$wpdb->options} WHERE option_name LIKE '_transient_sg_license_%' OR option_name LIKE '_transient_timeout_sg_license_%'"); 421 422 // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching 425 423 $wpdb->query("DELETE FROM {$wpdb->options} WHERE option_name LIKE '_transient_series_grid_license_%' OR option_name LIKE '_transient_timeout_series_grid_license_%'"); 426 424 } … … 513 511 </form> 514 512 </div> 515 516 <style>517 .tab-content { display: none; padding-top: 20px; }518 .tab-content.active { display: block; }519 .pro-tag { color: #999; font-size: 11px; }520 </style>521 513 522 514 <?php … … 1433 1425 ]; 1434 1426 1435 // Merge instance settings with defaults - global settings are defaults, instance settings take priority1436 $merged_defaults = wp_parse_args($ defaults, $instance_settings);1427 // Merge instance settings with defaults - instance settings take priority over global defaults 1428 $merged_defaults = wp_parse_args($instance_settings, $defaults); 1437 1429 1438 1430 // Merge with shortcode attributes - shortcode overrides both … … 1506 1498 } 1507 1499 1508 // Debug output - remove in production1509 if ($atts['layout'] === 'slider') {1510 $post->debug_has_thumbnail = has_post_thumbnail($post->ID) ? 'yes' : 'no';1511 $post->debug_extract_images = $atts['extract_images'];1512 $post->debug_image_found = !empty($post->image) ? 'yes' : 'no';1513 }1514 1515 1500 // Get category info if needed 1516 1501 if ($atts['show_category'] === 'yes') { … … 1764 1749 </div> 1765 1750 1766 <!-- Success Message -->1767 <div id="instance-success-message" style="display: none; background: #d4edda; border: 1px solid #c3e6cb; padding: 15px; margin-top: 15px; border-radius: 4px;">1768 <p style="margin: 0; color: #155724;">1769 ✅ <strong><?php esc_html_e('Instance Created Successfully!', 'series-grid'); ?></strong><br>1770 <span style="font-size: 14px;"><?php esc_html_e('Use the shortcode below on your frontpage:', 'series-grid'); ?></span>1771 <br>1772 <code id="new-instance-shortcode" style="background: #f8f9fa; padding: 5px; border-radius: 3px; margin-top: 5px; display: inline-block;"></code>1773 </p>1774 </div>1775 1776 1751 <!-- Instance Quick Reference - Always show this panel --> 1777 1752 <div class="instance-quick-reference"> … … 1883 1858 1884 1859 <!-- Success Message --> 1885 <div id="instance-success-message" style="display: none; background: #d4edda; border: 1px solid #c3e6cb; padding: 15px; margin-top: 15px; border-radius: 4px;">1886 <p style="margin: 0; color: #155724;">1860 <div id="instance-success-message" class="instance-success-message" style="display: none;"> 1861 <p> 1887 1862 ✅ <strong><?php esc_html_e('Instance Created Successfully!', 'series-grid'); ?></strong><br> 1888 <span style="font-size: 14px;"><?php esc_html_e('Use the shortcode below on your frontpage:', 'series-grid'); ?></span>1863 <span><?php esc_html_e('Use the shortcode below on your frontpage:', 'series-grid'); ?></span> 1889 1864 <br> 1890 <code id="new-instance-shortcode" style="background: #f8f9fa; padding: 5px; border-radius: 3px; margin-top: 5px; display: inline-block;"></code>1865 <code id="new-instance-shortcode" class="success-shortcode"></code> 1891 1866 </p> 1892 1867 </div> 1893 1868 </div> 1894 1869 1895 <style>1896 .instance-manager {1897 margin-top: 20px;1898 background: #fff;1899 border: 1px solid #ddd;1900 border-radius: 8px;1901 padding: 20px;1902 }1903 1904 .instance-list, .instance-create, .instance-quick-reference {1905 margin-bottom: 25px;1906 }1907 1908 .instance-quick-reference {1909 background: #f8f9fa;1910 border: 1px solid #e9ecef;1911 border-radius: 6px;1912 padding: 15px;1913 }1914 1915 .instance-quick-reference h4 {1916 margin-top: 0;1917 color: #495057;1918 }1919 1920 .shortcodes-list {1921 margin-top: 15px;1922 }1923 1924 .shortcode-item {1925 background: white;1926 border: 1px solid #dee2e6;1927 border-radius: 4px;1928 padding: 10px;1929 margin-bottom: 8px;1930 display: flex;1931 align-items: center;1932 }1933 1934 .shortcode-item code {1935 flex: 1;1936 font-family: 'Courier New', monospace;1937 background: #f8f9fa;1938 padding: 4px 8px;1939 border-radius: 3px;1940 }1941 1942 .instance-table {1943 margin-top: 15px;1944 }1945 1946 .instance-search {1947 margin-bottom: 15px;1948 display: flex;1949 align-items: center;1950 }1951 1952 .instance-search input, .instance-search select {1953 padding: 5px 8px;1954 border: 1px solid #ccc;1955 border-radius: 3px;1956 }1957 1958 .layout-badge {1959 display: inline-block;1960 padding: 4px 8px;1961 border-radius: 12px;1962 font-size: 12px;1963 font-weight: bold;1964 text-transform: uppercase;1965 }1966 1967 .layout-grid { background: #e3f2fd; color: #1976d2; }1968 .layout-list { background: #f3e5f5; color: #7b1fa2; }1969 .layout-slider { background: #e8f5e8; color: #388e3c; }1970 1971 .action-buttons {1972 display: flex;1973 gap: 5px;1974 flex-wrap: wrap;1975 }1976 1977 .action-buttons .button {1978 font-size: 11px;1979 padding: 4px 8px;1980 }1981 1982 .instance-create-table {1983 background: #f8f9fa;1984 border: 1px solid #e9ecef;1985 border-radius: 6px;1986 padding: 15px;1987 }1988 1989 .loading-indicator {1990 color: #0073aa;1991 }1992 1993 .no-instances {1994 text-align: center;1995 padding: 30px;1996 background: #f8f9fa;1997 border: 1px solid #e9ecef;1998 border-radius: 6px;1999 }2000 </style>2001 2002 <!-- INLINE JAVASCRIPT REMOVED -->2003 1870 <?php 2004 1871 }
Note: See TracChangeset
for help on using the changeset viewer.