Changeset 3442776
- Timestamp:
- 01/19/2026 07:43:18 PM (2 months ago)
- Location:
- synced-pattern-popups
- Files:
-
- 35 added
- 12 edited
-
tags/1.3.0 (added)
-
tags/1.3.0/assets (added)
-
tags/1.3.0/assets/css (added)
-
tags/1.3.0/assets/css/admin.css (added)
-
tags/1.3.0/assets/css/modal.css (added)
-
tags/1.3.0/assets/js (added)
-
tags/1.3.0/assets/js/admin.js (added)
-
tags/1.3.0/assets/js/command-palette.js (added)
-
tags/1.3.0/assets/js/gallery-editor.js (added)
-
tags/1.3.0/assets/js/gallery.js (added)
-
tags/1.3.0/assets/js/modal.js (added)
-
tags/1.3.0/assets/patterns (added)
-
tags/1.3.0/assets/patterns/pattern-more-details.html (added)
-
tags/1.3.0/assets/patterns/pattern-terms-conditions.html (added)
-
tags/1.3.0/includes (added)
-
tags/1.3.0/includes/class-sppopups-abilities.php (added)
-
tags/1.3.0/includes/class-sppopups-admin.php (added)
-
tags/1.3.0/includes/class-sppopups-ajax.php (added)
-
tags/1.3.0/includes/class-sppopups-asset-collector.php (added)
-
tags/1.3.0/includes/class-sppopups-cache.php (added)
-
tags/1.3.0/includes/class-sppopups-command-palette.php (added)
-
tags/1.3.0/includes/class-sppopups-gallery.php (added)
-
tags/1.3.0/includes/class-sppopups-pattern.php (added)
-
tags/1.3.0/includes/class-sppopups-plugin.php (added)
-
tags/1.3.0/includes/class-sppopups-review-notice.php (added)
-
tags/1.3.0/includes/class-sppopups-settings.php (added)
-
tags/1.3.0/includes/class-sppopups-shipped-patterns.php (added)
-
tags/1.3.0/includes/class-sppopups-tldr.php (added)
-
tags/1.3.0/includes/class-sppopups-trigger-parser.php (added)
-
tags/1.3.0/languages (added)
-
tags/1.3.0/languages/synced-pattern-popups.pot (added)
-
tags/1.3.0/readme.txt (added)
-
tags/1.3.0/sppopups.php (added)
-
trunk/assets/css/admin.css (modified) (1 diff)
-
trunk/assets/css/modal.css (modified) (14 diffs)
-
trunk/assets/js/admin.js (modified) (7 diffs)
-
trunk/assets/js/command-palette.js (added)
-
trunk/assets/js/gallery.js (modified) (2 diffs)
-
trunk/assets/js/modal.js (modified) (5 diffs)
-
trunk/includes/class-sppopups-admin.php (modified) (8 diffs)
-
trunk/includes/class-sppopups-command-palette.php (added)
-
trunk/includes/class-sppopups-plugin.php (modified) (2 diffs)
-
trunk/includes/class-sppopups-review-notice.php (modified) (2 diffs)
-
trunk/includes/class-sppopups-settings.php (modified) (9 diffs)
-
trunk/languages/synced-pattern-popups.pot (modified) (12 diffs)
-
trunk/readme.txt (modified) (3 diffs)
-
trunk/sppopups.php (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
synced-pattern-popups/trunk/assets/css/admin.css
r3439916 r3442776 1041 1041 1042 1042 /* Gallery Block Editor Styles - Using standard TextControl, no custom styles needed */ 1043 1044 /* Defaults Accordion Styles */ 1045 .sppopups-defaults-accordion { 1046 border: 1px solid #dcdcde; 1047 border-radius: 4px; 1048 background: #fff; 1049 overflow: hidden; 1050 } 1051 1052 .sppopups-defaults-accordion-header { 1053 border-bottom: 1px solid #dcdcde; 1054 } 1055 1056 .sppopups-defaults-accordion:last-of-type { 1057 margin-bottom: 20px; 1058 } 1059 1060 .sppopups-defaults-accordion-trigger { 1061 width: 100%; 1062 padding: 16px 24px; 1063 background: #f6f7f7; 1064 border: none; 1065 cursor: pointer; 1066 text-align: left; 1067 display: flex; 1068 justify-content: space-between; 1069 align-items: center; 1070 font-size: 16px; 1071 font-weight: 600; 1072 color: #1d2327; 1073 transition: background-color 0.15s ease, color 0.15s ease; 1074 position: relative; 1075 } 1076 1077 .sppopups-defaults-accordion-trigger:hover { 1078 background: #f0f0f1; 1079 color: #2271b1; 1080 } 1081 1082 .sppopups-defaults-accordion-trigger:focus { 1083 outline: none; 1084 box-shadow: inset 0 0 0 1px #2271b1; 1085 } 1086 1087 .sppopups-defaults-accordion-trigger[aria-expanded="true"] { 1088 background: #f6f7f7; 1089 border-bottom: 1px solid #dcdcde; 1090 } 1091 1092 .sppopups-defaults-accordion-title { 1093 flex: 1; 1094 } 1095 1096 .sppopups-defaults-accordion-icon { 1097 width: 20px; 1098 height: 20px; 1099 position: relative; 1100 flex-shrink: 0; 1101 margin-left: 12px; 1102 transition: transform 0.3s ease; 1103 } 1104 1105 .sppopups-defaults-accordion-icon::before, 1106 .sppopups-defaults-accordion-icon::after { 1107 content: ''; 1108 position: absolute; 1109 background: currentColor; 1110 transition: transform 0.3s ease; 1111 } 1112 1113 .sppopups-defaults-accordion-icon::before { 1114 width: 12px; 1115 height: 2px; 1116 left: 50%; 1117 top: 50%; 1118 transform: translate(-50%, -50%); 1119 } 1120 1121 .sppopups-defaults-accordion-icon::after { 1122 width: 2px; 1123 height: 12px; 1124 left: 50%; 1125 top: 50%; 1126 transform: translate(-50%, -50%); 1127 } 1128 1129 .sppopups-defaults-accordion-trigger[aria-expanded="true"] .sppopups-defaults-accordion-icon::after { 1130 transform: translate(-50%, -50%) rotate(90deg); 1131 opacity: 0; 1132 } 1133 1134 .sppopups-defaults-accordion-content { 1135 overflow: hidden; 1136 transition: opacity 0.3s ease; 1137 opacity: 0; 1138 max-height: 0; 1139 } 1140 1141 .sppopups-defaults-accordion-content.is-open { 1142 opacity: 1; 1143 max-height: none; 1144 } -
synced-pattern-popups/trunk/assets/css/modal.css
r3439916 r3442776 42 42 width: 100%; 43 43 height: 100%; 44 background: rgba(0, 0, 0, 0.1);45 backdrop-filter: blur( 8px);46 -webkit-backdrop-filter: blur( 8px);44 background: var(--sppopups-overlay-color, rgba(0, 0, 0, 0.1)); 45 backdrop-filter: blur(var(--sppopups-backdrop-blur, 8px)); 46 -webkit-backdrop-filter: blur(var(--sppopups-backdrop-blur, 8px)); 47 47 } 48 48 … … 50 50 position: relative; 51 51 width: 100%; 52 max-width: 600px; 53 max-height: 90vh; 52 max-width: var(--sppopups-max-width, 600px); 53 /* 54 * Height behavior: 55 * - No explicit height allows container to shrink to content naturally (small content = small modal) 56 * - max-height constraint ensures it doesn't exceed viewport when content is tall 57 * - display: flex with flex-direction: column enables proper height constraint propagation 58 * - When content is small: container shrinks, card shrinks, no scrollbar 59 * - When content is tall: container hits max-height, card is constrained via flex, content scrolls 60 * 61 * IMPORTANT: Flex container here allows card (flex child) to respect the max-height constraint 62 * while still allowing natural shrinking when content is small. 63 */ 64 display: flex; 65 flex-direction: column; 66 max-height: var(--sppopups-max-height-vh, 90vh); 54 67 z-index: 1; 55 /* Fixed 6px border radius*/56 border-radius: 6px;68 /* Border radius from CSS variable */ 69 border-radius: var(--sppopups-border-radius, 6px); 57 70 /* Ensure inline max-width from JavaScript is respected */ 58 71 box-sizing: border-box; … … 71 84 right: -3px; 72 85 bottom: -3px; 73 border-radius: 9px;86 border-radius: calc(var(--sppopups-border-radius, 6px) + 3px); 74 87 background: conic-gradient( 75 88 from 0deg, … … 132 145 } 133 146 147 /* Hide footer close button if setting is disabled */ 148 .sppopups-modal:not([data-show-footer-close="true"]) .sppopups-close-footer { 149 display: none; 150 } 151 134 152 .sppopups-close-footer:hover { 135 153 color: #000; … … 144 162 .sppopups-card { 145 163 background: #ffffff; 146 border-radius: 8px;164 border-radius: calc(var(--sppopups-border-radius, 6px) + 2px); 147 165 box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3); 148 166 position: relative; 149 167 padding: 0; 150 168 animation: sppopups-fade-in 0.3s ease-out; 151 /* Ensure content doesn't overflow */169 /* Ensure content doesn't overflow the card boundaries */ 152 170 overflow: hidden; 153 171 border: none; 154 /* Flexbox for footer positioning */ 172 /* 173 * Flexbox column layout enables: 174 * - Content area to flex and scroll when constrained 175 * - Footer to stick to bottom (flex-shrink: 0) 176 * - Natural height growth for small content 177 */ 155 178 display: flex; 156 179 flex-direction: column; 157 height: 100%; 158 max-height: 90vh; 180 /* 181 * Height behavior as flex child of container: 182 * - flex: 1 1 auto allows card to grow/shrink naturally 183 * - min-height: 0 is CRITICAL - allows card to shrink below content size when constrained 184 * - When container is small: card shrinks to content, no scroll needed 185 * - When container hits max-height: card is constrained, content area scrolls 186 * 187 * IMPORTANT: min-height: 0 is required for flex items to shrink below their content size. 188 * Without it, the card won't respect the container's max-height constraint. 189 */ 190 flex: 1 1 auto; 191 min-height: 0; 159 192 z-index: 1; 160 193 } … … 211 244 } 212 245 246 /* Hide icon close button if setting is disabled */ 247 .sppopups-modal:not([data-show-icon-close="true"]) .sppopups-close { 248 display: none; 249 } 250 213 251 .sppopups-close:hover { 214 252 color: #000; … … 233 271 .sppopups-content { 234 272 width: 100%; 235 min-height: 200px;236 273 position: relative; 237 274 z-index: 1; 238 /* Make content scrollable */ 275 /* 276 * Overflow behavior: auto enables scrollbar only when content exceeds available space. 277 * This works because: 278 * - Small content: card/container grow naturally, no scrollbar needed 279 * - Tall content: container hits max-height, card constrained, content scrolls 280 */ 239 281 overflow-y: auto; 240 282 overflow-x: hidden; 241 flex: 1; 283 /* 284 * Flex: 1 allows content to fill available space in flex column. 285 * min-height: 0 is CRITICAL - without it, flex items won't shrink below content size, 286 * preventing scrolling. This is a flexbox quirk that must be set. 287 */ 288 flex: 1 1 auto; 289 min-height: 0; 242 290 243 291 /* Smooth scrolling on iOS */ … … 317 365 .sppopups-container { 318 366 max-width: 100%; 319 max-height: calc(100vh - 20px);320 max-height: calc(100vh - max(20px, env(safe-area-inset-top)) - max(20px, env(safe-area-inset-bottom)));321 border-radius: 6px;367 /* Use CSS variable if set (percentage converted to vh), otherwise calculate from viewport */ 368 max-height: var(--sppopups-max-height-vh, calc(100vh - max(20px, env(safe-area-inset-top)) - max(20px, env(safe-area-inset-bottom)))); 369 border-radius: var(--sppopups-border-radius, 6px); 322 370 } 323 371 324 372 .sppopups-container::before { 325 border-radius: 8px;373 border-radius: calc(var(--sppopups-border-radius, 6px) + 3px); 326 374 } 327 375 … … 369 417 .sppopups-container { 370 418 max-width: 90%; 371 max-height: 85vh; 419 /* Use CSS variable if set (percentage converted to vh), otherwise use 85vh */ 420 max-height: var(--sppopups-max-height-vh, 85vh); 372 421 } 373 422 … … 384 433 @media screen and (min-width: 769px) { 385 434 .sppopups-container { 386 max-width: 600px;435 max-width: var(--sppopups-max-width, 600px); 387 436 } 388 437 } … … 404 453 405 454 .sppopups-container { 406 max-height: calc(100vh - 20px);407 max-height: calc(100vh - max(20px, env(safe-area-inset-top)) - max(20px, env(safe-area-inset-bottom)));455 /* Use CSS variable if set (percentage converted to vh), otherwise calculate from viewport */ 456 max-height: var(--sppopups-max-height-vh, calc(100vh - max(20px, env(safe-area-inset-top)) - max(20px, env(safe-area-inset-bottom)))); 408 457 margin-top: 10px; 409 border-radius: 6px;458 border-radius: var(--sppopups-border-radius, 6px); 410 459 } 411 460 412 461 .sppopups-container::before { 413 border-radius: 8px;462 border-radius: calc(var(--sppopups-border-radius, 6px) + 3px); 414 463 } 415 464 … … 500 549 box-sizing: border-box; 501 550 opacity: 0; 502 transition: opacity 0.5scubic-bezier(0.4, 0, 0.2, 1);551 transition: opacity var(--sppopups-gallery-transition-duration, 500ms) cubic-bezier(0.4, 0, 0.2, 1); 503 552 pointer-events: none; 504 553 z-index: 1; 554 } 555 556 /* Disable crossfade transition if setting is disabled */ 557 .sppopups-modal:not([data-gallery-crossfade="true"]) .sppopups-gallery-image-wrapper { 558 transition: opacity 0ms; 505 559 } 506 560 … … 592 646 } 593 647 648 /* Always show navigation buttons if hover setting is disabled */ 649 .sppopups-modal:not([data-gallery-nav-hover="true"]) .sppopups-gallery-nav { 650 opacity: 1; 651 pointer-events: auto; 652 } 653 594 654 .sppopups-gallery-nav:hover { 595 655 color: #000; … … 676 736 } 677 737 738 /* Hide captions if setting is disabled */ 739 .sppopups-modal:not([data-gallery-show-captions="true"]) .sppopups-gallery-caption { 740 display: none; 741 } 742 678 743 /* If caption contains HTML, allow it to display properly */ 679 744 .sppopups-gallery-caption p { -
synced-pattern-popups/trunk/assets/js/admin.js
r3439916 r3442776 150 150 window.location.hash = '#' + tabId; 151 151 } 152 153 // Update form tab fields when tab switches 154 if (typeof window.sppopupsUpdateTabFields === 'function') { 155 window.sppopupsUpdateTabFields(); 156 } 152 157 } 153 158 … … 176 181 function handleInitialTab() { 177 182 var hash = window.location.hash.substring( 1 ); 178 var validTabs = ['patterns', 'tldr', ' how-to-use'];183 var validTabs = ['patterns', 'tldr', 'defaults', 'how-to-use']; 179 184 180 185 if (hash && validTabs.indexOf( hash ) !== -1) { … … 189 194 function handleHashChange() { 190 195 var hash = window.location.hash.substring( 1 ); 191 var validTabs = ['patterns', 'tldr', ' how-to-use'];196 var validTabs = ['patterns', 'tldr', 'defaults', 'how-to-use']; 192 197 193 198 if (hash && validTabs.indexOf( hash ) !== -1) { … … 205 210 if (target && target.getAttribute( 'href' ) && target.getAttribute( 'href' ).startsWith( '#' )) { 206 211 var hash = target.getAttribute( 'href' ).substring( 1 ); 207 var validTabs = ['patterns', 'tldr', ' how-to-use'];212 var validTabs = ['patterns', 'tldr', 'defaults', 'how-to-use']; 208 213 209 214 if (validTabs.indexOf( hash ) !== -1) { … … 339 344 ); 340 345 346 // Initialize form tab persistence first (so it's available when tabs initialize) 347 initFormTabPersistence(); 348 341 349 // Initialize tabs 342 350 initTabs(); … … 347 355 // Initialize TLDR prompt type toggle 348 356 initTldrPromptToggle(); 357 358 // Initialize defaults inheritance toggles 359 initDefaultsInheritanceToggles(); 360 361 // Initialize defaults accordions 362 initDefaultsAccordions(); 363 } 364 365 /** 366 * Initialize defaults accordions 367 */ 368 function initDefaultsAccordions() { 369 var accordionTriggers = document.querySelectorAll( '.sppopups-defaults-accordion-trigger' ); 370 371 accordionTriggers.forEach( 372 function (trigger) { 373 trigger.addEventListener( 374 'click', 375 function () { 376 var isExpanded = trigger.getAttribute( 'aria-expanded' ) === 'true'; 377 var contentId = trigger.getAttribute( 'aria-controls' ); 378 var content = document.getElementById( contentId ); 379 380 if ( ! content) { 381 return; 382 } 383 384 // Toggle state 385 var newExpanded = ! isExpanded; 386 trigger.setAttribute( 'aria-expanded', newExpanded.toString() ); 387 388 // Toggle content visibility 389 if (newExpanded) { 390 // Set display first, then trigger transition 391 content.style.display = 'block'; 392 // Force reflow to ensure display is applied 393 content.offsetHeight; 394 // Add class to trigger transition 395 content.classList.add( 'is-open' ); 396 } else { 397 // Remove class to trigger transition 398 content.classList.remove( 'is-open' ); 399 // Wait for transition to complete before hiding 400 setTimeout( 401 function () { 402 if ( ! content.classList.contains( 'is-open' )) { 403 content.style.display = 'none'; 404 } 405 }, 406 300 407 ); 408 } 409 } 410 ); 411 } 412 ); 349 413 } 350 414 … … 462 526 // Initialize review notice dismiss functionality 463 527 initReviewNoticeDismiss(); 528 529 /** 530 * Initialize defaults inheritance toggles 531 */ 532 function initDefaultsInheritanceToggles() { 533 // TLDR inheritance toggles 534 var tldrModalAppearanceRadios = document.querySelectorAll( 'input[name="sppopups_defaults_tldr[inheritModalAppearance]"]' ); 535 var tldrOverlayRadios = document.querySelectorAll( 'input[name="sppopups_defaults_tldr[inheritOverlay]"]' ); 536 var tldrCloseButtonsRadios = document.querySelectorAll( 'input[name="sppopups_defaults_tldr[inheritCloseButtons]"]' ); 537 538 // Gallery inheritance toggles 539 var galleryModalAppearanceRadios = document.querySelectorAll( 'input[name="sppopups_defaults_gallery[inheritModalAppearance]"]' ); 540 var galleryOverlayRadios = document.querySelectorAll( 'input[name="sppopups_defaults_gallery[inheritOverlay]"]' ); 541 var galleryCloseButtonsRadios = document.querySelectorAll( 'input[name="sppopups_defaults_gallery[inheritCloseButtons]"]' ); 542 543 // Toggle function for TLDR modal appearance 544 function toggleTldrModalAppearance() { 545 var selectedValue = ''; 546 tldrModalAppearanceRadios.forEach( 547 function (radio) { 548 if (radio.checked) { 549 selectedValue = radio.value; 550 } 551 } 552 ); 553 554 var customWrapper = document.getElementById( 'tldr-modal-appearance-custom' ); 555 if (customWrapper) { 556 customWrapper.style.display = (selectedValue === '0') ? 'block' : 'none'; 557 } 558 } 559 560 // Toggle function for TLDR overlay 561 function toggleTldrOverlay() { 562 var selectedValue = ''; 563 tldrOverlayRadios.forEach( 564 function (radio) { 565 if (radio.checked) { 566 selectedValue = radio.value; 567 } 568 } 569 ); 570 571 var customWrapper = document.getElementById( 'tldr-overlay-custom' ); 572 if (customWrapper) { 573 customWrapper.style.display = (selectedValue === '0') ? 'block' : 'none'; 574 } 575 } 576 577 // Toggle function for TLDR close buttons 578 function toggleTldrCloseButtons() { 579 var selectedValue = ''; 580 tldrCloseButtonsRadios.forEach( 581 function (radio) { 582 if (radio.checked) { 583 selectedValue = radio.value; 584 } 585 } 586 ); 587 588 var customWrapper = document.getElementById( 'tldr-close-buttons-custom' ); 589 if (customWrapper) { 590 customWrapper.style.display = (selectedValue === '0') ? 'block' : 'none'; 591 } 592 } 593 594 // Toggle function for Gallery modal appearance 595 function toggleGalleryModalAppearance() { 596 var selectedValue = ''; 597 galleryModalAppearanceRadios.forEach( 598 function (radio) { 599 if (radio.checked) { 600 selectedValue = radio.value; 601 } 602 } 603 ); 604 605 var customWrapper = document.getElementById( 'gallery-modal-appearance-custom' ); 606 if (customWrapper) { 607 customWrapper.style.display = (selectedValue === '0') ? 'block' : 'none'; 608 } 609 } 610 611 // Toggle function for Gallery overlay 612 function toggleGalleryOverlay() { 613 var selectedValue = ''; 614 galleryOverlayRadios.forEach( 615 function (radio) { 616 if (radio.checked) { 617 selectedValue = radio.value; 618 } 619 } 620 ); 621 622 var customWrapper = document.getElementById( 'gallery-overlay-custom' ); 623 if (customWrapper) { 624 customWrapper.style.display = (selectedValue === '0') ? 'block' : 'none'; 625 } 626 } 627 628 // Toggle function for Gallery close buttons 629 function toggleGalleryCloseButtons() { 630 var selectedValue = ''; 631 galleryCloseButtonsRadios.forEach( 632 function (radio) { 633 if (radio.checked) { 634 selectedValue = radio.value; 635 } 636 } 637 ); 638 639 var customWrapper = document.getElementById( 'gallery-close-buttons-custom' ); 640 if (customWrapper) { 641 customWrapper.style.display = (selectedValue === '0') ? 'block' : 'none'; 642 } 643 } 644 645 // Set initial state 646 toggleTldrModalAppearance(); 647 toggleTldrOverlay(); 648 toggleTldrCloseButtons(); 649 toggleGalleryModalAppearance(); 650 toggleGalleryOverlay(); 651 toggleGalleryCloseButtons(); 652 653 // Listen for changes 654 tldrModalAppearanceRadios.forEach( 655 function (radio) { 656 radio.addEventListener( 'change', toggleTldrModalAppearance ); 657 } 658 ); 659 660 tldrOverlayRadios.forEach( 661 function (radio) { 662 radio.addEventListener( 'change', toggleTldrOverlay ); 663 } 664 ); 665 666 tldrCloseButtonsRadios.forEach( 667 function (radio) { 668 radio.addEventListener( 'change', toggleTldrCloseButtons ); 669 } 670 ); 671 672 galleryModalAppearanceRadios.forEach( 673 function (radio) { 674 radio.addEventListener( 'change', toggleGalleryModalAppearance ); 675 } 676 ); 677 678 galleryOverlayRadios.forEach( 679 function (radio) { 680 radio.addEventListener( 'change', toggleGalleryOverlay ); 681 } 682 ); 683 684 galleryCloseButtonsRadios.forEach( 685 function (radio) { 686 radio.addEventListener( 'change', toggleGalleryCloseButtons ); 687 } 688 ); 689 } 690 691 /** 692 * Initialize form tab persistence 693 * Updates hidden tab fields before form submission to preserve current tab 694 */ 695 function initFormTabPersistence() { 696 // Get all hidden tab input fields 697 var tabFields = document.querySelectorAll( 'input[name="sppopups_current_tab"]' ); 698 699 if ( ! tabFields.length) { 700 return; 701 } 702 703 // Function to get current tab from URL hash or active tab 704 function getCurrentTab() { 705 // First, try to get from URL hash 706 var hash = window.location.hash.substring( 1 ); 707 var validTabs = ['patterns', 'tldr', 'defaults', 'how-to-use']; 708 if (hash && validTabs.indexOf( hash ) !== -1) { 709 return hash; 710 } 711 712 // If no hash, try to detect active tab from DOM 713 var activeTabLink = document.querySelector( '.sppopups-tab-nav-link.active' ); 714 if (activeTabLink) { 715 var href = activeTabLink.getAttribute( 'href' ); 716 if (href && href.startsWith( '#' )) { 717 var tabId = href.substring( 1 ); 718 if (validTabs.indexOf( tabId ) !== -1) { 719 return tabId; 720 } 721 } 722 } 723 724 // Check which tab content is visible 725 var activeTabContent = document.querySelector( '.sppopups-tab-content.active' ); 726 if (activeTabContent) { 727 var tabId = activeTabContent.id.replace( 'sppopups-tab-', '' ); 728 if (validTabs.indexOf( tabId ) !== -1) { 729 return tabId; 730 } 731 } 732 733 // Default to patterns if nothing found 734 return 'patterns'; 735 } 736 737 // Update all hidden tab fields with current tab 738 function updateTabFields() { 739 var currentTab = getCurrentTab(); 740 tabFields.forEach( 741 function (field) { 742 field.value = currentTab; 743 } 744 ); 745 } 746 747 // Make updateTabFields available globally so switchTab can call it 748 window.sppopupsUpdateTabFields = updateTabFields; 749 750 // Update on page load (with a small delay to ensure tabs are initialized) 751 setTimeout( 752 function () { 753 updateTabFields(); 754 }, 755 100 756 ); 757 758 // Update when hash changes (tab switch) 759 window.addEventListener( 760 'hashchange', 761 function () { 762 updateTabFields(); 763 } 764 ); 765 766 // Update before form submission to ensure we have the latest tab 767 tabFields.forEach( 768 function (field) { 769 var form = field.closest( 'form' ); 770 if (form) { 771 form.addEventListener( 772 'submit', 773 function (e) { 774 // Update immediately before submission 775 updateTabFields(); 776 }, 777 false 778 ); 779 } 780 } 781 ); 782 } 464 783 })(); -
synced-pattern-popups/trunk/assets/js/gallery.js
r3439916 r3442776 30 30 closeModal: null, 31 31 setupModalState: null, 32 applyModalDefaults: null, 33 getDefaultsForType: null, 32 34 getTitleElement: null, 33 35 focusWithoutScroll: null, … … 525 527 currentGalleryData.settings = settings; 526 528 527 // Set modal size 529 // Get gallery defaults 530 var galleryDefaults = null; 531 if (dependencies.getDefaultsForType) { 532 galleryDefaults = dependencies.getDefaultsForType( 'gallery' ); 533 } 534 535 // Apply defaults to modal (overrides with gallery-specific settings if provided) 536 var overrides = {}; 537 if (settings.modalSize) { 538 overrides.maxWidth = settings.modalSize; 539 } 540 if (dependencies.applyModalDefaults && dependencies.modal) { 541 dependencies.applyModalDefaults( dependencies.modal, 'gallery', overrides ); 542 } 543 544 // Set modal size (may be overridden by defaults) 528 545 if (dependencies.container) { 529 dependencies.container.style.maxWidth = settings.modalSize + 'px'; 546 var finalMaxWidth = overrides.maxWidth || (galleryDefaults && galleryDefaults.maxWidth) || settings.modalSize || 600; 547 dependencies.container.style.maxWidth = finalMaxWidth + 'px'; 530 548 if (dependencies.setCurrentMaxWidth) { 531 dependencies.setCurrentMaxWidth( settings.modalSize ); 532 } 533 } 534 535 // Show/hide close buttons based on setting 536 if (dependencies.closeBtn) { 537 dependencies.closeBtn.style.display = (settings.closeButtons === 'icon' || settings.closeButtons === 'both') ? '' : 'none'; 538 } 539 540 // Use common modal setup 541 dependencies.setupModalState( settings.modalSize, '' ); 549 dependencies.setCurrentMaxWidth( finalMaxWidth ); 550 } 551 } 552 553 // Use common modal setup with gallery type 554 dependencies.setupModalState( settings.modalSize || null, '', 'gallery' ); 542 555 543 556 // Create container for gallery images -
synced-pattern-popups/trunk/assets/js/modal.js
r3439916 r3442776 561 561 562 562 /** 563 * Get defaults for a popup type with inheritance logic applied 564 * 565 * @param {string} popupType Popup type: 'pattern', 'tldr', or 'gallery' 566 * @return {object} Complete defaults object with inheritance resolved 567 */ 568 function getDefaultsForType(popupType) { 569 // Check if defaults are available 570 if ( ! sppopups || ! sppopups.defaults || ! sppopups.defaults[popupType]) { 571 // Log warning if defaults not available (helps with debugging) 572 if (window.console && console.warn) { 573 console.warn( 'SPPopups: Defaults not available for type', popupType, '- using fallback defaults' ); 574 } 575 // Fallback to hardcoded defaults if not available 576 return { 577 maxWidth: 600, 578 borderRadius: 6, 579 maxHeight: 90, 580 overlayColor: 'rgba(0, 0, 0, 0.1)', 581 backdropBlur: 8, 582 showIconClose: true, 583 showFooterClose: true, 584 footerCloseText: 'Close →' 585 }; 586 } 587 588 return sppopups.defaults[popupType]; 589 } 590 591 /** 592 * Apply CSS variables and data attributes to modal based on defaults 593 * 594 * @param {HTMLElement} modalElement Modal element 595 * @param {string} popupType Popup type: 'pattern', 'tldr', or 'gallery' 596 * @param {object} overrides Optional overrides (e.g., custom max-width from trigger) 597 * @return {object} Applied defaults object 598 */ 599 function applyModalDefaults(modalElement, popupType, overrides) { 600 var defaults = getDefaultsForType(popupType); 601 602 // Apply overrides if provided 603 if (overrides) { 604 defaults = Object.assign( {}, defaults, overrides); 605 } 606 607 // Set CSS variables 608 modalElement.style.setProperty( '--sppopups-max-width', defaults.maxWidth + 'px' ); 609 modalElement.style.setProperty( '--sppopups-border-radius', defaults.borderRadius + 'px' ); 610 // Convert percentage to viewport height units for proper scrolling 611 modalElement.style.setProperty( '--sppopups-max-height', defaults.maxHeight + '%' ); 612 modalElement.style.setProperty( '--sppopups-max-height-vh', defaults.maxHeight + 'vh' ); 613 modalElement.style.setProperty( '--sppopups-overlay-color', defaults.overlayColor ); 614 modalElement.style.setProperty( '--sppopups-backdrop-blur', defaults.backdropBlur + 'px' ); 615 616 // Set data attributes for conditional CSS 617 modalElement.setAttribute( 'data-show-icon-close', defaults.showIconClose ? 'true' : 'false' ); 618 modalElement.setAttribute( 'data-show-footer-close', defaults.showFooterClose ? 'true' : 'false' ); 619 620 // Gallery-specific attributes 621 if (popupType === 'gallery') { 622 modalElement.setAttribute( 'data-gallery-crossfade', defaults.crossfadeTransition ? 'true' : 'false' ); 623 modalElement.setAttribute( 'data-gallery-show-captions', defaults.showCaptions ? 'true' : 'false' ); 624 modalElement.setAttribute( 'data-gallery-nav-hover', defaults.showNavOnHover ? 'true' : 'false' ); 625 if (defaults.transitionDuration !== undefined) { 626 modalElement.style.setProperty( '--sppopups-gallery-transition-duration', defaults.transitionDuration + 'ms' ); 627 } 628 } 629 630 // Update footer close button text if available 631 if (defaults.footerCloseText && closeFooterBtn) { 632 closeFooterBtn.textContent = defaults.footerCloseText; 633 } 634 635 return defaults; 636 } 637 638 /** 563 639 * Setup modal state (common initialization logic) 564 640 * 565 641 * @param {number|null} maxWidth Optional max-width in pixels 566 642 * @param {string} loadingContent HTML content to show while loading 567 */ 568 function setupModalState(maxWidth, loadingContent) { 643 * @param {string} popupType Optional popup type for applying defaults 644 */ 645 function setupModalState(maxWidth, loadingContent, popupType) { 569 646 // Save scroll position BEFORE any DOM changes (for all screen sizes) 570 647 savedScrollPosition = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0; … … 573 650 lastActiveElement = document.activeElement; 574 651 575 // Store the requested max-width for resize handling 576 currentMaxWidth = maxWidth; 577 578 // Calculate and apply max-width with 6% margin 652 // Apply defaults if popup type is provided 653 var finalMaxWidth = maxWidth; 654 var overrides = {}; 579 655 if (maxWidth !== null) { 580 var calculatedWidth = calculateMaxWidth( maxWidth ); 656 overrides.maxWidth = maxWidth; 657 } 658 659 if (popupType) { 660 var appliedDefaults = applyModalDefaults( modal, popupType, overrides ); 661 // Use the applied max-width from defaults (or override) 662 finalMaxWidth = appliedDefaults.maxWidth; 663 // Debug: log applied defaults (remove in production if desired) 664 if (window.console && console.log) { 665 console.log( 'SPPopups: Applied defaults for', popupType, appliedDefaults ); 666 } 667 } else { 668 // Legacy behavior: use provided maxWidth or default 669 if (maxWidth === null) { 670 finalMaxWidth = 600; // Legacy default 671 } 672 } 673 674 // Store the final max-width for resize handling 675 currentMaxWidth = finalMaxWidth; 676 677 // Apply max-width to container (with 6% margin calculation) 678 if (finalMaxWidth !== null) { 679 var calculatedWidth = calculateMaxWidth( finalMaxWidth ); 581 680 container.style.maxWidth = calculatedWidth + 'px'; 582 681 } else { … … 639 738 } 640 739 641 setupModalState( maxWidth, loadingHtml );740 setupModalState( maxWidth, loadingHtml, 'pattern' ); 642 741 643 742 // Prepare form data for POST request … … 1126 1225 } 1127 1226 1128 // Use common modal setup (no custom max-width for TLDR) 1129 setupModalState( null, '<div class="sppopups-loading"><div class="sppopups-spinner"></div><p>Generating TLDR</p></div>' ); 1227 // Get TLDR defaults for loading text and title 1228 var tldrDefaults = getDefaultsForType( 'tldr' ); 1229 var loadingText = tldrDefaults.loadingText || 'Generating TLDR'; 1230 var titleText = tldrDefaults.titleText || 'TLDR'; 1231 1232 // Use common modal setup with TLDR defaults 1233 setupModalState( null, '<div class="sppopups-loading"><div class="sppopups-spinner"></div><p>' + loadingText + '</p></div>', 'tldr' ); 1234 1235 // Set title if available 1236 var titleEl = getTitleElement(); 1237 if (titleEl) { 1238 titleEl.textContent = titleText; 1239 } 1130 1240 1131 1241 // Prepare form data … … 1212 1322 closeModal: closeModal, 1213 1323 setupModalState: setupModalState, 1324 applyModalDefaults: applyModalDefaults, 1325 getDefaultsForType: getDefaultsForType, 1214 1326 getTitleElement: getTitleElement, 1215 1327 focusWithoutScroll: focusWithoutScroll, -
synced-pattern-popups/trunk/includes/class-sppopups-admin.php
r3439916 r3442776 199 199 } 200 200 201 wp_safe_redirect( admin_url( 'themes.php?page=simplest-popup-patterns&tldr_settings_saved=1' ) ); 201 // Get current tab from form submission, default to 'tldr' if not provided. 202 $current_tab = isset( $_POST['sppopups_current_tab'] ) ? sanitize_text_field( wp_unslash( $_POST['sppopups_current_tab'] ) ) : 'tldr'; 203 // Ensure tab is valid. 204 $valid_tabs = array( 'patterns', 'tldr', 'defaults', 'how-to-use' ); 205 if ( ! in_array( $current_tab, $valid_tabs, true ) ) { 206 $current_tab = 'tldr'; 207 } 208 wp_safe_redirect( admin_url( 'themes.php?page=simplest-popup-patterns&tldr_settings_saved=1#' . $current_tab ) ); 209 exit; 210 } 211 } 212 213 // Handle defaults settings save. 214 if ( isset( $_POST['save_defaults_settings'] ) && isset( $_POST['sppopups_defaults_settings_nonce'] ) ) { 215 if ( ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['sppopups_defaults_settings_nonce'] ) ), 'sppopups_save_defaults_settings' ) ) { 216 wp_die( esc_html__( 'Security check failed.', 'synced-pattern-popups' ) ); 217 } 218 219 if ( current_user_can( 'manage_options' ) ) { 220 $settings = new SPPopups_Settings(); 221 222 // Save pattern defaults. 223 if ( isset( $_POST['sppopups_defaults_pattern'] ) && is_array( $_POST['sppopups_defaults_pattern'] ) ) { 224 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized via sanitize_pattern_defaults callback 225 $pattern_defaults = $settings->sanitize_pattern_defaults( wp_unslash( $_POST['sppopups_defaults_pattern'] ) ); 226 update_option( 'sppopups_defaults_pattern', $pattern_defaults ); 227 } 228 229 // Save TLDR defaults. 230 if ( isset( $_POST['sppopups_defaults_tldr'] ) && is_array( $_POST['sppopups_defaults_tldr'] ) ) { 231 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized via sanitize_tldr_defaults callback 232 $tldr_defaults = $settings->sanitize_tldr_defaults( wp_unslash( $_POST['sppopups_defaults_tldr'] ) ); 233 update_option( 'sppopups_defaults_tldr', $tldr_defaults ); 234 } 235 236 // Save gallery defaults. 237 if ( isset( $_POST['sppopups_defaults_gallery'] ) && is_array( $_POST['sppopups_defaults_gallery'] ) ) { 238 // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized via sanitize_gallery_defaults callback 239 $gallery_defaults = $settings->sanitize_gallery_defaults( wp_unslash( $_POST['sppopups_defaults_gallery'] ) ); 240 update_option( 'sppopups_defaults_gallery', $gallery_defaults ); 241 } 242 243 // Clear all transients when defaults are saved (defaults affect modal appearance). 244 $deleted_count = $this->cache_service->clear_all(); 245 246 // Get current tab from form submission, default to 'defaults' if not provided. 247 $current_tab = isset( $_POST['sppopups_current_tab'] ) ? sanitize_text_field( wp_unslash( $_POST['sppopups_current_tab'] ) ) : 'defaults'; 248 // Ensure tab is valid. 249 $valid_tabs = array( 'patterns', 'tldr', 'defaults', 'how-to-use' ); 250 if ( ! in_array( $current_tab, $valid_tabs, true ) ) { 251 $current_tab = 'defaults'; 252 } 253 wp_safe_redirect( admin_url( 'themes.php?page=simplest-popup-patterns&defaults_settings_saved=1&cache_cleared=1&deleted=' . absint( $deleted_count ) . '#' . $current_tab ) ); 202 254 exit; 203 255 } … … 233 285 $cache_cleared = isset( $_GET['cache_cleared'] ) ? sanitize_text_field( wp_unslash( $_GET['cache_cleared'] ) ) : ''; 234 286 $deleted_count = isset( $_GET['deleted'] ) ? absint( $_GET['deleted'] ) : 0; 235 $tldr_settings_saved = isset( $_GET['tldr_settings_saved'] ) ? sanitize_text_field( wp_unslash( $_GET['tldr_settings_saved'] ) ) : ''; 236 $transient_deleted = isset( $_GET['transient_deleted'] ) ? sanitize_text_field( wp_unslash( $_GET['transient_deleted'] ) ) : ''; 237 $transient_pattern_id = isset( $_GET['pattern_id'] ) ? absint( $_GET['pattern_id'] ) : 0; 287 $tldr_settings_saved = isset( $_GET['tldr_settings_saved'] ) ? sanitize_text_field( wp_unslash( $_GET['tldr_settings_saved'] ) ) : ''; 288 $defaults_settings_saved = isset( $_GET['defaults_settings_saved'] ) ? sanitize_text_field( wp_unslash( $_GET['defaults_settings_saved'] ) ) : ''; 289 $transient_deleted = isset( $_GET['transient_deleted'] ) ? sanitize_text_field( wp_unslash( $_GET['transient_deleted'] ) ) : ''; 290 $transient_pattern_id = isset( $_GET['pattern_id'] ) ? absint( $_GET['pattern_id'] ) : 0; 238 291 // phpcs:enable WordPress.Security.NonceVerification.Recommended 239 292 … … 267 320 if ( '1' === $tldr_settings_saved ) { 268 321 echo '<div class="notice notice-success is-dismissible"><p>' . esc_html__( 'TLDR settings saved successfully.', 'synced-pattern-popups' ) . '</p></div>'; 322 } 323 324 if ( '1' === $defaults_settings_saved ) { 325 echo '<div class="notice notice-success is-dismissible"><p>' . esc_html__( 'Defaults settings saved successfully.', 'synced-pattern-popups' ) . '</p></div>'; 269 326 } 270 327 … … 290 347 <a href="#tldr" class="sppopups-tab-nav-link" role="tab" aria-selected="false" aria-controls="sppopups-tab-tldr"> 291 348 <?php esc_html_e( 'TLDR', 'synced-pattern-popups' ); ?> 349 </a> 350 <a href="#defaults" class="sppopups-tab-nav-link" role="tab" aria-selected="false" aria-controls="sppopups-tab-defaults"> 351 <?php esc_html_e( 'Defaults', 'synced-pattern-popups' ); ?> 292 352 </a> 293 353 <a href="#how-to-use" class="sppopups-tab-nav-link" role="tab" aria-selected="false" aria-controls="sppopups-tab-how-to-use"> … … 405 465 <div class="sppopups-trigger-code-wrapper"> 406 466 <span class="sppopups-trigger-code-text"><?php echo esc_html( $trigger_code ); ?></span> 407 <button 408 type="button" 409 class="button button-small sppopups-copy-trigger-icon" 467 <button 468 type="button" 469 class="button button-small sppopups-copy-trigger-icon" 410 470 data-copy="<?php echo esc_attr( $trigger_code ); ?>" 411 471 title="<?php esc_attr_e( 'Copy to Clipboard', 'synced-pattern-popups' ); ?>" … … 426 486 <?php endif; ?> 427 487 <?php if ( current_user_can( 'delete_post', $pattern_id ) ) : ?> 428 <a 429 href="<?php echo esc_url( $delete_url ); ?>" 488 <a 489 href="<?php echo esc_url( $delete_url ); ?>" 430 490 class="button button-small delete-pattern" 431 491 onclick="return confirm('<?php echo esc_js( __( 'Are you sure you want to delete this pattern?', 'synced-pattern-popups' ) ); ?>');" … … 441 501 ); 442 502 ?> 443 <a 444 href="<?php echo esc_url( $delete_transient_url ); ?>" 503 <a 504 href="<?php echo esc_url( $delete_transient_url ); ?>" 445 505 class="button button-small delete-transient sppopups-action-transient" 446 506 onclick="return confirm(' … … 475 535 </div> 476 536 537 <!-- Defaults Tab --> 538 <div id="sppopups-tab-defaults" class="sppopups-tab-content" role="tabpanel" aria-labelledby="defaults"> 539 <?php 540 // Render defaults settings section. 541 $settings = new SPPopups_Settings(); 542 $settings->render_defaults_section(); 543 ?> 544 </div> 545 477 546 <!-- How to Use Tab --> 478 547 <div id="sppopups-tab-how-to-use" class="sppopups-tab-content" role="tabpanel" aria-labelledby="how-to-use"> -
synced-pattern-popups/trunk/includes/class-sppopups-plugin.php
r3439916 r3442776 86 86 $this->abilities = new SPPopups_Abilities( $this->pattern_service, $this->cache_service, $this->style_collector ); 87 87 $this->abilities->init(); 88 } 89 90 // Initialize Command Palette integration (WP 6.3+ only) 91 // This will gracefully skip if Command Palette API is not available. 92 if ( version_compare( get_bloginfo( 'version' ), '6.3', '>=' ) && is_admin() ) { 93 $command_palette = new SPPopups_Command_Palette( $this->pattern_service, $this->cache_service ); 94 $command_palette->init(); 88 95 } 89 96 … … 386 393 'styleUrls' => $style_urls, 387 394 'scriptUrls' => $script_urls, 395 'defaults' => array( 396 'pattern' => SPPopups_Settings::get_pattern_defaults(), 397 'tldr' => SPPopups_Settings::get_tldr_defaults(), 398 'gallery' => SPPopups_Settings::get_gallery_defaults(), 399 ), 388 400 'strings' => array( 389 401 'loading' => __( 'Loading content...', 'synced-pattern-popups' ), -
synced-pattern-popups/trunk/includes/class-sppopups-review-notice.php
r3439916 r3442776 175 175 ?> 176 176 </h3> 177 177 178 178 <p class="sppopups-review-notice-subheading"> 179 179 <?php esc_html_e( 'Leave us a kind review on WordPress.org', 'synced-pattern-popups' ); ?> 180 180 </p> 181 181 182 182 <div class="sppopups-review-notice-stars"> 183 183 ⭐⭐⭐⭐⭐ 184 184 </div> 185 185 186 186 <div class="sppopups-review-notice-actions"> 187 187 <a href="<?php echo esc_url( $review_url ); ?>" target="_blank" rel="noopener noreferrer" class="sppopups-review-notice-button"> … … 192 192 </a> 193 193 </div> 194 194 195 195 <p class="sppopups-review-notice-footer"> 196 196 <em><?php esc_html_e( 'Your review and feedback keeps us developing this plugin for more users like you!', 'synced-pattern-popups' ); ?></em> -
synced-pattern-popups/trunk/includes/class-sppopups-settings.php
r3439916 r3442776 75 75 ) 76 76 ); 77 78 // Register defaults settings. 79 register_setting( 80 $this->option_group, 81 'sppopups_defaults_pattern', 82 array( 83 'type' => 'array', 84 'sanitize_callback' => array( $this, 'sanitize_pattern_defaults' ), 85 'default' => $this->get_default_pattern_defaults(), 86 ) 87 ); 88 89 register_setting( 90 $this->option_group, 91 'sppopups_defaults_tldr', 92 array( 93 'type' => 'array', 94 'sanitize_callback' => array( $this, 'sanitize_tldr_defaults' ), 95 'default' => $this->get_default_tldr_defaults(), 96 ) 97 ); 98 99 register_setting( 100 $this->option_group, 101 'sppopups_defaults_gallery', 102 array( 103 'type' => 'array', 104 'sanitize_callback' => array( $this, 'sanitize_gallery_defaults' ), 105 'default' => $this->get_default_gallery_defaults(), 106 ) 107 ); 77 108 } 78 109 … … 85 116 public function sanitize_boolean( $value ) { 86 117 return (bool) $value; 118 } 119 120 /** 121 * Get default pattern defaults 122 * 123 * @return array Default pattern defaults 124 */ 125 private function get_default_pattern_defaults() { 126 return array( 127 'maxWidth' => 600, 128 'borderRadius' => 6, 129 'maxHeight' => 90, 130 'overlayColor' => 'rgba(0, 0, 0, 0.1)', 131 'backdropBlur' => 8, 132 'showIconClose' => true, 133 'showFooterClose' => true, 134 'footerCloseText' => 'Close →', 135 ); 136 } 137 138 /** 139 * Get default TLDR defaults 140 * 141 * @return array Default TLDR defaults 142 */ 143 private function get_default_tldr_defaults() { 144 return array( 145 'inheritModalAppearance' => true, 146 'inheritOverlay' => true, 147 'inheritCloseButtons' => true, 148 'maxWidth' => 600, 149 'borderRadius' => 6, 150 'maxHeight' => 90, 151 'overlayColor' => 'rgba(0, 0, 0, 0.1)', 152 'backdropBlur' => 8, 153 'showIconClose' => true, 154 'showFooterClose' => true, 155 'footerCloseText' => 'Close →', 156 'loadingText' => 'Generating TLDR', 157 'titleText' => 'TLDR', 158 ); 159 } 160 161 /** 162 * Get default gallery defaults 163 * 164 * @return array Default gallery defaults 165 */ 166 private function get_default_gallery_defaults() { 167 return array( 168 'inheritModalAppearance' => true, 169 'inheritOverlay' => true, 170 'inheritCloseButtons' => true, 171 'maxWidth' => 600, 172 'borderRadius' => 6, 173 'maxHeight' => 90, 174 'overlayColor' => 'rgba(0, 0, 0, 0.1)', 175 'backdropBlur' => 8, 176 'showIconClose' => true, 177 'showFooterClose' => true, 178 'footerCloseText' => 'Close →', 179 'imageNavigation' => 'both', 180 'showCaptions' => true, 181 'crossfadeTransition' => true, 182 'transitionDuration' => 500, 183 'preloadAdjacentImages' => true, 184 'showNavOnHover' => true, 185 ); 186 } 187 188 /** 189 * Sanitize rgba color value 190 * 191 * @param string $value Color value to sanitize. 192 * @return string Sanitized color value or default. 193 */ 194 private function sanitize_rgba_color( $value ) { 195 if ( ! is_string( $value ) ) { 196 return 'rgba(0, 0, 0, 0.1)'; 197 } 198 199 // Validate rgba format: rgba(r, g, b, a) where r,g,b are 0-255 and a is 0-1. 200 $pattern = '/^rgba\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(0|1|0?\.\d+)\s*\)$/'; 201 if ( preg_match( $pattern, $value ) ) { 202 return $value; 203 } 204 205 return 'rgba(0, 0, 0, 0.1)'; 206 } 207 208 /** 209 * Sanitize number with range validation 210 * 211 * @param mixed $value Value to sanitize. 212 * @param int $min Minimum value. 213 * @param int $max Maximum value. 214 * @param int $default Default value if invalid. 215 * @return int Sanitized number. 216 */ 217 private function sanitize_number_range( $value, $min, $max, $default ) { 218 $value = absint( $value ); 219 if ( $value < $min || $value > $max ) { 220 return $default; 221 } 222 return $value; 223 } 224 225 /** 226 * Sanitize pattern defaults 227 * 228 * @param mixed $value Value to sanitize. 229 * @return array Sanitized pattern defaults. 230 */ 231 public function sanitize_pattern_defaults( $value ) { 232 if ( ! is_array( $value ) ) { 233 return $this->get_default_pattern_defaults(); 234 } 235 236 $defaults = $this->get_default_pattern_defaults(); 237 $sanitized = array(); 238 239 // Sanitize maxWidth (100-5000). 240 $sanitized['maxWidth'] = isset( $value['maxWidth'] ) ? $this->sanitize_number_range( $value['maxWidth'], 100, 5000, $defaults['maxWidth'] ) : $defaults['maxWidth']; 241 242 // Sanitize borderRadius (0-50). 243 $sanitized['borderRadius'] = isset( $value['borderRadius'] ) ? $this->sanitize_number_range( $value['borderRadius'], 0, 50, $defaults['borderRadius'] ) : $defaults['borderRadius']; 244 245 // Sanitize maxHeight (50-100). 246 $sanitized['maxHeight'] = isset( $value['maxHeight'] ) ? $this->sanitize_number_range( $value['maxHeight'], 50, 100, $defaults['maxHeight'] ) : $defaults['maxHeight']; 247 248 // Sanitize overlayColor. 249 $sanitized['overlayColor'] = isset( $value['overlayColor'] ) ? $this->sanitize_rgba_color( $value['overlayColor'] ) : $defaults['overlayColor']; 250 251 // Sanitize backdropBlur (0-20). 252 $sanitized['backdropBlur'] = isset( $value['backdropBlur'] ) ? $this->sanitize_number_range( $value['backdropBlur'], 0, 20, $defaults['backdropBlur'] ) : $defaults['backdropBlur']; 253 254 // Sanitize booleans. 255 // Note: Unchecked checkboxes don't appear in POST data, so we use array_key_exists to detect if they were present. 256 // If the key exists, use the value; if not, it means unchecked, so set to false. 257 $sanitized['showIconClose'] = array_key_exists( 'showIconClose', $value ) ? (bool) $value['showIconClose'] : false; 258 $sanitized['showFooterClose'] = array_key_exists( 'showFooterClose', $value ) ? (bool) $value['showFooterClose'] : false; 259 260 // Sanitize footerCloseText. 261 $sanitized['footerCloseText'] = isset( $value['footerCloseText'] ) ? sanitize_text_field( wp_unslash( $value['footerCloseText'] ) ) : $defaults['footerCloseText']; 262 263 return $sanitized; 264 } 265 266 /** 267 * Sanitize TLDR defaults 268 * 269 * @param mixed $value Value to sanitize. 270 * @return array Sanitized TLDR defaults. 271 */ 272 public function sanitize_tldr_defaults( $value ) { 273 if ( ! is_array( $value ) ) { 274 return $this->get_default_tldr_defaults(); 275 } 276 277 $defaults = $this->get_default_tldr_defaults(); 278 $sanitized = array(); 279 280 // Sanitize inheritance flags. 281 $sanitized['inheritModalAppearance'] = isset( $value['inheritModalAppearance'] ) ? (bool) $value['inheritModalAppearance'] : $defaults['inheritModalAppearance']; 282 $sanitized['inheritOverlay'] = isset( $value['inheritOverlay'] ) ? (bool) $value['inheritOverlay'] : $defaults['inheritOverlay']; 283 $sanitized['inheritCloseButtons'] = isset( $value['inheritCloseButtons'] ) ? (bool) $value['inheritCloseButtons'] : $defaults['inheritCloseButtons']; 284 285 // Only sanitize modal appearance if not inheriting. 286 if ( ! $sanitized['inheritModalAppearance'] ) { 287 $sanitized['maxWidth'] = isset( $value['maxWidth'] ) ? $this->sanitize_number_range( $value['maxWidth'], 100, 5000, $defaults['maxWidth'] ) : $defaults['maxWidth']; 288 $sanitized['borderRadius'] = isset( $value['borderRadius'] ) ? $this->sanitize_number_range( $value['borderRadius'], 0, 50, $defaults['borderRadius'] ) : $defaults['borderRadius']; 289 $sanitized['maxHeight'] = isset( $value['maxHeight'] ) ? $this->sanitize_number_range( $value['maxHeight'], 50, 100, $defaults['maxHeight'] ) : $defaults['maxHeight']; 290 } else { 291 $sanitized['maxWidth'] = $defaults['maxWidth']; 292 $sanitized['borderRadius'] = $defaults['borderRadius']; 293 $sanitized['maxHeight'] = $defaults['maxHeight']; 294 } 295 296 // Only sanitize overlay if not inheriting. 297 if ( ! $sanitized['inheritOverlay'] ) { 298 $sanitized['overlayColor'] = isset( $value['overlayColor'] ) ? $this->sanitize_rgba_color( $value['overlayColor'] ) : $defaults['overlayColor']; 299 $sanitized['backdropBlur'] = isset( $value['backdropBlur'] ) ? $this->sanitize_number_range( $value['backdropBlur'], 0, 20, $defaults['backdropBlur'] ) : $defaults['backdropBlur']; 300 } else { 301 $sanitized['overlayColor'] = $defaults['overlayColor']; 302 $sanitized['backdropBlur'] = $defaults['backdropBlur']; 303 } 304 305 // Only sanitize close buttons if not inheriting. 306 if ( ! $sanitized['inheritCloseButtons'] ) { 307 // Note: Unchecked checkboxes don't appear in POST data, so we use array_key_exists to detect if they were present. 308 // If the key exists, use the value; if not, it means unchecked, so set to false. 309 $sanitized['showIconClose'] = array_key_exists( 'showIconClose', $value ) ? (bool) $value['showIconClose'] : false; 310 $sanitized['showFooterClose'] = array_key_exists( 'showFooterClose', $value ) ? (bool) $value['showFooterClose'] : false; 311 $sanitized['footerCloseText'] = isset( $value['footerCloseText'] ) ? sanitize_text_field( wp_unslash( $value['footerCloseText'] ) ) : $defaults['footerCloseText']; 312 } else { 313 $sanitized['showIconClose'] = $defaults['showIconClose']; 314 $sanitized['showFooterClose'] = $defaults['showFooterClose']; 315 $sanitized['footerCloseText'] = $defaults['footerCloseText']; 316 } 317 318 // TLDR-specific settings. 319 $sanitized['loadingText'] = isset( $value['loadingText'] ) ? sanitize_text_field( wp_unslash( $value['loadingText'] ) ) : $defaults['loadingText']; 320 $sanitized['titleText'] = isset( $value['titleText'] ) ? sanitize_text_field( wp_unslash( $value['titleText'] ) ) : $defaults['titleText']; 321 322 return $sanitized; 323 } 324 325 /** 326 * Sanitize gallery defaults 327 * 328 * @param mixed $value Value to sanitize. 329 * @return array Sanitized gallery defaults. 330 */ 331 public function sanitize_gallery_defaults( $value ) { 332 if ( ! is_array( $value ) ) { 333 return $this->get_default_gallery_defaults(); 334 } 335 336 $defaults = $this->get_default_gallery_defaults(); 337 $sanitized = array(); 338 339 // Sanitize inheritance flags. 340 $sanitized['inheritModalAppearance'] = isset( $value['inheritModalAppearance'] ) ? (bool) $value['inheritModalAppearance'] : $defaults['inheritModalAppearance']; 341 $sanitized['inheritOverlay'] = isset( $value['inheritOverlay'] ) ? (bool) $value['inheritOverlay'] : $defaults['inheritOverlay']; 342 $sanitized['inheritCloseButtons'] = isset( $value['inheritCloseButtons'] ) ? (bool) $value['inheritCloseButtons'] : $defaults['inheritCloseButtons']; 343 344 // Only sanitize modal appearance if not inheriting. 345 if ( ! $sanitized['inheritModalAppearance'] ) { 346 $sanitized['maxWidth'] = isset( $value['maxWidth'] ) ? $this->sanitize_number_range( $value['maxWidth'], 100, 5000, $defaults['maxWidth'] ) : $defaults['maxWidth']; 347 $sanitized['borderRadius'] = isset( $value['borderRadius'] ) ? $this->sanitize_number_range( $value['borderRadius'], 0, 50, $defaults['borderRadius'] ) : $defaults['borderRadius']; 348 $sanitized['maxHeight'] = isset( $value['maxHeight'] ) ? $this->sanitize_number_range( $value['maxHeight'], 50, 100, $defaults['maxHeight'] ) : $defaults['maxHeight']; 349 } else { 350 $sanitized['maxWidth'] = $defaults['maxWidth']; 351 $sanitized['borderRadius'] = $defaults['borderRadius']; 352 $sanitized['maxHeight'] = $defaults['maxHeight']; 353 } 354 355 // Only sanitize overlay if not inheriting. 356 if ( ! $sanitized['inheritOverlay'] ) { 357 $sanitized['overlayColor'] = isset( $value['overlayColor'] ) ? $this->sanitize_rgba_color( $value['overlayColor'] ) : $defaults['overlayColor']; 358 $sanitized['backdropBlur'] = isset( $value['backdropBlur'] ) ? $this->sanitize_number_range( $value['backdropBlur'], 0, 20, $defaults['backdropBlur'] ) : $defaults['backdropBlur']; 359 } else { 360 $sanitized['overlayColor'] = $defaults['overlayColor']; 361 $sanitized['backdropBlur'] = $defaults['backdropBlur']; 362 } 363 364 // Only sanitize close buttons if not inheriting. 365 if ( ! $sanitized['inheritCloseButtons'] ) { 366 // Note: Unchecked checkboxes don't appear in POST data, so we use array_key_exists to detect if they were present. 367 // If the key exists, use the value; if not, it means unchecked, so set to false. 368 $sanitized['showIconClose'] = array_key_exists( 'showIconClose', $value ) ? (bool) $value['showIconClose'] : false; 369 $sanitized['showFooterClose'] = array_key_exists( 'showFooterClose', $value ) ? (bool) $value['showFooterClose'] : false; 370 $sanitized['footerCloseText'] = isset( $value['footerCloseText'] ) ? sanitize_text_field( wp_unslash( $value['footerCloseText'] ) ) : $defaults['footerCloseText']; 371 } else { 372 $sanitized['showIconClose'] = $defaults['showIconClose']; 373 $sanitized['showFooterClose'] = $defaults['showFooterClose']; 374 $sanitized['footerCloseText'] = $defaults['footerCloseText']; 375 } 376 377 // Gallery-specific settings. 378 $allowed_navigation = array( 'image', 'footer', 'both' ); 379 $sanitized['imageNavigation'] = isset( $value['imageNavigation'] ) && in_array( $value['imageNavigation'], $allowed_navigation, true ) ? $value['imageNavigation'] : $defaults['imageNavigation']; 380 381 // Note: Unchecked checkboxes don't appear in POST data, so we use array_key_exists to detect if they were present. 382 // If the key exists, use the value; if not, it means unchecked, so set to false. 383 $sanitized['showCaptions'] = array_key_exists( 'showCaptions', $value ) ? (bool) $value['showCaptions'] : false; 384 $sanitized['crossfadeTransition'] = array_key_exists( 'crossfadeTransition', $value ) ? (bool) $value['crossfadeTransition'] : false; 385 $sanitized['transitionDuration'] = isset( $value['transitionDuration'] ) ? $this->sanitize_number_range( $value['transitionDuration'], 0, 2000, $defaults['transitionDuration'] ) : $defaults['transitionDuration']; 386 $sanitized['preloadAdjacentImages'] = array_key_exists( 'preloadAdjacentImages', $value ) ? (bool) $value['preloadAdjacentImages'] : false; 387 $sanitized['showNavOnHover'] = array_key_exists( 'showNavOnHover', $value ) ? (bool) $value['showNavOnHover'] : false; 388 389 return $sanitized; 87 390 } 88 391 … … 240 543 <?php esc_html_e( 'AI TLDR Settings', 'synced-pattern-popups' ); ?> 241 544 </h2> 242 545 243 546 <?php if ( ! $ai_available['plugin_active'] ) : ?> 244 547 <div class="notice notice-warning inline" style="margin: 0 0 20px 0;"> … … 257 560 <form method="post" action=""> 258 561 <?php wp_nonce_field( 'sppopups_save_tldr_settings', 'sppopups_tldr_settings_nonce' ); ?> 259 562 <input type="hidden" name="sppopups_current_tab" id="sppopups-tldr-current-tab-alt" value="tldr" /> 563 260 564 <table class="form-table" role="presentation"> 261 565 <tbody> … … 322 626 </tbody> 323 627 </table> 324 628 325 629 <?php submit_button( __( 'Save TLDR Settings', 'synced-pattern-popups' ), 'primary', 'save_tldr_settings', false ); ?> 326 630 </form> … … 338 642 <div class="sppopups-tab-content-inner"> 339 643 <h2><?php esc_html_e( 'AI TLDR Settings', 'synced-pattern-popups' ); ?></h2> 340 644 341 645 <?php if ( ! $all_requirements_met ) : ?> 342 646 <p class="description"> … … 351 655 <form method="post" action=""> 352 656 <?php wp_nonce_field( 'sppopups_save_tldr_settings', 'sppopups_tldr_settings_nonce' ); ?> 353 657 <input type="hidden" name="sppopups_current_tab" id="sppopups-tldr-current-tab" value="tldr" /> 658 354 659 <table class="form-table" role="presentation"> 355 660 <tbody> … … 416 721 </tbody> 417 722 </table> 418 723 419 724 <?php submit_button( __( 'Save TLDR Settings', 'synced-pattern-popups' ), 'primary', 'save_tldr_settings', false ); ?> 420 725 </form> … … 557 862 return $hours * HOUR_IN_SECONDS; 558 863 } 864 865 /** 866 * Render defaults section for admin page 867 */ 868 public function render_defaults_section() { 869 ?> 870 <div class="sppopups-tab-content-inner"> 871 <h2><?php esc_html_e( 'Popup Defaults', 'synced-pattern-popups' ); ?></h2> 872 <p class="description"> 873 <?php esc_html_e( 'Configure default appearance and behavior settings for all popup types. These settings will be used unless overridden by individual popups.', 'synced-pattern-popups' ); ?> 874 </p> 875 876 <form method="post" action=""> 877 <?php wp_nonce_field( 'sppopups_save_defaults_settings', 'sppopups_defaults_settings_nonce' ); ?> 878 <input type="hidden" name="sppopups_current_tab" id="sppopups-defaults-current-tab" value="defaults" /> 879 880 <?php $this->render_pattern_defaults_section(); ?> 881 <?php $this->render_tldr_defaults_section(); ?> 882 <?php $this->render_gallery_defaults_section(); ?> 883 884 <?php submit_button( __( 'Save Defaults', 'synced-pattern-popups' ), 'primary', 'save_defaults_settings', false ); ?> 885 </form> 886 </div> 887 <?php 888 } 889 890 /** 891 * Render pattern defaults section 892 */ 893 private function render_pattern_defaults_section() { 894 $defaults = $this->get_default_pattern_defaults(); 895 $saved = get_option( 'sppopups_defaults_pattern', array() ); 896 $values = wp_parse_args( $saved, $defaults ); 897 ?> 898 <div class="sppopups-defaults-accordion" style="margin-top: 30px;"> 899 <div class="sppopups-defaults-accordion-header"> 900 <button type="button" class="sppopups-defaults-accordion-trigger" aria-expanded="false" aria-controls="sppopups-defaults-pattern-content"> 901 <span class="sppopups-defaults-accordion-title"><?php esc_html_e( 'Pattern Popups Defaults', 'synced-pattern-popups' ); ?></span> 902 <span class="sppopups-defaults-accordion-icon" aria-hidden="true"></span> 903 </button> 904 </div> 905 <div id="sppopups-defaults-pattern-content" class="sppopups-defaults-accordion-content" style="display: none; padding: 24px; background: #f6f7f7; border: 1px solid #dcdcde; border-top: none; border-radius: 0 0 4px 4px;"> 906 907 <table class="form-table" role="presentation"> 908 <tbody> 909 <tr> 910 <th scope="row"> 911 <label for="pattern_max_width"> 912 <?php esc_html_e( 'Default Width', 'synced-pattern-popups' ); ?> 913 </label> 914 </th> 915 <td> 916 <input type="number" name="sppopups_defaults_pattern[maxWidth]" id="pattern_max_width" value="<?php echo esc_attr( $values['maxWidth'] ); ?>" min="100" max="5000" step="1" style="width: 100px;" /> 917 <span style="margin-left: 8px;"><?php esc_html_e( 'px', 'synced-pattern-popups' ); ?></span> 918 <p class="description"> 919 <?php esc_html_e( 'Default modal width in pixels (100-5000).', 'synced-pattern-popups' ); ?> 920 </p> 921 </td> 922 </tr> 923 <tr> 924 <th scope="row"> 925 <label for="pattern_border_radius"> 926 <?php esc_html_e( 'Border Radius', 'synced-pattern-popups' ); ?> 927 </label> 928 </th> 929 <td> 930 <input type="number" name="sppopups_defaults_pattern[borderRadius]" id="pattern_border_radius" value="<?php echo esc_attr( $values['borderRadius'] ); ?>" min="0" max="50" step="1" style="width: 100px;" /> 931 <span style="margin-left: 8px;"><?php esc_html_e( 'px', 'synced-pattern-popups' ); ?></span> 932 <p class="description"> 933 <?php esc_html_e( 'Modal border radius in pixels (0-50).', 'synced-pattern-popups' ); ?> 934 </p> 935 </td> 936 </tr> 937 <tr> 938 <th scope="row"> 939 <label for="pattern_max_height"> 940 <?php esc_html_e( 'Max Height', 'synced-pattern-popups' ); ?> 941 </label> 942 </th> 943 <td> 944 <input type="number" name="sppopups_defaults_pattern[maxHeight]" id="pattern_max_height" value="<?php echo esc_attr( $values['maxHeight'] ); ?>" min="50" max="100" step="1" style="width: 100px;" /> 945 <span style="margin-left: 8px;"><?php esc_html_e( '%', 'synced-pattern-popups' ); ?></span> 946 <p class="description"> 947 <?php esc_html_e( 'Maximum modal height as percentage of viewport (50-100).', 'synced-pattern-popups' ); ?> 948 </p> 949 </td> 950 </tr> 951 <tr> 952 <th scope="row"> 953 <label for="pattern_overlay_color"> 954 <?php esc_html_e( 'Overlay Color', 'synced-pattern-popups' ); ?> 955 </label> 956 </th> 957 <td> 958 <input type="text" name="sppopups_defaults_pattern[overlayColor]" id="pattern_overlay_color" value="<?php echo esc_attr( $values['overlayColor'] ); ?>" class="regular-text" placeholder="rgba(0, 0, 0, 0.1)" /> 959 <p class="description"> 960 <?php esc_html_e( 'Overlay background color in rgba format (e.g., rgba(0, 0, 0, 0.1)).', 'synced-pattern-popups' ); ?> 961 </p> 962 </td> 963 </tr> 964 <tr> 965 <th scope="row"> 966 <label for="pattern_backdrop_blur"> 967 <?php esc_html_e( 'Backdrop Blur', 'synced-pattern-popups' ); ?> 968 </label> 969 </th> 970 <td> 971 <input type="number" name="sppopups_defaults_pattern[backdropBlur]" id="pattern_backdrop_blur" value="<?php echo esc_attr( $values['backdropBlur'] ); ?>" min="0" max="20" step="1" style="width: 100px;" /> 972 <span style="margin-left: 8px;"><?php esc_html_e( 'px', 'synced-pattern-popups' ); ?></span> 973 <p class="description"> 974 <?php esc_html_e( 'Backdrop blur amount in pixels (0-20).', 'synced-pattern-popups' ); ?> 975 </p> 976 </td> 977 </tr> 978 <tr> 979 <th scope="row"> 980 <?php esc_html_e( 'Close Buttons', 'synced-pattern-popups' ); ?> 981 </th> 982 <td> 983 <fieldset> 984 <label> 985 <input type="checkbox" name="sppopups_defaults_pattern[showIconClose]" value="1" <?php checked( $values['showIconClose'], true ); ?> /> 986 <?php esc_html_e( 'Show icon close button', 'synced-pattern-popups' ); ?> 987 </label> 988 <br /> 989 <label> 990 <input type="checkbox" name="sppopups_defaults_pattern[showFooterClose]" value="1" <?php checked( $values['showFooterClose'], true ); ?> /> 991 <?php esc_html_e( 'Show footer close button', 'synced-pattern-popups' ); ?> 992 </label> 993 </fieldset> 994 </td> 995 </tr> 996 <tr> 997 <th scope="row"> 998 <label for="pattern_footer_close_text"> 999 <?php esc_html_e( 'Footer Button Text', 'synced-pattern-popups' ); ?> 1000 </label> 1001 </th> 1002 <td> 1003 <input type="text" name="sppopups_defaults_pattern[footerCloseText]" id="pattern_footer_close_text" value="<?php echo esc_attr( $values['footerCloseText'] ); ?>" class="regular-text" /> 1004 <p class="description"> 1005 <?php esc_html_e( 'Text displayed on the footer close button.', 'synced-pattern-popups' ); ?> 1006 </p> 1007 </td> 1008 </tr> 1009 </tbody> 1010 </table> 1011 </div> 1012 </div> 1013 <?php 1014 } 1015 1016 /** 1017 * Render TLDR defaults section 1018 */ 1019 private function render_tldr_defaults_section() { 1020 $defaults = $this->get_default_tldr_defaults(); 1021 $saved = get_option( 'sppopups_defaults_tldr', array() ); 1022 $values = wp_parse_args( $saved, $defaults ); 1023 $pattern_defaults = self::get_pattern_defaults(); 1024 ?> 1025 <div class="sppopups-defaults-accordion" style="margin-top: 30px;"> 1026 <div class="sppopups-defaults-accordion-header"> 1027 <button type="button" class="sppopups-defaults-accordion-trigger" aria-expanded="false" aria-controls="sppopups-defaults-tldr-content"> 1028 <span class="sppopups-defaults-accordion-title"><?php esc_html_e( 'TLDR Popups Defaults', 'synced-pattern-popups' ); ?></span> 1029 <span class="sppopups-defaults-accordion-icon" aria-hidden="true"></span> 1030 </button> 1031 </div> 1032 <div id="sppopups-defaults-tldr-content" class="sppopups-defaults-accordion-content" style="display: none; padding: 24px; background: #f6f7f7; border: 1px solid #dcdcde; border-top: none; border-radius: 0 0 4px 4px;"> 1033 1034 <table class="form-table" role="presentation"> 1035 <tbody> 1036 <tr> 1037 <th scope="row"> 1038 <?php esc_html_e( 'Modal Appearance', 'synced-pattern-popups' ); ?> 1039 </th> 1040 <td> 1041 <fieldset> 1042 <label> 1043 <input type="radio" name="sppopups_defaults_tldr[inheritModalAppearance]" value="1" <?php checked( $values['inheritModalAppearance'], true ); ?> class="tldr-inherit-modal-appearance" /> 1044 <?php esc_html_e( 'Inherit from Pattern Modal', 'synced-pattern-popups' ); ?> 1045 </label> 1046 <br /> 1047 <label> 1048 <input type="radio" name="sppopups_defaults_tldr[inheritModalAppearance]" value="0" <?php checked( $values['inheritModalAppearance'], false ); ?> class="tldr-inherit-modal-appearance" /> 1049 <?php esc_html_e( 'Custom', 'synced-pattern-popups' ); ?> 1050 </label> 1051 </fieldset> 1052 <div id="tldr-modal-appearance-custom" style="margin-top: 12px; <?php echo $values['inheritModalAppearance'] ? 'display: none;' : ''; ?>"> 1053 <table class="form-table" role="presentation" style="margin-top: 0;"> 1054 <tbody> 1055 <tr> 1056 <th scope="row"> 1057 <label for="tldr_max_width"> 1058 <?php esc_html_e( 'Default Width', 'synced-pattern-popups' ); ?> 1059 </label> 1060 </th> 1061 <td> 1062 <input type="number" name="sppopups_defaults_tldr[maxWidth]" id="tldr_max_width" value="<?php echo esc_attr( $values['maxWidth'] ); ?>" min="100" max="5000" step="1" style="width: 100px;" /> 1063 <span style="margin-left: 8px;"><?php esc_html_e( 'px', 'synced-pattern-popups' ); ?></span> 1064 </td> 1065 </tr> 1066 <tr> 1067 <th scope="row"> 1068 <label for="tldr_border_radius"> 1069 <?php esc_html_e( 'Border Radius', 'synced-pattern-popups' ); ?> 1070 </label> 1071 </th> 1072 <td> 1073 <input type="number" name="sppopups_defaults_tldr[borderRadius]" id="tldr_border_radius" value="<?php echo esc_attr( $values['borderRadius'] ); ?>" min="0" max="50" step="1" style="width: 100px;" /> 1074 <span style="margin-left: 8px;"><?php esc_html_e( 'px', 'synced-pattern-popups' ); ?></span> 1075 </td> 1076 </tr> 1077 <tr> 1078 <th scope="row"> 1079 <label for="tldr_max_height"> 1080 <?php esc_html_e( 'Max Height', 'synced-pattern-popups' ); ?> 1081 </label> 1082 </th> 1083 <td> 1084 <input type="number" name="sppopups_defaults_tldr[maxHeight]" id="tldr_max_height" value="<?php echo esc_attr( $values['maxHeight'] ); ?>" min="50" max="100" step="1" style="width: 100px;" /> 1085 <span style="margin-left: 8px;"><?php esc_html_e( '%', 'synced-pattern-popups' ); ?></span> 1086 </td> 1087 </tr> 1088 </tbody> 1089 </table> 1090 </div> 1091 </td> 1092 </tr> 1093 <tr> 1094 <th scope="row"> 1095 <?php esc_html_e( 'Overlay', 'synced-pattern-popups' ); ?> 1096 </th> 1097 <td> 1098 <fieldset> 1099 <label> 1100 <input type="radio" name="sppopups_defaults_tldr[inheritOverlay]" value="1" <?php checked( $values['inheritOverlay'], true ); ?> class="tldr-inherit-overlay" /> 1101 <?php esc_html_e( 'Inherit from Pattern Modal', 'synced-pattern-popups' ); ?> 1102 </label> 1103 <br /> 1104 <label> 1105 <input type="radio" name="sppopups_defaults_tldr[inheritOverlay]" value="0" <?php checked( $values['inheritOverlay'], false ); ?> class="tldr-inherit-overlay" /> 1106 <?php esc_html_e( 'Custom', 'synced-pattern-popups' ); ?> 1107 </label> 1108 </fieldset> 1109 <div id="tldr-overlay-custom" style="margin-top: 12px; <?php echo $values['inheritOverlay'] ? 'display: none;' : ''; ?>"> 1110 <table class="form-table" role="presentation" style="margin-top: 0;"> 1111 <tbody> 1112 <tr> 1113 <th scope="row"> 1114 <label for="tldr_overlay_color"> 1115 <?php esc_html_e( 'Overlay Color', 'synced-pattern-popups' ); ?> 1116 </label> 1117 </th> 1118 <td> 1119 <input type="text" name="sppopups_defaults_tldr[overlayColor]" id="tldr_overlay_color" value="<?php echo esc_attr( $values['overlayColor'] ); ?>" class="regular-text" placeholder="rgba(0, 0, 0, 0.1)" /> 1120 </td> 1121 </tr> 1122 <tr> 1123 <th scope="row"> 1124 <label for="tldr_backdrop_blur"> 1125 <?php esc_html_e( 'Backdrop Blur', 'synced-pattern-popups' ); ?> 1126 </label> 1127 </th> 1128 <td> 1129 <input type="number" name="sppopups_defaults_tldr[backdropBlur]" id="tldr_backdrop_blur" value="<?php echo esc_attr( $values['backdropBlur'] ); ?>" min="0" max="20" step="1" style="width: 100px;" /> 1130 <span style="margin-left: 8px;"><?php esc_html_e( 'px', 'synced-pattern-popups' ); ?></span> 1131 </td> 1132 </tr> 1133 </tbody> 1134 </table> 1135 </div> 1136 </td> 1137 </tr> 1138 <tr> 1139 <th scope="row"> 1140 <?php esc_html_e( 'Close Buttons', 'synced-pattern-popups' ); ?> 1141 </th> 1142 <td> 1143 <fieldset> 1144 <label> 1145 <input type="radio" name="sppopups_defaults_tldr[inheritCloseButtons]" value="1" <?php checked( $values['inheritCloseButtons'], true ); ?> class="tldr-inherit-close-buttons" /> 1146 <?php esc_html_e( 'Inherit from Pattern Modal', 'synced-pattern-popups' ); ?> 1147 </label> 1148 <br /> 1149 <label> 1150 <input type="radio" name="sppopups_defaults_tldr[inheritCloseButtons]" value="0" <?php checked( $values['inheritCloseButtons'], false ); ?> class="tldr-inherit-close-buttons" /> 1151 <?php esc_html_e( 'Custom', 'synced-pattern-popups' ); ?> 1152 </label> 1153 </fieldset> 1154 <div id="tldr-close-buttons-custom" style="margin-top: 12px; <?php echo $values['inheritCloseButtons'] ? 'display: none;' : ''; ?>"> 1155 <table class="form-table" role="presentation" style="margin-top: 0;"> 1156 <tbody> 1157 <tr> 1158 <th scope="row"> 1159 <?php esc_html_e( 'Options', 'synced-pattern-popups' ); ?> 1160 </th> 1161 <td> 1162 <fieldset> 1163 <label> 1164 <input type="checkbox" name="sppopups_defaults_tldr[showIconClose]" value="1" <?php checked( $values['showIconClose'], true ); ?> /> 1165 <?php esc_html_e( 'Show icon close button', 'synced-pattern-popups' ); ?> 1166 </label> 1167 <br /> 1168 <label> 1169 <input type="checkbox" name="sppopups_defaults_tldr[showFooterClose]" value="1" <?php checked( $values['showFooterClose'], true ); ?> /> 1170 <?php esc_html_e( 'Show footer close button', 'synced-pattern-popups' ); ?> 1171 </label> 1172 </fieldset> 1173 </td> 1174 </tr> 1175 <tr> 1176 <th scope="row"> 1177 <label for="tldr_footer_close_text"> 1178 <?php esc_html_e( 'Footer Button Text', 'synced-pattern-popups' ); ?> 1179 </label> 1180 </th> 1181 <td> 1182 <input type="text" name="sppopups_defaults_tldr[footerCloseText]" id="tldr_footer_close_text" value="<?php echo esc_attr( $values['footerCloseText'] ); ?>" class="regular-text" /> 1183 </td> 1184 </tr> 1185 </tbody> 1186 </table> 1187 </div> 1188 </td> 1189 </tr> 1190 <tr> 1191 <th scope="row"> 1192 <label for="tldr_loading_text"> 1193 <?php esc_html_e( 'Loading Text', 'synced-pattern-popups' ); ?> 1194 </label> 1195 </th> 1196 <td> 1197 <input type="text" name="sppopups_defaults_tldr[loadingText]" id="tldr_loading_text" value="<?php echo esc_attr( $values['loadingText'] ); ?>" class="regular-text" /> 1198 <p class="description"> 1199 <?php esc_html_e( 'Text displayed while generating TLDR summary.', 'synced-pattern-popups' ); ?> 1200 </p> 1201 </td> 1202 </tr> 1203 <tr> 1204 <th scope="row"> 1205 <label for="tldr_title_text"> 1206 <?php esc_html_e( 'Title Text', 'synced-pattern-popups' ); ?> 1207 </label> 1208 </th> 1209 <td> 1210 <input type="text" name="sppopups_defaults_tldr[titleText]" id="tldr_title_text" value="<?php echo esc_attr( $values['titleText'] ); ?>" class="regular-text" /> 1211 <p class="description"> 1212 <?php esc_html_e( 'Title displayed in TLDR modal header.', 'synced-pattern-popups' ); ?> 1213 </p> 1214 </td> 1215 </tr> 1216 </tbody> 1217 </table> 1218 </div> 1219 </div> 1220 <?php 1221 } 1222 1223 /** 1224 * Render gallery defaults section 1225 */ 1226 private function render_gallery_defaults_section() { 1227 $defaults = $this->get_default_gallery_defaults(); 1228 $saved = get_option( 'sppopups_defaults_gallery', array() ); 1229 $values = wp_parse_args( $saved, $defaults ); 1230 $pattern_defaults = self::get_pattern_defaults(); 1231 ?> 1232 <div class="sppopups-defaults-accordion" style="margin-top: 30px;"> 1233 <div class="sppopups-defaults-accordion-header"> 1234 <button type="button" class="sppopups-defaults-accordion-trigger" aria-expanded="false" aria-controls="sppopups-defaults-gallery-content"> 1235 <span class="sppopups-defaults-accordion-title"><?php esc_html_e( 'Gallery Popups Defaults', 'synced-pattern-popups' ); ?></span> 1236 <span class="sppopups-defaults-accordion-icon" aria-hidden="true"></span> 1237 </button> 1238 </div> 1239 <div id="sppopups-defaults-gallery-content" class="sppopups-defaults-accordion-content" style="display: none; padding: 24px; background: #f6f7f7; border: 1px solid #dcdcde; border-top: none; border-radius: 0 0 4px 4px;"> 1240 1241 <table class="form-table" role="presentation"> 1242 <tbody> 1243 <tr> 1244 <th scope="row"> 1245 <?php esc_html_e( 'Modal Appearance', 'synced-pattern-popups' ); ?> 1246 </th> 1247 <td> 1248 <fieldset> 1249 <label> 1250 <input type="radio" name="sppopups_defaults_gallery[inheritModalAppearance]" value="1" <?php checked( $values['inheritModalAppearance'], true ); ?> class="gallery-inherit-modal-appearance" /> 1251 <?php esc_html_e( 'Inherit from Pattern Modal', 'synced-pattern-popups' ); ?> 1252 </label> 1253 <br /> 1254 <label> 1255 <input type="radio" name="sppopups_defaults_gallery[inheritModalAppearance]" value="0" <?php checked( $values['inheritModalAppearance'], false ); ?> class="gallery-inherit-modal-appearance" /> 1256 <?php esc_html_e( 'Custom', 'synced-pattern-popups' ); ?> 1257 </label> 1258 </fieldset> 1259 <div id="gallery-modal-appearance-custom" style="margin-top: 12px; <?php echo $values['inheritModalAppearance'] ? 'display: none;' : ''; ?>"> 1260 <table class="form-table" role="presentation" style="margin-top: 0;"> 1261 <tbody> 1262 <tr> 1263 <th scope="row"> 1264 <label for="gallery_max_width"> 1265 <?php esc_html_e( 'Default Width', 'synced-pattern-popups' ); ?> 1266 </label> 1267 </th> 1268 <td> 1269 <input type="number" name="sppopups_defaults_gallery[maxWidth]" id="gallery_max_width" value="<?php echo esc_attr( $values['maxWidth'] ); ?>" min="100" max="5000" step="1" style="width: 100px;" /> 1270 <span style="margin-left: 8px;"><?php esc_html_e( 'px', 'synced-pattern-popups' ); ?></span> 1271 </td> 1272 </tr> 1273 <tr> 1274 <th scope="row"> 1275 <label for="gallery_border_radius"> 1276 <?php esc_html_e( 'Border Radius', 'synced-pattern-popups' ); ?> 1277 </label> 1278 </th> 1279 <td> 1280 <input type="number" name="sppopups_defaults_gallery[borderRadius]" id="gallery_border_radius" value="<?php echo esc_attr( $values['borderRadius'] ); ?>" min="0" max="50" step="1" style="width: 100px;" /> 1281 <span style="margin-left: 8px;"><?php esc_html_e( 'px', 'synced-pattern-popups' ); ?></span> 1282 </td> 1283 </tr> 1284 <tr> 1285 <th scope="row"> 1286 <label for="gallery_max_height"> 1287 <?php esc_html_e( 'Max Height', 'synced-pattern-popups' ); ?> 1288 </label> 1289 </th> 1290 <td> 1291 <input type="number" name="sppopups_defaults_gallery[maxHeight]" id="gallery_max_height" value="<?php echo esc_attr( $values['maxHeight'] ); ?>" min="50" max="100" step="1" style="width: 100px;" /> 1292 <span style="margin-left: 8px;"><?php esc_html_e( '%', 'synced-pattern-popups' ); ?></span> 1293 </td> 1294 </tr> 1295 </tbody> 1296 </table> 1297 </div> 1298 </td> 1299 </tr> 1300 <tr> 1301 <th scope="row"> 1302 <?php esc_html_e( 'Overlay', 'synced-pattern-popups' ); ?> 1303 </th> 1304 <td> 1305 <fieldset> 1306 <label> 1307 <input type="radio" name="sppopups_defaults_gallery[inheritOverlay]" value="1" <?php checked( $values['inheritOverlay'], true ); ?> class="gallery-inherit-overlay" /> 1308 <?php esc_html_e( 'Inherit from Pattern Modal', 'synced-pattern-popups' ); ?> 1309 </label> 1310 <br /> 1311 <label> 1312 <input type="radio" name="sppopups_defaults_gallery[inheritOverlay]" value="0" <?php checked( $values['inheritOverlay'], false ); ?> class="gallery-inherit-overlay" /> 1313 <?php esc_html_e( 'Custom', 'synced-pattern-popups' ); ?> 1314 </label> 1315 </fieldset> 1316 <div id="gallery-overlay-custom" style="margin-top: 12px; <?php echo $values['inheritOverlay'] ? 'display: none;' : ''; ?>"> 1317 <table class="form-table" role="presentation" style="margin-top: 0;"> 1318 <tbody> 1319 <tr> 1320 <th scope="row"> 1321 <label for="gallery_overlay_color"> 1322 <?php esc_html_e( 'Overlay Color', 'synced-pattern-popups' ); ?> 1323 </label> 1324 </th> 1325 <td> 1326 <input type="text" name="sppopups_defaults_gallery[overlayColor]" id="gallery_overlay_color" value="<?php echo esc_attr( $values['overlayColor'] ); ?>" class="regular-text" placeholder="rgba(0, 0, 0, 0.1)" /> 1327 </td> 1328 </tr> 1329 <tr> 1330 <th scope="row"> 1331 <label for="gallery_backdrop_blur"> 1332 <?php esc_html_e( 'Backdrop Blur', 'synced-pattern-popups' ); ?> 1333 </label> 1334 </th> 1335 <td> 1336 <input type="number" name="sppopups_defaults_gallery[backdropBlur]" id="gallery_backdrop_blur" value="<?php echo esc_attr( $values['backdropBlur'] ); ?>" min="0" max="20" step="1" style="width: 100px;" /> 1337 <span style="margin-left: 8px;"><?php esc_html_e( 'px', 'synced-pattern-popups' ); ?></span> 1338 </td> 1339 </tr> 1340 </tbody> 1341 </table> 1342 </div> 1343 </td> 1344 </tr> 1345 <tr> 1346 <th scope="row"> 1347 <?php esc_html_e( 'Close Buttons', 'synced-pattern-popups' ); ?> 1348 </th> 1349 <td> 1350 <fieldset> 1351 <label> 1352 <input type="radio" name="sppopups_defaults_gallery[inheritCloseButtons]" value="1" <?php checked( $values['inheritCloseButtons'], true ); ?> class="gallery-inherit-close-buttons" /> 1353 <?php esc_html_e( 'Inherit from Pattern Modal', 'synced-pattern-popups' ); ?> 1354 </label> 1355 <br /> 1356 <label> 1357 <input type="radio" name="sppopups_defaults_gallery[inheritCloseButtons]" value="0" <?php checked( $values['inheritCloseButtons'], false ); ?> class="gallery-inherit-close-buttons" /> 1358 <?php esc_html_e( 'Custom', 'synced-pattern-popups' ); ?> 1359 </label> 1360 </fieldset> 1361 <div id="gallery-close-buttons-custom" style="margin-top: 12px; <?php echo $values['inheritCloseButtons'] ? 'display: none;' : ''; ?>"> 1362 <table class="form-table" role="presentation" style="margin-top: 0;"> 1363 <tbody> 1364 <tr> 1365 <th scope="row"> 1366 <?php esc_html_e( 'Options', 'synced-pattern-popups' ); ?> 1367 </th> 1368 <td> 1369 <fieldset> 1370 <label> 1371 <input type="checkbox" name="sppopups_defaults_gallery[showIconClose]" value="1" <?php checked( $values['showIconClose'], true ); ?> /> 1372 <?php esc_html_e( 'Show icon close button', 'synced-pattern-popups' ); ?> 1373 </label> 1374 <br /> 1375 <label> 1376 <input type="checkbox" name="sppopups_defaults_gallery[showFooterClose]" value="1" <?php checked( $values['showFooterClose'], true ); ?> /> 1377 <?php esc_html_e( 'Show footer close button', 'synced-pattern-popups' ); ?> 1378 </label> 1379 </fieldset> 1380 </td> 1381 </tr> 1382 <tr> 1383 <th scope="row"> 1384 <label for="gallery_footer_close_text"> 1385 <?php esc_html_e( 'Footer Button Text', 'synced-pattern-popups' ); ?> 1386 </label> 1387 </th> 1388 <td> 1389 <input type="text" name="sppopups_defaults_gallery[footerCloseText]" id="gallery_footer_close_text" value="<?php echo esc_attr( $values['footerCloseText'] ); ?>" class="regular-text" /> 1390 </td> 1391 </tr> 1392 </tbody> 1393 </table> 1394 </div> 1395 </td> 1396 </tr> 1397 <tr> 1398 <th scope="row"> 1399 <label for="gallery_image_navigation"> 1400 <?php esc_html_e( 'Image Navigation', 'synced-pattern-popups' ); ?> 1401 </label> 1402 </th> 1403 <td> 1404 <select name="sppopups_defaults_gallery[imageNavigation]" id="gallery_image_navigation"> 1405 <option value="image" <?php selected( $values['imageNavigation'], 'image' ); ?>><?php esc_html_e( 'Image', 'synced-pattern-popups' ); ?></option> 1406 <option value="footer" <?php selected( $values['imageNavigation'], 'footer' ); ?>><?php esc_html_e( 'Footer', 'synced-pattern-popups' ); ?></option> 1407 <option value="both" <?php selected( $values['imageNavigation'], 'both' ); ?>><?php esc_html_e( 'Both', 'synced-pattern-popups' ); ?></option> 1408 </select> 1409 <p class="description"> 1410 <?php esc_html_e( 'Where to display navigation controls for gallery images.', 'synced-pattern-popups' ); ?> 1411 </p> 1412 </td> 1413 </tr> 1414 <tr> 1415 <th scope="row"> 1416 <?php esc_html_e( 'Gallery Options', 'synced-pattern-popups' ); ?> 1417 </th> 1418 <td> 1419 <fieldset> 1420 <label> 1421 <input type="checkbox" name="sppopups_defaults_gallery[showCaptions]" value="1" <?php checked( $values['showCaptions'], true ); ?> /> 1422 <?php esc_html_e( 'Show captions', 'synced-pattern-popups' ); ?> 1423 </label> 1424 <br /> 1425 <label> 1426 <input type="checkbox" name="sppopups_defaults_gallery[crossfadeTransition]" value="1" <?php checked( $values['crossfadeTransition'], true ); ?> /> 1427 <?php esc_html_e( 'Crossfade transition', 'synced-pattern-popups' ); ?> 1428 </label> 1429 <br /> 1430 <label> 1431 <input type="checkbox" name="sppopups_defaults_gallery[preloadAdjacentImages]" value="1" <?php checked( $values['preloadAdjacentImages'], true ); ?> /> 1432 <?php esc_html_e( 'Preload adjacent images', 'synced-pattern-popups' ); ?> 1433 </label> 1434 <br /> 1435 <label> 1436 <input type="checkbox" name="sppopups_defaults_gallery[showNavOnHover]" value="1" <?php checked( $values['showNavOnHover'], true ); ?> /> 1437 <?php esc_html_e( 'Show navigation on hover/touch', 'synced-pattern-popups' ); ?> 1438 </label> 1439 </fieldset> 1440 </td> 1441 </tr> 1442 <tr> 1443 <th scope="row"> 1444 <label for="gallery_transition_duration"> 1445 <?php esc_html_e( 'Transition Duration', 'synced-pattern-popups' ); ?> 1446 </label> 1447 </th> 1448 <td> 1449 <input type="number" name="sppopups_defaults_gallery[transitionDuration]" id="gallery_transition_duration" value="<?php echo esc_attr( $values['transitionDuration'] ); ?>" min="0" max="2000" step="1" style="width: 100px;" /> 1450 <span style="margin-left: 8px;"><?php esc_html_e( 'ms', 'synced-pattern-popups' ); ?></span> 1451 <p class="description"> 1452 <?php esc_html_e( 'Transition duration in milliseconds (0-2000).', 'synced-pattern-popups' ); ?> 1453 </p> 1454 </td> 1455 </tr> 1456 </tbody> 1457 </table> 1458 </div> 1459 </div> 1460 <?php 1461 } 1462 1463 /** 1464 * Get pattern defaults with fallbacks 1465 * 1466 * @return array Pattern defaults 1467 */ 1468 public static function get_pattern_defaults() { 1469 $instance = new self(); 1470 $defaults = $instance->get_default_pattern_defaults(); 1471 $saved = get_option( 'sppopups_defaults_pattern', array() ); 1472 1473 if ( ! is_array( $saved ) || empty( $saved ) ) { 1474 return $defaults; 1475 } 1476 1477 return wp_parse_args( $saved, $defaults ); 1478 } 1479 1480 /** 1481 * Get TLDR defaults with inheritance logic applied 1482 * 1483 * @return array TLDR defaults with inheritance resolved 1484 */ 1485 public static function get_tldr_defaults() { 1486 $instance = new self(); 1487 $pattern_defaults = self::get_pattern_defaults(); 1488 $tldr_defaults = $instance->get_default_tldr_defaults(); 1489 $saved = get_option( 'sppopups_defaults_tldr', array() ); 1490 1491 if ( ! is_array( $saved ) || empty( $saved ) ) { 1492 $saved = $tldr_defaults; 1493 } 1494 1495 $result = wp_parse_args( $saved, $tldr_defaults ); 1496 1497 // Apply inheritance from pattern defaults. 1498 if ( ! empty( $result['inheritModalAppearance'] ) ) { 1499 $result['maxWidth'] = $pattern_defaults['maxWidth']; 1500 $result['borderRadius'] = $pattern_defaults['borderRadius']; 1501 $result['maxHeight'] = $pattern_defaults['maxHeight']; 1502 } 1503 1504 if ( ! empty( $result['inheritOverlay'] ) ) { 1505 $result['overlayColor'] = $pattern_defaults['overlayColor']; 1506 $result['backdropBlur'] = $pattern_defaults['backdropBlur']; 1507 } 1508 1509 if ( ! empty( $result['inheritCloseButtons'] ) ) { 1510 $result['showIconClose'] = $pattern_defaults['showIconClose']; 1511 $result['showFooterClose'] = $pattern_defaults['showFooterClose']; 1512 $result['footerCloseText'] = $pattern_defaults['footerCloseText']; 1513 } 1514 1515 return $result; 1516 } 1517 1518 /** 1519 * Get gallery defaults with inheritance logic applied 1520 * 1521 * @return array Gallery defaults with inheritance resolved 1522 */ 1523 public static function get_gallery_defaults() { 1524 $instance = new self(); 1525 $pattern_defaults = self::get_pattern_defaults(); 1526 $gallery_defaults = $instance->get_default_gallery_defaults(); 1527 $saved = get_option( 'sppopups_defaults_gallery', array() ); 1528 1529 if ( ! is_array( $saved ) || empty( $saved ) ) { 1530 $saved = $gallery_defaults; 1531 } 1532 1533 $result = wp_parse_args( $saved, $gallery_defaults ); 1534 1535 // Apply inheritance from pattern defaults. 1536 if ( ! empty( $result['inheritModalAppearance'] ) ) { 1537 $result['maxWidth'] = $pattern_defaults['maxWidth']; 1538 $result['borderRadius'] = $pattern_defaults['borderRadius']; 1539 $result['maxHeight'] = $pattern_defaults['maxHeight']; 1540 } 1541 1542 if ( ! empty( $result['inheritOverlay'] ) ) { 1543 $result['overlayColor'] = $pattern_defaults['overlayColor']; 1544 $result['backdropBlur'] = $pattern_defaults['backdropBlur']; 1545 } 1546 1547 if ( ! empty( $result['inheritCloseButtons'] ) ) { 1548 $result['showIconClose'] = $pattern_defaults['showIconClose']; 1549 $result['showFooterClose'] = $pattern_defaults['showFooterClose']; 1550 $result['footerCloseText'] = $pattern_defaults['footerCloseText']; 1551 } 1552 1553 return $result; 1554 } 559 1555 } 560 1556 -
synced-pattern-popups/trunk/languages/synced-pattern-popups.pot
r3439916 r3442776 3 3 msgid "" 4 4 msgstr "" 5 "Project-Id-Version: Synced Pattern Popups 1. 2.1\n"5 "Project-Id-Version: Synced Pattern Popups 1.3.0\n" 6 6 "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/synced-pattern-popups\n" 7 7 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" … … 10 10 "Content-Type: text/plain; charset=UTF-8\n" 11 11 "Content-Transfer-Encoding: 8bit\n" 12 "POT-Creation-Date: 2026-01-1 4T23:10:03+00:00\n"12 "POT-Creation-Date: 2026-01-19T18:07:00+00:00\n" 13 13 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" 14 14 "X-Generator: WP-CLI 2.12.0\n" … … 18 18 #: sppopups.php 19 19 #: includes/class-sppopups-abilities.php:83 20 #: includes/class-sppopups-admin.php:5 3220 #: includes/class-sppopups-admin.php:587 21 21 #: assets/js/gallery-editor.js:229 22 22 msgid "Synced Pattern Popups" … … 101 101 #: includes/class-sppopups-abilities.php:224 102 102 #: includes/class-sppopups-abilities.php:305 103 #: includes/class-sppopups-admin.php: 381103 #: includes/class-sppopups-admin.php:427 104 104 msgid "(no title)" 105 105 msgstr "" … … 122 122 123 123 #: includes/class-sppopups-abilities.php:322 124 #: includes/class-sppopups-command-palette.php:111 124 125 msgid "Clear Popup Cache" 125 126 msgstr "" … … 189 190 #: includes/class-sppopups-admin.php:77 190 191 #: includes/class-sppopups-admin.php:78 191 #: includes/class-sppopups-admin.php: 275192 #: includes/class-sppopups-admin.php:318 192 193 msgid "Synced Patterns" 193 194 msgstr "" … … 202 203 203 204 #: includes/class-sppopups-admin.php:174 205 #: includes/class-sppopups-admin.php:209 204 206 msgid "Security check failed." 205 207 msgstr "" 206 208 207 #: includes/class-sppopups-admin.php:2 41209 #: includes/class-sppopups-admin.php:280 208 210 msgid "Pattern deleted successfully." 209 211 msgstr "" 210 212 211 213 #. translators: %d: number of cache entries deleted 212 #: includes/class-sppopups-admin.php:2 47214 #: includes/class-sppopups-admin.php:286 213 215 #, php-format 214 216 msgid "Cache cleared successfully. %d entry deleted." … … 218 220 219 221 #. translators: %d: Pattern ID 220 #: includes/class-sppopups-admin.php: 261222 #: includes/class-sppopups-admin.php:300 221 223 #, php-format 222 224 msgid "Transient cache deleted successfully for pattern #%d." 223 225 msgstr "" 224 226 225 #: includes/class-sppopups-admin.php: 268227 #: includes/class-sppopups-admin.php:307 226 228 msgid "TLDR settings saved successfully." 227 229 msgstr "" 228 230 229 #: includes/class-sppopups-admin.php:280 231 #: includes/class-sppopups-admin.php:311 232 msgid "Defaults settings saved successfully." 233 msgstr "" 234 235 #: includes/class-sppopups-admin.php:323 230 236 msgid "Learn more about Synced Pattern Popups" 231 237 msgstr "" 232 238 233 #: includes/class-sppopups-admin.php: 288239 #: includes/class-sppopups-admin.php:331 234 240 msgid "Patterns" 235 241 msgstr "" 236 242 237 #: includes/class-sppopups-admin.php: 291243 #: includes/class-sppopups-admin.php:334 238 244 #: includes/class-sppopups-ajax.php:374 239 245 msgid "TLDR" 240 246 msgstr "" 241 247 242 #: includes/class-sppopups-admin.php:294 248 #: includes/class-sppopups-admin.php:337 249 msgid "Defaults" 250 msgstr "" 251 252 #: includes/class-sppopups-admin.php:340 243 253 msgid "How to Use" 244 254 msgstr "" 245 255 246 #: includes/class-sppopups-admin.php: 297256 #: includes/class-sppopups-admin.php:343 247 257 msgid "Get Support" 248 258 msgstr "" 249 259 250 #: includes/class-sppopups-admin.php:3 06260 #: includes/class-sppopups-admin.php:352 251 261 msgid "Add New" 252 262 msgstr "" 253 263 254 #: includes/class-sppopups-admin.php:3 15264 #: includes/class-sppopups-admin.php:361 255 265 msgid "Clear Transient Cache" 256 266 msgstr "" 257 267 258 #: includes/class-sppopups-admin.php:3 20268 #: includes/class-sppopups-admin.php:366 259 269 msgid "Manage synced patterns that can be used as popups. Only synced patterns are available for popup triggers." 260 270 msgstr "" 261 271 262 #: includes/class-sppopups-admin.php:3 26272 #: includes/class-sppopups-admin.php:372 263 273 msgid "No synced patterns found." 264 274 msgstr "" 265 275 266 #: includes/class-sppopups-admin.php:3 28276 #: includes/class-sppopups-admin.php:374 267 277 msgid "Create your first synced pattern" 268 278 msgstr "" 269 279 270 #: includes/class-sppopups-admin.php:3 37271 #: includes/class-sppopups-admin.php: 375280 #: includes/class-sppopups-admin.php:383 281 #: includes/class-sppopups-admin.php:421 272 282 msgid "ID" 273 283 msgstr "" 274 284 275 #: includes/class-sppopups-admin.php:3 38276 #: includes/class-sppopups-admin.php: 378285 #: includes/class-sppopups-admin.php:384 286 #: includes/class-sppopups-admin.php:424 277 287 msgid "Title" 278 288 msgstr "" 279 289 280 #: includes/class-sppopups-admin.php:3 39281 #: includes/class-sppopups-admin.php: 392290 #: includes/class-sppopups-admin.php:385 291 #: includes/class-sppopups-admin.php:438 282 292 msgid "Status" 283 293 msgstr "" 284 294 285 #: includes/class-sppopups-admin.php:3 40286 #: includes/class-sppopups-admin.php:4 04295 #: includes/class-sppopups-admin.php:386 296 #: includes/class-sppopups-admin.php:450 287 297 msgid "Trigger Code" 288 298 msgstr "" 289 299 290 #: includes/class-sppopups-admin.php:3 41291 #: includes/class-sppopups-admin.php:4 19300 #: includes/class-sppopups-admin.php:387 301 #: includes/class-sppopups-admin.php:465 292 302 msgid "Actions" 293 303 msgstr "" 294 304 295 #: includes/class-sppopups-admin.php:4 11296 #: includes/class-sppopups-admin.php:4 12305 #: includes/class-sppopups-admin.php:457 306 #: includes/class-sppopups-admin.php:458 297 307 msgid "Copy to Clipboard" 298 308 msgstr "" 299 309 300 #: includes/class-sppopups-admin.php:4 24310 #: includes/class-sppopups-admin.php:470 301 311 msgid "Edit" 302 312 msgstr "" 303 313 304 #: includes/class-sppopups-admin.php:4 31314 #: includes/class-sppopups-admin.php:477 305 315 msgid "Are you sure you want to delete this pattern?" 306 316 msgstr "" 307 317 308 #: includes/class-sppopups-admin.php:4 33318 #: includes/class-sppopups-admin.php:479 309 319 msgid "Delete" 310 320 msgstr "" 311 321 312 322 #. translators: %d: Pattern ID 313 #: includes/class-sppopups-admin.php:4 49323 #: includes/class-sppopups-admin.php:495 314 324 #, php-format 315 325 msgid "Are you sure you want to delete the transient cache for pattern #%d?" … … 317 327 318 328 #. translators: %d: Pattern ID 319 #: includes/class-sppopups-admin.php: 455329 #: includes/class-sppopups-admin.php:501 320 330 #, php-format 321 331 msgid "Delete Transient #%d" 322 332 msgstr "" 323 333 324 #: includes/class-sppopups-admin.php: 480334 #: includes/class-sppopups-admin.php:535 325 335 msgid "How to Use Synced Pattern Popups" 326 336 msgstr "" 327 337 328 #: includes/class-sppopups-admin.php: 482338 #: includes/class-sppopups-admin.php:537 329 339 msgid "There are two ways to trigger a popup on your site:" 330 340 msgstr "" 331 341 332 #: includes/class-sppopups-admin.php: 486342 #: includes/class-sppopups-admin.php:541 333 343 msgid "Method 1: Class Name" 334 344 msgstr "" 335 345 336 #: includes/class-sppopups-admin.php: 487346 #: includes/class-sppopups-admin.php:542 337 347 msgid "Add the class" 338 348 msgstr "" 339 349 340 #: includes/class-sppopups-admin.php: 487350 #: includes/class-sppopups-admin.php:542 341 351 msgid "to any clickable element, where" 342 352 msgstr "" 343 353 344 #: includes/class-sppopups-admin.php: 487354 #: includes/class-sppopups-admin.php:542 345 355 msgid "is the numeric ID of your Synced Pattern." 346 356 msgstr "" 347 357 348 #: includes/class-sppopups-admin.php: 488358 #: includes/class-sppopups-admin.php:543 349 359 msgid "Examples:" 350 360 msgstr "" 351 361 352 #: includes/class-sppopups-admin.php: 489353 #: includes/class-sppopups-admin.php: 497362 #: includes/class-sppopups-admin.php:544 363 #: includes/class-sppopups-admin.php:552 354 364 msgid "Open Popup" 355 365 msgstr "" 356 366 357 #: includes/class-sppopups-admin.php: 490367 #: includes/class-sppopups-admin.php:545 358 368 msgid "Click Me" 359 369 msgstr "" 360 370 361 #: includes/class-sppopups-admin.php: 494371 #: includes/class-sppopups-admin.php:549 362 372 msgid "Method 2: Href Attribute" 363 373 msgstr "" 364 374 365 #: includes/class-sppopups-admin.php: 495375 #: includes/class-sppopups-admin.php:550 366 376 msgid "Set the" 367 377 msgstr "" 368 378 369 #: includes/class-sppopups-admin.php: 495379 #: includes/class-sppopups-admin.php:550 370 380 msgid "attribute to" 371 381 msgstr "" 372 382 373 #: includes/class-sppopups-admin.php: 495383 #: includes/class-sppopups-admin.php:550 374 384 msgid "on any link element. This is especially useful in the WordPress Block Editor where you can't easily add custom classes." 375 385 msgstr "" 376 386 377 #: includes/class-sppopups-admin.php: 496378 #: includes/class-sppopups-admin.php:5 03387 #: includes/class-sppopups-admin.php:551 388 #: includes/class-sppopups-admin.php:558 379 389 msgid "Example:" 380 390 msgstr "" 381 391 382 #: includes/class-sppopups-admin.php:5 01392 #: includes/class-sppopups-admin.php:556 383 393 msgid "Custom Width" 384 394 msgstr "" 385 395 386 #: includes/class-sppopups-admin.php:5 02396 #: includes/class-sppopups-admin.php:557 387 397 msgid "You can specify a custom modal width by adding a width suffix:" 388 398 msgstr "" 389 399 390 #: includes/class-sppopups-admin.php:5 02400 #: includes/class-sppopups-admin.php:557 391 401 msgid "where width is in pixels (100-5000px)." 392 402 msgstr "" 393 403 394 #: includes/class-sppopups-admin.php:5 04404 #: includes/class-sppopups-admin.php:559 395 405 msgid "Open 800px Modal" 396 406 msgstr "" 397 407 398 #: includes/class-sppopups-admin.php:5 08408 #: includes/class-sppopups-admin.php:563 399 409 msgid "Finding Pattern IDs" 400 410 msgstr "" 401 411 402 #: includes/class-sppopups-admin.php:5 09412 #: includes/class-sppopups-admin.php:564 403 413 msgid "Go to WordPress Admin → Appearance → Synced Patterns. The ID column shows the pattern ID prominently. You can also click the \"Copy Trigger\" button in the Actions column to copy the complete trigger code." 404 414 msgstr "" 405 415 406 #: includes/class-sppopups-admin.php: 564416 #: includes/class-sppopups-admin.php:619 407 417 msgid "Modal Assets:" 408 418 msgstr "" 409 419 410 #: includes/class-sppopups-admin.php: 569411 #: includes/class-sppopups-admin.php: 585420 #: includes/class-sppopups-admin.php:624 421 #: includes/class-sppopups-admin.php:640 412 422 msgid "Auto-Detect" 413 423 msgstr "" 414 424 415 #: includes/class-sppopups-admin.php: 573416 #: includes/class-sppopups-admin.php: 589425 #: includes/class-sppopups-admin.php:628 426 #: includes/class-sppopups-admin.php:644 417 427 msgid "Loaded" 418 428 msgstr "" 419 429 420 #: includes/class-sppopups-admin.php: 580430 #: includes/class-sppopups-admin.php:635 421 431 msgid "Gallery Assets:" 422 432 msgstr "" 423 433 424 #: includes/class-sppopups-admin.php: 663434 #: includes/class-sppopups-admin.php:718 425 435 msgid "You do not have permission to install plugins." 426 436 msgstr "" 427 437 428 438 #. translators: %s: Error message 429 #: includes/class-sppopups-admin.php:7 01439 #: includes/class-sppopups-admin.php:756 430 440 #, php-format 431 441 msgid "Error retrieving plugin information: %s" 432 442 msgstr "" 433 443 434 #: includes/class-sppopups-admin.php:7 11444 #: includes/class-sppopups-admin.php:766 435 445 msgid "Filesystem credentials are required to install plugins." 436 446 msgstr "" 437 447 438 #: includes/class-sppopups-admin.php:7 15448 #: includes/class-sppopups-admin.php:770 439 449 msgid "Filesystem initialization failed." 440 450 msgstr "" 441 451 442 452 #. translators: %s: Error message 443 #: includes/class-sppopups-admin.php:7 30453 #: includes/class-sppopups-admin.php:785 444 454 #, php-format 445 455 msgid "Plugin installation failed: %s" 446 456 msgstr "" 447 457 448 #: includes/class-sppopups-admin.php:7 37458 #: includes/class-sppopups-admin.php:792 449 459 msgid "Plugin installation failed. Please try again." 450 460 msgstr "" 451 461 452 #: includes/class-sppopups-admin.php:8 06462 #: includes/class-sppopups-admin.php:861 453 463 msgid "Go to Synced Pattern Popups" 454 464 msgstr "" 455 465 456 #: includes/class-sppopups-admin.php: 852466 #: includes/class-sppopups-admin.php:907 457 467 msgid "Settings" 458 468 msgstr "" … … 499 509 msgstr "" 500 510 501 #: includes/class-sppopups-plugin.php:389 502 #: includes/class-sppopups-plugin.php:417 511 #: includes/class-sppopups-command-palette.php:110 512 msgid "Go to: Appearance > Synced Patterns" 513 msgstr "" 514 515 #: includes/class-sppopups-plugin.php:401 516 #: includes/class-sppopups-plugin.php:429 503 517 msgid "Loading content..." 504 518 msgstr "" 505 519 506 #: includes/class-sppopups-plugin.php: 390520 #: includes/class-sppopups-plugin.php:402 507 521 msgid "Error loading content. Please try again." 508 522 msgstr "" 509 523 510 #: includes/class-sppopups-plugin.php: 391524 #: includes/class-sppopups-plugin.php:403 511 525 msgid "Content not found." 512 526 msgstr "" 513 527 514 #: includes/class-sppopups-plugin.php:4 08528 #: includes/class-sppopups-plugin.php:420 515 529 msgid "Press Escape to close. Tab stays within the popup." 516 530 msgstr "" 517 531 518 #: includes/class-sppopups-plugin.php:409519 532 #: includes/class-sppopups-plugin.php:421 533 #: includes/class-sppopups-plugin.php:433 520 534 msgid "Close modal" 521 535 msgstr "" 522 536 523 #: includes/class-sppopups-plugin.php:4 22537 #: includes/class-sppopups-plugin.php:434 524 538 msgid "Close" 525 539 msgstr "" … … 563 577 msgstr "" 564 578 565 #: includes/class-sppopups-settings.php: 104579 #: includes/class-sppopups-settings.php:399 566 580 msgid "Configure the AI-powered TLDR feature that generates page summaries on-demand." 567 581 msgstr "" 568 582 569 #: includes/class-sppopups-settings.php: 107570 #: includes/class-sppopups-settings.php: 245583 #: includes/class-sppopups-settings.php:402 584 #: includes/class-sppopups-settings.php:540 571 585 msgid "AI Experiments plugin is not active. TLDR feature requires the AI Experiments plugin to be installed and activated." 572 586 msgstr "" 573 587 574 #: includes/class-sppopups-settings.php: 111575 #: includes/class-sppopups-settings.php: 249588 #: includes/class-sppopups-settings.php:406 589 #: includes/class-sppopups-settings.php:544 576 590 msgid "AI credentials are not configured. Please configure AI credentials in Settings → AI Experiments." 577 591 msgstr "" 578 592 579 #: includes/class-sppopups-settings.php: 115580 #: includes/class-sppopups-settings.php: 253593 #: includes/class-sppopups-settings.php:410 594 #: includes/class-sppopups-settings.php:548 581 595 msgid "AI Experiments plugin is active and credentials are configured." 582 596 msgstr "" 583 597 584 #: includes/class-sppopups-settings.php: 129585 #: includes/class-sppopups-settings.php: 271586 #: includes/class-sppopups-settings.php: 365598 #: includes/class-sppopups-settings.php:424 599 #: includes/class-sppopups-settings.php:566 600 #: includes/class-sppopups-settings.php:660 587 601 msgid "Enable AI-powered TLDR feature" 588 602 msgstr "" 589 603 590 #: includes/class-sppopups-settings.php: 132591 #: includes/class-sppopups-settings.php: 274592 #: includes/class-sppopups-settings.php: 368604 #: includes/class-sppopups-settings.php:427 605 #: includes/class-sppopups-settings.php:569 606 #: includes/class-sppopups-settings.php:663 593 607 msgid "When enabled, users can click elements with class \"spp-trigger-tldr\" to generate and display AI-powered summaries of the current page." 594 608 msgstr "" 595 609 596 #: includes/class-sppopups-settings.php: 145597 #: includes/class-sppopups-settings.php: 304598 #: includes/class-sppopups-settings.php: 398610 #: includes/class-sppopups-settings.php:440 611 #: includes/class-sppopups-settings.php:599 612 #: includes/class-sppopups-settings.php:693 599 613 msgid "The prompt template used to generate TLDR summaries. The page content will be automatically appended to your prompt." 600 614 msgstr "" 601 615 602 #: includes/class-sppopups-settings.php: 158616 #: includes/class-sppopups-settings.php:453 603 617 msgid "How long to cache generated TLDR summaries (in hours). Default: 12 hours." 604 618 msgstr "" 605 619 606 #: includes/class-sppopups-settings.php: 240607 #: includes/class-sppopups-settings.php: 339620 #: includes/class-sppopups-settings.php:535 621 #: includes/class-sppopups-settings.php:634 608 622 msgid "AI TLDR Settings" 609 623 msgstr "" 610 624 611 #: includes/class-sppopups-settings.php: 265612 #: includes/class-sppopups-settings.php: 359625 #: includes/class-sppopups-settings.php:560 626 #: includes/class-sppopups-settings.php:654 613 627 msgid "Enable TLDR Feature" 614 628 msgstr "" 615 629 616 #: includes/class-sppopups-settings.php: 281617 #: includes/class-sppopups-settings.php: 375630 #: includes/class-sppopups-settings.php:576 631 #: includes/class-sppopups-settings.php:670 618 632 msgid "TLDR Prompt" 619 633 msgstr "" 620 634 621 #: includes/class-sppopups-settings.php: 293622 #: includes/class-sppopups-settings.php: 387635 #: includes/class-sppopups-settings.php:588 636 #: includes/class-sppopups-settings.php:682 623 637 msgid "Default" 624 638 msgstr "" 625 639 626 #: includes/class-sppopups-settings.php:297 627 #: includes/class-sppopups-settings.php:391 640 #: includes/class-sppopups-settings.php:592 641 #: includes/class-sppopups-settings.php:686 642 #: includes/class-sppopups-settings.php:1029 643 #: includes/class-sppopups-settings.php:1086 644 #: includes/class-sppopups-settings.php:1131 645 #: includes/class-sppopups-settings.php:1231 646 #: includes/class-sppopups-settings.php:1288 647 #: includes/class-sppopups-settings.php:1333 628 648 msgid "Custom" 629 649 msgstr "" 630 650 631 #: includes/class-sppopups-settings.php: 311632 #: includes/class-sppopups-settings.php: 405651 #: includes/class-sppopups-settings.php:606 652 #: includes/class-sppopups-settings.php:700 633 653 msgid "Cache Duration" 634 654 msgstr "" 635 655 636 #: includes/class-sppopups-settings.php: 316637 #: includes/class-sppopups-settings.php: 410656 #: includes/class-sppopups-settings.php:611 657 #: includes/class-sppopups-settings.php:705 638 658 msgid "hours" 639 659 msgstr "" 640 660 641 #: includes/class-sppopups-settings.php: 318642 #: includes/class-sppopups-settings.php: 412661 #: includes/class-sppopups-settings.php:613 662 #: includes/class-sppopups-settings.php:707 643 663 msgid "How long to cache generated TLDR summaries. Default: 12 hours." 644 664 msgstr "" 645 665 646 #: includes/class-sppopups-settings.php: 325647 #: includes/class-sppopups-settings.php: 419666 #: includes/class-sppopups-settings.php:620 667 #: includes/class-sppopups-settings.php:714 648 668 msgid "Save TLDR Settings" 649 669 msgstr "" 650 670 651 #: includes/class-sppopups-settings.php: 343671 #: includes/class-sppopups-settings.php:638 652 672 msgid "The AI-powered TLDR feature generates concise summaries of your page content on-demand. To use this feature, you need to complete the following requirements:" 653 673 msgstr "" 654 674 655 #: includes/class-sppopups-settings.php: 348675 #: includes/class-sppopups-settings.php:643 656 676 msgid "AI Experiments plugin is active and credentials are configured. You can now configure the TLDR feature settings below." 657 677 msgstr "" 658 678 659 #: includes/class-sppopups-settings.php: 440679 #: includes/class-sppopups-settings.php:735 660 680 msgid "Step 1" 661 681 msgstr "" 662 682 663 #: includes/class-sppopups-settings.php: 442683 #: includes/class-sppopups-settings.php:737 664 684 msgid "AI Experiments plugin installed" 665 685 msgstr "" 666 686 667 #: includes/class-sppopups-settings.php: 446687 #: includes/class-sppopups-settings.php:741 668 688 msgid "Install the AI Experiments plugin from the WordPress repository" 669 689 msgstr "" 670 690 671 #: includes/class-sppopups-settings.php: 458691 #: includes/class-sppopups-settings.php:753 672 692 msgid "Install" 673 693 msgstr "" 674 694 675 #: includes/class-sppopups-settings.php: 474695 #: includes/class-sppopups-settings.php:769 676 696 msgid "Step 2" 677 697 msgstr "" 678 698 679 #: includes/class-sppopups-settings.php: 476699 #: includes/class-sppopups-settings.php:771 680 700 msgid "AI Experiments plugin activated" 681 701 msgstr "" 682 702 683 #: includes/class-sppopups-settings.php: 480703 #: includes/class-sppopups-settings.php:775 684 704 msgid "Activate the AI Experiments plugin to enable AI features" 685 705 msgstr "" 686 706 687 #: includes/class-sppopups-settings.php: 492707 #: includes/class-sppopups-settings.php:787 688 708 msgid "Activate" 689 709 msgstr "" 690 710 691 #: includes/class-sppopups-settings.php: 503711 #: includes/class-sppopups-settings.php:798 692 712 msgid "Step 3" 693 713 msgstr "" 694 714 695 #: includes/class-sppopups-settings.php: 505715 #: includes/class-sppopups-settings.php:800 696 716 msgid "AI credentials saved in settings" 697 717 msgstr "" 698 718 699 #: includes/class-sppopups-settings.php: 509719 #: includes/class-sppopups-settings.php:804 700 720 msgid "Configure your AI API credentials in the plugin settings" 701 721 msgstr "" 702 722 703 #: includes/class-sppopups-settings.php: 515723 #: includes/class-sppopups-settings.php:810 704 724 msgid "Start" 705 725 msgstr "" 706 726 707 #: includes/class-sppopups-tldr.php:49 708 msgid "Invalid post ID." 709 msgstr "" 710 711 #: includes/class-sppopups-tldr.php:54 712 msgid "TLDR feature is disabled." 713 msgstr "" 714 715 #: includes/class-sppopups-tldr.php:66 716 msgid "AI service is not available. Please check AI Experiments plugin configuration." 717 msgstr "" 718 719 #: includes/class-sppopups-tldr.php:76 720 msgid "No content found to generate TLDR." 721 msgstr "" 722 723 #: includes/class-sppopups-tldr.php:157 724 msgid "AI Client is not available." 725 msgstr "" 726 727 #: includes/class-sppopups-tldr.php:167 728 msgid "Format your response using Markdown syntax (use **bold** for emphasis, * for lists, ## for headings, etc.)." 729 msgstr "" 730 731 #: includes/class-sppopups-tldr.php:189 732 msgid "Invalid response from AI service." 733 msgstr "" 734 735 #: includes/class-sppopups-tldr.php:191 736 msgid "Failed to generate TLDR: " 737 msgstr "" 738 739 #: assets/js/gallery-editor.js:235 740 msgid "Modal Size" 741 msgstr "" 742 743 #: assets/js/gallery-editor.js:242 744 msgid "Width in pixels" 745 msgstr "" 746 727 #: includes/class-sppopups-settings.php:861 728 msgid "Popup Defaults" 729 msgstr "" 730 731 #: includes/class-sppopups-settings.php:863 732 msgid "Configure default appearance and behavior settings for all popup types. These settings will be used unless overridden by individual popups." 733 msgstr "" 734 735 #: includes/class-sppopups-settings.php:873 736 msgid "Save Defaults" 737 msgstr "" 738 739 #: includes/class-sppopups-settings.php:889 740 msgid "Pattern Popups Defaults" 741 msgstr "" 742 743 #: includes/class-sppopups-settings.php:897 744 #: includes/class-sppopups-settings.php:1038 745 #: includes/class-sppopups-settings.php:1240 746 msgid "Default Width" 747 msgstr "" 748 749 #: includes/class-sppopups-settings.php:902 750 #: includes/class-sppopups-settings.php:916 751 #: includes/class-sppopups-settings.php:957 752 #: includes/class-sppopups-settings.php:1043 753 #: includes/class-sppopups-settings.php:1054 754 #: includes/class-sppopups-settings.php:1110 755 #: includes/class-sppopups-settings.php:1245 756 #: includes/class-sppopups-settings.php:1256 757 #: includes/class-sppopups-settings.php:1312 758 msgid "px" 759 msgstr "" 760 761 #: includes/class-sppopups-settings.php:904 762 msgid "Default modal width in pixels (100-5000)." 763 msgstr "" 764 765 #: includes/class-sppopups-settings.php:911 766 #: includes/class-sppopups-settings.php:1049 767 #: includes/class-sppopups-settings.php:1251 768 msgid "Border Radius" 769 msgstr "" 770 771 #: includes/class-sppopups-settings.php:918 772 msgid "Modal border radius in pixels (0-50)." 773 msgstr "" 774 775 #: includes/class-sppopups-settings.php:925 776 #: includes/class-sppopups-settings.php:1060 777 #: includes/class-sppopups-settings.php:1262 778 msgid "Max Height" 779 msgstr "" 780 781 #: includes/class-sppopups-settings.php:930 782 #: includes/class-sppopups-settings.php:1065 783 #: includes/class-sppopups-settings.php:1267 784 msgid "%" 785 msgstr "" 786 787 #: includes/class-sppopups-settings.php:932 788 msgid "Maximum modal height as percentage of viewport (50-100)." 789 msgstr "" 790 791 #: includes/class-sppopups-settings.php:939 792 #: includes/class-sppopups-settings.php:1095 793 #: includes/class-sppopups-settings.php:1297 794 msgid "Overlay Color" 795 msgstr "" 796 797 #: includes/class-sppopups-settings.php:945 798 msgid "Overlay background color in rgba format (e.g., rgba(0, 0, 0, 0.1))." 799 msgstr "" 800 801 #: includes/class-sppopups-settings.php:952 802 #: includes/class-sppopups-settings.php:1105 803 #: includes/class-sppopups-settings.php:1307 804 msgid "Backdrop Blur" 805 msgstr "" 806 807 #: includes/class-sppopups-settings.php:959 808 msgid "Backdrop blur amount in pixels (0-20)." 809 msgstr "" 810 811 #: includes/class-sppopups-settings.php:965 812 #: includes/class-sppopups-settings.php:1120 813 #: includes/class-sppopups-settings.php:1322 747 814 #: assets/js/gallery-editor.js:249 748 815 msgid "Close Buttons" 749 816 msgstr "" 750 817 751 #: assets/js/gallery-editor.js:253 752 msgid "X icon" 753 msgstr "" 754 755 #: assets/js/gallery-editor.js:254 756 msgid "Close Button" 757 msgstr "" 758 818 #: includes/class-sppopups-settings.php:971 819 #: includes/class-sppopups-settings.php:1145 820 #: includes/class-sppopups-settings.php:1347 821 msgid "Show icon close button" 822 msgstr "" 823 824 #: includes/class-sppopups-settings.php:976 825 #: includes/class-sppopups-settings.php:1150 826 #: includes/class-sppopups-settings.php:1352 827 msgid "Show footer close button" 828 msgstr "" 829 830 #: includes/class-sppopups-settings.php:984 831 #: includes/class-sppopups-settings.php:1158 832 #: includes/class-sppopups-settings.php:1360 833 msgid "Footer Button Text" 834 msgstr "" 835 836 #: includes/class-sppopups-settings.php:990 837 msgid "Text displayed on the footer close button." 838 msgstr "" 839 840 #: includes/class-sppopups-settings.php:1011 841 msgid "TLDR Popups Defaults" 842 msgstr "" 843 844 #: includes/class-sppopups-settings.php:1018 845 #: includes/class-sppopups-settings.php:1220 846 msgid "Modal Appearance" 847 msgstr "" 848 849 #: includes/class-sppopups-settings.php:1024 850 #: includes/class-sppopups-settings.php:1081 851 #: includes/class-sppopups-settings.php:1126 852 #: includes/class-sppopups-settings.php:1226 853 #: includes/class-sppopups-settings.php:1283 854 #: includes/class-sppopups-settings.php:1328 855 msgid "Inherit from Pattern Modal" 856 msgstr "" 857 858 #: includes/class-sppopups-settings.php:1075 859 #: includes/class-sppopups-settings.php:1277 860 msgid "Overlay" 861 msgstr "" 862 863 #: includes/class-sppopups-settings.php:1139 864 #: includes/class-sppopups-settings.php:1341 865 msgid "Options" 866 msgstr "" 867 868 #: includes/class-sppopups-settings.php:1173 869 msgid "Loading Text" 870 msgstr "" 871 872 #: includes/class-sppopups-settings.php:1179 873 msgid "Text displayed while generating TLDR summary." 874 msgstr "" 875 876 #: includes/class-sppopups-settings.php:1186 877 msgid "Title Text" 878 msgstr "" 879 880 #: includes/class-sppopups-settings.php:1192 881 msgid "Title displayed in TLDR modal header." 882 msgstr "" 883 884 #: includes/class-sppopups-settings.php:1213 885 msgid "Gallery Popups Defaults" 886 msgstr "" 887 888 #: includes/class-sppopups-settings.php:1375 889 #: assets/js/gallery-editor.js:263 890 msgid "Image Navigation" 891 msgstr "" 892 893 #: includes/class-sppopups-settings.php:1380 894 msgid "Image" 895 msgstr "" 896 897 #: includes/class-sppopups-settings.php:1381 898 msgid "Footer" 899 msgstr "" 900 901 #: includes/class-sppopups-settings.php:1382 759 902 #: assets/js/gallery-editor.js:255 760 903 #: assets/js/gallery-editor.js:269 … … 762 905 msgstr "" 763 906 764 #: assets/js/gallery-editor.js:263 765 msgid "Image Navigation" 907 #: includes/class-sppopups-settings.php:1385 908 msgid "Where to display navigation controls for gallery images." 909 msgstr "" 910 911 #: includes/class-sppopups-settings.php:1391 912 msgid "Gallery Options" 913 msgstr "" 914 915 #: includes/class-sppopups-settings.php:1397 916 msgid "Show captions" 917 msgstr "" 918 919 #: includes/class-sppopups-settings.php:1402 920 msgid "Crossfade transition" 921 msgstr "" 922 923 #: includes/class-sppopups-settings.php:1407 924 msgid "Preload adjacent images" 925 msgstr "" 926 927 #: includes/class-sppopups-settings.php:1412 928 msgid "Show navigation on hover/touch" 929 msgstr "" 930 931 #: includes/class-sppopups-settings.php:1420 932 msgid "Transition Duration" 933 msgstr "" 934 935 #: includes/class-sppopups-settings.php:1425 936 msgid "ms" 937 msgstr "" 938 939 #: includes/class-sppopups-settings.php:1427 940 msgid "Transition duration in milliseconds (0-2000)." 941 msgstr "" 942 943 #: includes/class-sppopups-tldr.php:49 944 msgid "Invalid post ID." 945 msgstr "" 946 947 #: includes/class-sppopups-tldr.php:54 948 msgid "TLDR feature is disabled." 949 msgstr "" 950 951 #: includes/class-sppopups-tldr.php:66 952 msgid "AI service is not available. Please check AI Experiments plugin configuration." 953 msgstr "" 954 955 #: includes/class-sppopups-tldr.php:76 956 msgid "No content found to generate TLDR." 957 msgstr "" 958 959 #: includes/class-sppopups-tldr.php:157 960 msgid "AI Client is not available." 961 msgstr "" 962 963 #: includes/class-sppopups-tldr.php:167 964 msgid "Format your response using Markdown syntax (use **bold** for emphasis, * for lists, ## for headings, etc.)." 965 msgstr "" 966 967 #: includes/class-sppopups-tldr.php:189 968 msgid "Invalid response from AI service." 969 msgstr "" 970 971 #: includes/class-sppopups-tldr.php:191 972 msgid "Failed to generate TLDR: " 973 msgstr "" 974 975 #: assets/js/gallery-editor.js:235 976 msgid "Modal Size" 977 msgstr "" 978 979 #: assets/js/gallery-editor.js:242 980 msgid "Width in pixels" 981 msgstr "" 982 983 #: assets/js/gallery-editor.js:253 984 msgid "X icon" 985 msgstr "" 986 987 #: assets/js/gallery-editor.js:254 988 msgid "Close Button" 766 989 msgstr "" 767 990 -
synced-pattern-popups/trunk/readme.txt
r3439916 r3442776 1 === Synced Pattern Popups ===1 === Synced Pattern Popups === 2 2 Contributors: webdevmattcrom 3 3 Tags: popup, modal, synced-patterns, ai, tldr 4 4 Requires at least: 5.8 5 5 Tested up to: 6.9 6 Stable tag: 1. 2.16 Stable tag: 1.3.0 7 7 License: GPLv2 or later 8 8 License URI: https://www.gnu.org/licenses/gpl-2.0.html … … 198 198 199 199 == Changelog == 200 201 = 1.3.0 = 202 * New: Default Settings page for configuring popup appearance defaults (Pattern, TLDR, and Gallery popups) 203 * New: Settings inheritance system - TLDR and Gallery popups can inherit from Pattern defaults 204 * New: Command Palette integration for quick access to plugin features 205 * New: Comprehensive testing infrastructure (PHPUnit and Jest) to ensure defaults are respected 206 * New: CI/CD workflows for automated testing on every commit 207 * Improved: Modal scrolling behavior - modals now properly scroll long content instead of extending beyond viewport 208 * Improved: CSS refactored to use custom properties for dynamic styling based on settings 209 * Improved: Frontend defaults application with proper inheritance and override support 210 * Fixed: Modal height constraints now work correctly with max-height settings 211 * Fixed: Default width settings now properly apply to all popup types 200 212 201 213 = 1.2.0 = … … 271 283 == Upgrade Notice == 272 284 285 = 1.3.0 = 286 Major update introducing default settings page and Command Palette integration. Configure default popup appearance (width, height, colors, close buttons) for Pattern, TLDR, and Gallery popups. TLDR and Gallery can inherit from Pattern defaults. Improved modal scrolling. Recommended for all users. 287 273 288 = 1.2.0 = 274 289 Major refactor of modal state management for improved stability, maintainability, and debugging. Fixes an issue with gallery random order. Addresses Plugin Check warnings. Recommended for all users. -
synced-pattern-popups/trunk/sppopups.php
r3439916 r3442776 1 <?php1 <?php 2 2 /** 3 3 * Plugin Name: Synced Pattern Popups 4 4 * Description: A lightweight modal popup system that loads WordPress Synced Pattern content on demand. Trigger with class "spp-trigger-{id}". 5 * Version: 1. 2.15 * Version: 1.3.0 6 6 * Author: Matt Cromwell 7 7 * Author URI: https://www.mattcromwell.com … … 21 21 22 22 // Define plugin constants. 23 define( 'SPPOPUPS_VERSION', '1. 2.1' );23 define( 'SPPOPUPS_VERSION', '1.3.0' ); 24 24 define( 'SPPOPUPS_PLUGIN_DIR', plugin_dir_path( __FILE__ ) ); 25 25 define( 'SPPOPUPS_PLUGIN_URL', plugin_dir_url( __FILE__ ) ); … … 40 40 require_once SPPOPUPS_PLUGIN_DIR . 'includes/class-sppopups-shipped-patterns.php'; 41 41 require_once SPPOPUPS_PLUGIN_DIR . 'includes/class-sppopups-gallery.php'; 42 require_once SPPOPUPS_PLUGIN_DIR . 'includes/class-sppopups-command-palette.php'; 42 43 43 44 // Register activation hook to set review notice trigger date and ensure shipped patterns.
Note: See TracChangeset
for help on using the changeset viewer.