diff --git a/CHANGELOG.md b/CHANGELOG.md index 8218283..5e8e02f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [1.1.0] - 2024-12-15 + +### Added + +- Customize tab with live preview for password form styling +- Preset themes: Default Purple, Business Blue, Dark Mode +- Background customization: color, gradient, and background image +- Card styling options: background color, border radius, shadow +- Logo upload with adjustable width +- Typography settings: heading text, heading color, text color, font family +- Button customization: text, background color, text color, border radius +- Form options: show/hide "Remember Me" checkbox, input border radius +- Footer customization: text and link URL +- Updated Norwegian Bokmål translations for all new strings + ## [1.0.4] - 2024-12-15 ### Added diff --git a/README.md b/README.md index 805e310..18899de 100644 --- a/README.md +++ b/README.md @@ -8,10 +8,14 @@ A WordPress plugin for password protecting your site's content. Protect all page - **Front Page Bypass**: The front page is always accessible without a password - **Logged-in User Bypass**: Authenticated users skip the password prompt - **Protection Modes**: Protect all content (with exclusions) or only selected pages/posts +- **Customizable Password Form**: Personalize colors, typography, logo, and more with live preview +- **Preset Themes**: Choose from built-in themes (Default Purple, Business Blue, Dark Mode) - **Remember Me**: Visitors stay authenticated for a configurable duration - **Secure Cookie Handling**: Uses SHA256 hashing with WordPress salts for cookie security - **Native WordPress Methods**: Built using WordPress Settings API and password functions + + ## Installation 1. Upload the `passwp-posts` folder to `/wp-content/plugins/` @@ -20,7 +24,7 @@ A WordPress plugin for password protecting your site's content. Protect all page ## Configuration -### Settings +### General Settings | Setting | Description | |---------|-------------| @@ -31,6 +35,19 @@ A WordPress plugin for password protecting your site's content. Protect all page | **Excluded Pages/Posts** | When protecting all: select pages/posts to exclude | | **Protected Pages/Posts** | When protecting selected: choose which pages/posts to protect | +### Customize Settings + +| Setting | Description | +|---------|-------------| +| **Preset Themes** | Quick-apply themes: Default Purple, Business Blue, Dark Mode | +| **Background** | Background color, gradient, and optional background image | +| **Card Styling** | Card background color, border radius, and shadow | +| **Logo** | Upload a custom logo with adjustable width | +| **Typography** | Heading text, colors, and font family | +| **Button** | Button text, colors, and border radius | +| **Form Options** | Show/hide "Remember Me" checkbox, input border radius | +| **Footer** | Custom footer text and link URL | + ## How It Works 1. When a visitor tries to access a protected page or post, they are shown a password form @@ -89,9 +106,11 @@ passwp-posts/ ├── assets/ │ ├── css/ │ │ ├── admin.css +│ │ ├── customize-admin.css │ │ └── password-form.css │ ├── js/ -│ │ └── admin.js +│ │ ├── admin.js +│ │ └── customize.js │ └── vendor/ │ └── select2/ ├── includes/ diff --git a/assets/css/customize-admin.css b/assets/css/customize-admin.css new file mode 100644 index 0000000..cdcaf0c --- /dev/null +++ b/assets/css/customize-admin.css @@ -0,0 +1,461 @@ +/** + * PassWP Posts Customize Admin Styles. + * + * Styles for the Customize tab in admin settings. + * + * @package PassWP_Posts + */ + +/* Tab navigation */ +.nav-tab-wrapper { + margin-bottom: 20px; +} + +/* Two-column layout */ +.passwp-customize-wrapper { + display: grid; + grid-template-columns: 1fr 380px; + gap: 30px; + align-items: start; + margin-top: 20px; +} + +@media (max-width: 1200px) { + .passwp-customize-wrapper { + grid-template-columns: 1fr; + } +} + +/* Options column */ +.passwp-customize-options { + background: #fff; + border: 1px solid #c3c4c7; + border-radius: 4px; + padding: 0; +} + +/* Sections */ +.passwp-section { + padding: 20px; + border-bottom: 1px solid #e5e7eb; +} + +.passwp-section:last-child { + border-bottom: none; +} + +.passwp-section h2 { + margin: 0 0 15px; + padding: 0; + font-size: 14px; + font-weight: 600; + color: #1d2327; +} + +/* Settings grid - sections after presets */ +.passwp-settings-grid { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 0; + border-top: 1px solid #e5e7eb; +} + +@media (max-width: 1600px) { + .passwp-settings-grid { + grid-template-columns: repeat(2, 1fr); + } +} + +@media (max-width: 1200px) { + .passwp-settings-grid { + grid-template-columns: 1fr; + } +} + +.passwp-settings-grid .passwp-section { + border-bottom: 1px solid #e5e7eb; + border-right: 1px solid #e5e7eb; +} + +.passwp-settings-grid .passwp-section:nth-child(3n) { + border-right: none; +} + +@media (max-width: 1600px) { + .passwp-settings-grid .passwp-section:nth-child(3n) { + border-right: 1px solid #e5e7eb; + } + + .passwp-settings-grid .passwp-section:nth-child(2n) { + border-right: none; + } +} + +@media (max-width: 1200px) { + .passwp-settings-grid .passwp-section { + border-right: none; + } +} + +.passwp-settings-grid .passwp-section:last-child { + border-bottom: none; +} + +/* Preset themes */ +.passwp-presets { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 12px; +} + +@media (max-width: 782px) { + .passwp-presets { + grid-template-columns: 1fr 1fr; + } +} + +.passwp-preset-card { + display: flex; + flex-direction: column; + align-items: center; + border: 2px solid #dcdcde; + border-radius: 8px; + padding: 12px; + cursor: pointer; + transition: border-color 0.2s, box-shadow 0.2s; + background: #fff; +} + +.passwp-preset-card:hover { + border-color: #2271b1; +} + +.passwp-preset-card.active { + border-color: #2271b1; + box-shadow: 0 0 0 1px #2271b1; +} + +.passwp-preset-preview { + display: block; + width: 100%; + height: 50px; + border-radius: 4px; + margin-bottom: 8px; +} + +.passwp-preset-name { + display: block; + font-weight: 500; + text-align: center; + font-size: 12px; + color: #1e1e1e; +} + +/* Form rows */ +.passwp-form-row { + margin-bottom: 16px; +} + +.passwp-form-row:last-child { + margin-bottom: 0; +} + +.passwp-form-row>label { + display: block; + margin-bottom: 6px; + font-weight: 500; + font-size: 13px; + color: #1d2327; +} + +.passwp-form-row .description { + margin-top: 6px; + color: #646970; + font-size: 12px; + font-style: italic; +} + +/* Color picker adjustments */ +.passwp-form-row .wp-picker-container { + display: block; +} + +.passwp-form-row .wp-picker-container .wp-color-result.button { + margin: 0; +} + +/* Range slider */ +.passwp-range-wrapper { + display: flex; + align-items: center; + gap: 12px; +} + +.passwp-range-wrapper input[type="range"] { + flex: 1; + max-width: 200px; + margin: 0; +} + +.passwp-range-value { + min-width: 50px; + color: #50575e; + font-size: 13px; + font-weight: 500; +} + +/* Toggle switch */ +.passwp-toggle { + position: relative; + display: inline-block; + width: 44px; + height: 24px; + cursor: pointer; +} + +.passwp-toggle input { + opacity: 0; + width: 0; + height: 0; +} + +.passwp-toggle-slider { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: #ccc; + border-radius: 24px; + transition: 0.3s; +} + +.passwp-toggle-slider::before { + position: absolute; + content: ""; + height: 18px; + width: 18px; + left: 3px; + bottom: 3px; + background-color: #fff; + border-radius: 50%; + transition: 0.3s; +} + +.passwp-toggle input:checked+.passwp-toggle-slider { + background-color: #2271b1; +} + +.passwp-toggle input:checked+.passwp-toggle-slider::before { + transform: translateX(20px); +} + +.passwp-toggle input:focus+.passwp-toggle-slider { + box-shadow: 0 0 0 2px #fff, 0 0 0 4px #2271b1; +} + +/* Media uploader */ +.passwp-media-upload { + display: flex; + align-items: center; + gap: 10px; + flex-wrap: wrap; +} + +.passwp-media-upload .button { + margin: 0; +} + +.passwp-media-preview { + width: 80px; + height: 50px; + border-radius: 4px; + border: 1px solid #dcdcde; + background: #f0f0f1; + display: flex; + align-items: center; + justify-content: center; + overflow: hidden; +} + +.passwp-media-preview img { + max-width: 100%; + max-height: 100%; + object-fit: contain; +} + +.passwp-media-preview:empty::before { + content: "—"; + color: #a7aaad; + font-size: 18px; +} + +/* Text inputs */ +.passwp-form-row input[type="text"], +.passwp-form-row input[type="url"] { + width: 100%; + max-width: 100%; +} + +.passwp-form-row input.regular-text { + width: 100%; + max-width: 100%; +} + +.passwp-form-row select { + width: 100%; + max-width: 100%; +} + +/* Actions section */ +.passwp-section.passwp-actions { + display: flex; + justify-content: space-between; + align-items: center; + background: #f6f7f7; + border-top: 1px solid #c3c4c7; + border-bottom: none; +} + +#passwp-reset-customize { + color: #b32d2e; + border-color: #b32d2e; +} + +#passwp-reset-customize:hover { + background: #b32d2e; + color: #fff; + border-color: #b32d2e; +} + +/* Preview column */ +.passwp-preview-wrapper { + position: sticky; + top: 50px; +} + +.passwp-preview-wrapper h2 { + margin: 0 0 12px; + font-size: 14px; + font-weight: 600; + color: #1d2327; +} + +#passwp-preview-container { + border: 1px solid #c3c4c7; + border-radius: 8px; + overflow: hidden; + background: #1e1e1e; +} + +.passwp-preview-frame { + padding: 20px; + min-height: 400px; + display: flex; + align-items: center; + justify-content: center; +} + +/* Preview content styles */ +.passwp-preview-bg { + width: 100%; + min-height: 360px; + display: flex; + align-items: center; + justify-content: center; + border-radius: 4px; + padding: 20px; + box-sizing: border-box; +} + +.passwp-preview-card { + background: #fff; + padding: 30px; + width: 100%; + max-width: 280px; + text-align: center; +} + +.passwp-preview-logo { + margin-bottom: 16px; + max-width: 100%; + height: auto; +} + +.passwp-preview-heading { + margin: 0 0 8px; + font-size: 18px; + font-weight: 600; +} + +.passwp-preview-text { + margin: 0 0 16px; + font-size: 13px; +} + +.passwp-preview-form { + text-align: left; +} + +.passwp-preview-form input[type="password"] { + width: 100%; + padding: 10px 12px; + margin-bottom: 12px; + border: 1px solid #ddd; + font-size: 14px; + box-sizing: border-box; +} + +.passwp-preview-remember { + display: flex; + align-items: center; + gap: 6px; + margin-bottom: 12px; + font-size: 12px; +} + +.passwp-preview-remember input { + margin: 0; +} + +.passwp-preview-form button { + width: 100%; + padding: 10px 16px; + border: none; + font-size: 14px; + font-weight: 600; + cursor: pointer; +} + +.passwp-preview-footer { + margin-top: 16px; + font-size: 12px; +} + +.passwp-preview-footer a { + text-decoration: none; +} + +.passwp-preview-footer a:hover { + text-decoration: underline; +} + +/* Responsive adjustments */ +@media (max-width: 782px) { + .passwp-customize-wrapper { + gap: 20px; + } + + .passwp-section { + padding: 15px; + } + + .passwp-preview-wrapper { + position: relative; + top: 0; + } + + .passwp-preview-frame { + min-height: 300px; + } +} \ No newline at end of file diff --git a/assets/css/password-form.css b/assets/css/password-form.css index 9dfcaa4..1dafe11 100644 --- a/assets/css/password-form.css +++ b/assets/css/password-form.css @@ -4,6 +4,22 @@ * @package PassWP_Posts */ +/* CSS Custom Properties (defaults - overridden by inline styles) */ +:root { + --passwp-bg-color: #667eea; + --passwp-bg-gradient-end: #764ba2; + --passwp-card-bg-color: #ffffff; + --passwp-card-border-radius: 12px; + --passwp-card-shadow: 0 20px 60px rgba(0, 0, 0, 0.2); + --passwp-heading-color: #1e1e1e; + --passwp-text-color: #666666; + --passwp-font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; + --passwp-button-bg-color: #667eea; + --passwp-button-text-color: #ffffff; + --passwp-button-border-radius: 8px; + --passwp-input-border-radius: 8px; +} + /* Reset and base styles */ .passwp-posts-body { margin: 0; @@ -12,11 +28,11 @@ display: flex; align-items: center; justify-content: center; - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; + font-family: var(--passwp-font-family); font-size: 14px; line-height: 1.5; - color: #1e1e1e; - background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + color: var(--passwp-heading-color); + background: linear-gradient(135deg, var(--passwp-bg-color) 0%, var(--passwp-bg-gradient-end) 100%); background-attachment: fixed; } @@ -30,12 +46,23 @@ /* Card */ .passwp-posts-card { - background: #fff; - border-radius: 12px; - box-shadow: 0 20px 60px rgba(0, 0, 0, 0.2); + background: var(--passwp-card-bg-color); + border-radius: var(--passwp-card-border-radius); + box-shadow: var(--passwp-card-shadow); overflow: hidden; } +/* Logo */ +.passwp-posts-logo { + padding: 24px 24px 0; + text-align: center; +} + +.passwp-posts-logo img { + max-width: 100%; + height: auto; +} + /* Header */ .passwp-posts-header { padding: 24px 24px 0; @@ -65,7 +92,7 @@ margin: 0; font-size: 18px; font-weight: 600; - color: #1e1e1e; + color: var(--passwp-heading-color); } /* Content */ @@ -78,7 +105,7 @@ display: flex; justify-content: center; margin-bottom: 16px; - color: #667eea; + color: var(--passwp-button-bg-color); } /* Title and description */ @@ -87,13 +114,13 @@ font-size: 24px; font-weight: 600; text-align: center; - color: #1e1e1e; + color: var(--passwp-heading-color); } .passwp-posts-description { margin: 0 0 24px; text-align: center; - color: #666; + color: var(--passwp-text-color); font-size: 14px; } @@ -132,10 +159,10 @@ font-size: 16px; font-family: inherit; line-height: 1.5; - color: #1e1e1e; + color: var(--passwp-heading-color); background: #f9fafb; border: 2px solid #e5e7eb; - border-radius: 8px; + border-radius: var(--passwp-input-border-radius); box-sizing: border-box; transition: border-color 0.15s ease, background-color 0.15s ease; } @@ -143,7 +170,7 @@ .passwp-posts-input:focus { outline: none; background: #fff; - border-color: #667eea; + border-color: var(--passwp-button-bg-color); box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1); } @@ -162,7 +189,7 @@ gap: 8px; cursor: pointer; font-size: 14px; - color: #4b5563; + color: var(--passwp-text-color); } .passwp-posts-checkbox-label input[type="checkbox"] { @@ -170,7 +197,7 @@ height: 18px; margin: 0; cursor: pointer; - accent-color: #667eea; + accent-color: var(--passwp-button-bg-color); } /* Submit button */ @@ -182,17 +209,18 @@ font-weight: 600; font-family: inherit; line-height: 1.5; - color: #fff; - background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); + color: var(--passwp-button-text-color); + background: var(--passwp-button-bg-color); border: none; - border-radius: 8px; + border-radius: var(--passwp-button-border-radius); cursor: pointer; - transition: transform 0.15s ease, box-shadow 0.15s ease; + transition: transform 0.15s ease, box-shadow 0.15s ease, filter 0.15s ease; } .passwp-posts-submit:hover { transform: translateY(-1px); - box-shadow: 0 4px 12px rgba(102, 126, 234, 0.4); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2); + filter: brightness(1.1); } .passwp-posts-submit:active { @@ -213,11 +241,16 @@ } .passwp-posts-footer a { - color: #667eea; + color: var(--passwp-button-bg-color); text-decoration: none; font-size: 14px; } +.passwp-posts-footer span { + color: var(--passwp-text-color); + font-size: 14px; +} + .passwp-posts-footer a:hover { text-decoration: underline; } diff --git a/assets/js/customize.js b/assets/js/customize.js new file mode 100644 index 0000000..a57982a --- /dev/null +++ b/assets/js/customize.js @@ -0,0 +1,427 @@ +/** + * PassWP Posts Customize Tab JavaScript. + * + * Handles live preview, color pickers, media uploaders, and preset themes. + * + * @package PassWP_Posts + */ + +(function ($) { + 'use strict'; + + /** + * Escape HTML entities to prevent XSS. + * + * @param {string} str String to escape. + * @return {string} Escaped string. + */ + function escapeHtml(str) { + if (!str) return ''; + const div = document.createElement('div'); + div.textContent = str; + return div.innerHTML; + } + + /** + * Escape URL for use in attributes. + * + * @param {string} url URL to escape. + * @return {string} Escaped URL or empty string if invalid. + */ + function escapeUrl(url) { + if (!url) return ''; + try { + const parsed = new URL(url, window.location.origin); + // Only allow http, https, and data URLs (for images) + if (!['http:', 'https:', 'data:'].includes(parsed.protocol)) { + return ''; + } + return parsed.href; + } catch (e) { + return ''; + } + } + + // Preset theme definitions matching PHP field names. + const presets = { + default: { + bg_color: '#667eea', + bg_gradient_end: '#764ba2', + bg_image: '', + card_bg_color: '#ffffff', + card_border_radius: 16, + card_shadow: true, + logo: '', + logo_width: 120, + heading_text: '', + heading_color: '#1e1e1e', + text_color: '#666666', + font_family: 'system-ui, -apple-system, sans-serif', + button_text: '', + button_bg_color: '#667eea', + button_text_color: '#ffffff', + button_border_radius: 8, + show_remember_me: true, + input_border_radius: 8, + footer_text: '', + footer_link: '' + }, + 'business-blue': { + bg_color: '#2193b0', + bg_gradient_end: '#6dd5ed', + bg_image: '', + card_bg_color: '#ffffff', + card_border_radius: 12, + card_shadow: true, + logo: '', + logo_width: 120, + heading_text: '', + heading_color: '#1e1e1e', + text_color: '#666666', + font_family: 'system-ui, -apple-system, sans-serif', + button_text: '', + button_bg_color: '#2193b0', + button_text_color: '#ffffff', + button_border_radius: 6, + show_remember_me: true, + input_border_radius: 6, + footer_text: '', + footer_link: '' + }, + 'dark-mode': { + bg_color: '#1a1a2e', + bg_gradient_end: '', + bg_image: '', + card_bg_color: '#16213e', + card_border_radius: 16, + card_shadow: true, + logo: '', + logo_width: 120, + heading_text: '', + heading_color: '#e5e5e5', + text_color: '#a0a0a0', + font_family: 'system-ui, -apple-system, sans-serif', + button_text: '', + button_bg_color: '#6366f1', + button_text_color: '#ffffff', + button_border_radius: 8, + show_remember_me: true, + input_border_radius: 8, + footer_text: '', + footer_link: '' + } + }; + + /** + * Initialize customize functionality. + */ + function init() { + initColorPickers(); + initMediaUploaders(); + initPresetThemes(); + initRangeSliders(); + initLivePreview(); + initResetButton(); + } + + /** + * Initialize WordPress color pickers. + */ + function initColorPickers() { + $('.passwp-color-picker').wpColorPicker({ + change: function () { + setTimeout(updatePreview, 50); + }, + clear: function () { + setTimeout(updatePreview, 50); + } + }); + } + + /** + * Initialize WordPress media uploaders. + */ + function initMediaUploaders() { + $('.passwp-media-upload').each(function () { + const $wrapper = $(this); + const $input = $wrapper.find('input[type="hidden"]'); + const $preview = $wrapper.find('.passwp-media-preview'); + const $selectBtn = $wrapper.find('.passwp-media-select'); + const $removeBtn = $wrapper.find('.passwp-media-remove'); + + $selectBtn.on('click', function (e) { + e.preventDefault(); + + const frame = wp.media({ + title: passwpCustomize.selectImage || 'Select Image', + button: { text: passwpCustomize.useImage || 'Use this image' }, + multiple: false + }); + + frame.on('select', function () { + const attachment = frame.state().get('selection').first().toJSON(); + const safeUrl = escapeUrl(attachment.url); + $input.val(safeUrl); + $preview.empty(); + if (safeUrl) { + $('', { src: safeUrl, alt: '' }).appendTo($preview); + } + $removeBtn.show(); + updatePreview(); + }); + + frame.open(); + }); + + $removeBtn.on('click', function (e) { + e.preventDefault(); + $input.val(''); + $preview.empty(); + $(this).hide(); + updatePreview(); + }); + }); + } + + /** + * Initialize preset theme selection. + */ + function initPresetThemes() { + $('.passwp-preset-card').on('click', function () { + const preset = $(this).data('preset'); + if (!presets[preset]) return; + + $('.passwp-preset-card').removeClass('active'); + $(this).addClass('active'); + + applyPreset(presets[preset]); + updatePreview(); + }); + } + + /** + * Apply preset values to form fields. + */ + function applyPreset(values) { + // Color fields. + setColorPickerValue('#passwp_bg_color', values.bg_color); + setColorPickerValue('#passwp_bg_gradient_end', values.bg_gradient_end); + setColorPickerValue('#passwp_card_bg_color', values.card_bg_color); + setColorPickerValue('#passwp_heading_color', values.heading_color); + setColorPickerValue('#passwp_text_color', values.text_color); + setColorPickerValue('#passwp_button_bg_color', values.button_bg_color); + setColorPickerValue('#passwp_button_text_color', values.button_text_color); + + // Range sliders. + $('#passwp_card_border_radius').val(values.card_border_radius).trigger('input'); + $('#passwp_button_border_radius').val(values.button_border_radius).trigger('input'); + $('#passwp_input_border_radius').val(values.input_border_radius).trigger('input'); + $('#passwp_logo_width').val(values.logo_width).trigger('input'); + + // Checkboxes. + $('#passwp_card_shadow').prop('checked', values.card_shadow); + $('#passwp_show_remember_me').prop('checked', values.show_remember_me); + + // Select. + $('#passwp_font_family').val(values.font_family); + + // Text fields. + $('#passwp_heading_text').val(values.heading_text); + $('#passwp_button_text').val(values.button_text); + $('#passwp_footer_text').val(values.footer_text); + $('#passwp_footer_link').val(values.footer_link); + } + + /** + * Set color picker value programmatically. + */ + function setColorPickerValue(selector, value) { + const $input = $(selector); + if ($input.length) { + $input.val(value); + if ($input.hasClass('wp-color-picker')) { + $input.wpColorPicker('color', value); + } + } + } + + /** + * Initialize range sliders. + */ + function initRangeSliders() { + $('input[type="range"]').on('input', function () { + $(this).closest('.passwp-range-wrapper').find('.passwp-range-value').text($(this).val() + 'px'); + updatePreview(); + }); + } + + /** + * Initialize live preview updates. + */ + function initLivePreview() { + // Debounced update for text fields. + let debounceTimer; + $('#passwp-customize-form').on('input', 'input[type="text"], input[type="url"]', function () { + clearTimeout(debounceTimer); + debounceTimer = setTimeout(updatePreview, 150); + }); + + // Immediate update for selects and checkboxes. + $('#passwp-customize-form').on('change', 'select, input[type="checkbox"]', updatePreview); + } + + /** + * Update the live preview. + */ + function updatePreview() { + const $preview = $('.passwp-preview-frame'); + if (!$preview.length) return; + + // Get current values. + const bgColor = $('#passwp_bg_color').val() || '#667eea'; + const bgGradientEnd = $('#passwp_bg_gradient_end').val(); + const bgImage = $('#passwp_bg_image').val(); + const cardBgColor = $('#passwp_card_bg_color').val() || '#ffffff'; + const cardBorderRadius = $('#passwp_card_border_radius').val() || 16; + const cardShadow = $('#passwp_card_shadow').is(':checked'); + const logo = $('#passwp_logo').val(); + const logoWidth = $('#passwp_logo_width').val() || 120; + const headingText = $('#passwp_heading_text').val(); + const headingColor = $('#passwp_heading_color').val() || '#1e1e1e'; + const textColor = $('#passwp_text_color').val() || '#666666'; + const fontFamily = $('#passwp_font_family').val() || 'system-ui, -apple-system, sans-serif'; + const buttonText = $('#passwp_button_text').val(); + const buttonBgColor = $('#passwp_button_bg_color').val() || '#667eea'; + const buttonTextColor = $('#passwp_button_text_color').val() || '#ffffff'; + const buttonBorderRadius = $('#passwp_button_border_radius').val() || 8; + const showRememberMe = $('#passwp_show_remember_me').is(':checked'); + const inputBorderRadius = $('#passwp_input_border_radius').val() || 8; + const footerText = $('#passwp_footer_text').val(); + const footerLink = $('#passwp_footer_link').val(); + + // Build background style. + let bgStyle; + const safeBgImage = escapeUrl(bgImage); + if (safeBgImage) { + bgStyle = 'url(' + safeBgImage + ') center/cover no-repeat'; + } else if (bgGradientEnd) { + bgStyle = 'linear-gradient(135deg, ' + bgColor + ' 0%, ' + bgGradientEnd + ' 100%)'; + } else { + bgStyle = bgColor; + } + + // Build card shadow. + const shadowStyle = cardShadow ? '0 10px 40px rgba(0, 0, 0, 0.2)' : 'none'; + + // Update preview elements. + $preview.find('.passwp-preview-bg').css({ + 'background': bgStyle, + 'font-family': fontFamily + }); + + $preview.find('.passwp-preview-card').css({ + 'background-color': cardBgColor, + 'border-radius': cardBorderRadius + 'px', + 'box-shadow': shadowStyle + }); + + // Logo. + const $logoImg = $preview.find('.passwp-preview-logo'); + const safeLogo = escapeUrl(logo); + if (safeLogo) { + if ($logoImg.length) { + $logoImg.attr('src', safeLogo).css('width', logoWidth + 'px').show(); + } else { + $('', { + src: safeLogo, + alt: '', + 'class': 'passwp-preview-logo', + css: { width: logoWidth + 'px' } + }).prependTo($preview.find('.passwp-preview-card')); + } + } else { + $logoImg.hide(); + } + + // Heading. + $preview.find('.passwp-preview-heading').css('color', headingColor); + if (headingText) { + $preview.find('.passwp-preview-heading').text(headingText); + } + + // Text. + $preview.find('.passwp-preview-text').css('color', textColor); + + // Form input. + $preview.find('.passwp-preview-form input[type="password"]').css('border-radius', inputBorderRadius + 'px'); + + // Remember me. + $preview.find('.passwp-preview-remember').toggle(showRememberMe).css('color', textColor); + + // Button. + $preview.find('.passwp-preview-form button').css({ + 'background-color': buttonBgColor, + 'color': buttonTextColor, + 'border-radius': buttonBorderRadius + 'px' + }); + if (buttonText) { + $preview.find('.passwp-preview-form button').text(buttonText); + } + + // Footer. + const $footer = $preview.find('.passwp-preview-footer'); + $footer.empty(); + if (footerText) { + const safeFooterLink = escapeUrl(footerLink); + if (safeFooterLink) { + $('', { + href: safeFooterLink, + text: footerText, + css: { color: buttonBgColor } + }).appendTo($footer); + } else { + $('', { + text: footerText, + css: { color: textColor } + }).appendTo($footer); + } + } else { + $('', { + href: '#', + html: '← Back to home', + css: { color: buttonBgColor } + }).appendTo($footer); + } + } + + /** + * Initialize reset button. + */ + function initResetButton() { + $('#passwp-reset-customize').on('click', function (e) { + e.preventDefault(); + + if (!confirm(passwpCustomize.resetConfirm || 'Are you sure you want to reset all settings to defaults?')) { + return; + } + + // Apply default preset. + applyPreset(presets.default); + + // Clear image fields. + $('#passwp_bg_image, #passwp_logo').val(''); + $('.passwp-media-preview').empty(); + $('.passwp-media-remove').hide(); + + // Update UI. + $('.passwp-preset-card').removeClass('active'); + $('.passwp-preset-card[data-preset="default"]').addClass('active'); + + updatePreview(); + }); + } + + // Initialize when document is ready. + $(document).ready(init); + +})(jQuery); diff --git a/customize.png b/customize.png new file mode 100644 index 0000000..41a8014 Binary files /dev/null and b/customize.png differ diff --git a/includes/class-admin-settings.php b/includes/class-admin-settings.php index 53f3b69..9f54eec 100644 --- a/includes/class-admin-settings.php +++ b/includes/class-admin-settings.php @@ -31,6 +31,34 @@ final class Admin_Settings { */ private const PAGE_SLUG = 'passwp-posts-settings'; + /** + * Default customize settings. + * + * @var array + */ + private const CUSTOMIZE_DEFAULTS = [ + 'bg_color' => '#667eea', + 'bg_gradient_end' => '#764ba2', + 'bg_image' => '', + 'card_bg_color' => '#ffffff', + 'card_border_radius' => 12, + 'card_shadow' => true, + 'logo' => '', + 'logo_width' => 120, + 'heading_text' => '', + 'heading_color' => '#1a1a2e', + 'text_color' => '#4a5568', + 'font_family' => 'system-ui, -apple-system, sans-serif', + 'button_text' => '', + 'button_bg_color' => '#667eea', + 'button_text_color' => '#ffffff', + 'button_border_radius' => 8, + 'show_remember_me' => true, + 'input_border_radius' => 8, + 'footer_text' => '', + 'footer_link_url' => '', + ]; + /** * Constructor. */ @@ -66,14 +94,7 @@ public function register_settings(): void { args: [ 'type' => 'array', 'sanitize_callback' => $this->sanitize_settings( ... ), - 'default' => [ - 'password_hash' => '', - 'cookie_expiry_days' => 30, - 'protection_mode' => 'all', - 'excluded_posts' => [], - 'protected_posts' => [], - 'enabled' => false, - ], + 'default' => $this->get_default_settings(), ] ); @@ -140,6 +161,34 @@ public function register_settings(): void { ); } + /** + * Get default settings. + * + * @return array + */ + private function get_default_settings(): array { + return [ + 'password_hash' => '', + 'cookie_expiry_days' => 30, + 'protection_mode' => 'all', + 'excluded_posts' => [], + 'protected_posts' => [], + 'enabled' => false, + 'customize' => self::CUSTOMIZE_DEFAULTS, + ]; + } + + /** + * Get customize settings with defaults. + * + * @return array + */ + public static function get_customize_settings(): array { + $settings = get_option( self::OPTION_NAME, [] ); + $customize = $settings[ 'customize' ] ?? []; + return array_merge( self::CUSTOMIZE_DEFAULTS, $customize ); + } + /** * Enqueue admin scripts and styles. * @@ -154,6 +203,9 @@ public function enqueue_admin_assets( string $hook ): void { // Use time() for cache busting in debug mode. $version = defined( 'WP_DEBUG' ) && WP_DEBUG ? (string) time() : PASSWP_POSTS_VERSION; + // Get current tab. + $current_tab = isset( $_GET[ 'tab' ] ) ? sanitize_key( $_GET[ 'tab' ] ) : 'general'; + // Select2 CSS. wp_enqueue_style( handle: 'select2', @@ -205,6 +257,47 @@ public function enqueue_admin_assets( string $hook ): void { 'protectionMode' => $protection_mode, ] ); + + // Customize tab assets. + if ( 'customize' === $current_tab ) { + // WordPress color picker. + wp_enqueue_style( 'wp-color-picker' ); + wp_enqueue_script( 'wp-color-picker' ); + + // WordPress media uploader. + wp_enqueue_media(); + + // Customize admin CSS. + wp_enqueue_style( + handle: 'passwp-posts-customize-admin', + src: PASSWP_POSTS_URL . 'assets/css/customize-admin.css', + deps: [ 'wp-color-picker' ], + ver: $version + ); + + // Customize JS. + wp_enqueue_script( + handle: 'passwp-posts-customize', + src: PASSWP_POSTS_URL . 'assets/js/customize.js', + deps: [ 'jquery', 'wp-color-picker' ], + ver: $version, + args: true + ); + + // Localize customize script. + wp_localize_script( + handle: 'passwp-posts-customize', + object_name: 'passwpCustomize', + l10n: [ + 'defaults' => self::CUSTOMIZE_DEFAULTS, + 'resetConfirm' => __( 'Are you sure you want to reset all customize settings to defaults?', 'passwp-posts' ), + 'selectImage' => __( 'Select Image', 'passwp-posts' ), + 'useImage' => __( 'Use this image', 'passwp-posts' ), + 'removeImage' => __( 'Remove', 'passwp-posts' ), + 'previewPasswordUrl' => add_query_arg( 'passwp-preview', '1', home_url( '/' ) ), + ] + ); + } } /** @@ -215,19 +308,437 @@ public function render_settings_page(): void { return; } + $current_tab = isset( $_GET[ 'tab' ] ) ? sanitize_key( $_GET[ 'tab' ] ) : 'general'; + $page_url = admin_url( 'options-general.php?page=' . self::PAGE_SLUG ); + ?> - - - + + + + + + + + + + render_customize_tab(); + } else { + $this->render_general_tab(); + } + ?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + > + + + + + + + + + + + + + + + + + + px + + + + + + + /> + + + + + + + + + + + + + + + + + + + + > + + + + + + + + px + + + + + + + + + + + + + + + + + + + + + + + + + + + > + + + > + + + > + + + > + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + px + + + + + + + + + + + + /> + + + + + + + + + px + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + render_preview_content( $settings ); ?> + + + + + + $settings The customize settings. + */ + private function render_preview_content( array $settings ): void { + $bg_style = ''; + if ( ! empty( $settings[ 'bg_image' ] ) ) { + $bg_style = sprintf( 'background-image: url(%s); background-size: cover; background-position: center;', esc_url( $settings[ 'bg_image' ] ) ); + } elseif ( ! empty( $settings[ 'bg_gradient_end' ] ) ) { + $bg_style = sprintf( 'background: linear-gradient(135deg, %s 0%%, %s 100%%);', esc_attr( $settings[ 'bg_color' ] ), esc_attr( $settings[ 'bg_gradient_end' ] ) ); + } else { + $bg_style = sprintf( 'background-color: %s;', esc_attr( $settings[ 'bg_color' ] ) ); + } + + $card_style = sprintf( + 'background-color: %s; border-radius: %dpx;%s', + esc_attr( $settings[ 'card_bg_color' ] ), + absint( $settings[ 'card_border_radius' ] ), + $settings[ 'card_shadow' ] ? ' box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2);' : '' + ); + ?> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ← + + + + sanitize_customize_settings( $input[ 'customize' ] ?? [] ); + + // Preserve existing general settings when saving from customize tab. + if ( isset( $input[ '_customize_tab' ] ) ) { + $sanitized[ 'enabled' ] = $existing[ 'enabled' ] ?? false; + $sanitized[ 'password_hash' ] = $existing[ 'password_hash' ] ?? ''; + $sanitized[ 'cookie_expiry_days' ] = $existing[ 'cookie_expiry_days' ] ?? 30; + $sanitized[ 'protection_mode' ] = $existing[ 'protection_mode' ] ?? 'all'; + $sanitized[ 'excluded_posts' ] = $existing[ 'excluded_posts' ] ?? []; + $sanitized[ 'protected_posts' ] = $existing[ 'protected_posts' ] ?? []; + } + } elseif ( ! empty( $existing[ 'customize' ] ) ) { + // Preserve existing customize settings when saving from general tab. + $sanitized[ 'customize' ] = $existing[ 'customize' ]; + } + return $sanitized; } + /** + * Sanitize customize settings. + * + * @param array $input Raw customize input. + * @return array Sanitized customize settings. + */ + private function sanitize_customize_settings( array $input ): array { + $sanitized = []; + + // Colors - sanitize as hex colors. + $color_fields = [ + 'bg_color', + 'bg_gradient_end', + 'card_bg_color', + 'heading_color', + 'text_color', + 'button_bg_color', + 'button_text_color', + ]; + + foreach ( $color_fields as $field ) { + $value = $input[ $field ] ?? self::CUSTOMIZE_DEFAULTS[ $field ]; + $sanitized[ $field ] = $this->sanitize_hex_color( $value ); + } + + // URLs - sanitize as URLs. + $url_fields = [ 'bg_image', 'logo', 'footer_link' ]; + foreach ( $url_fields as $field ) { + $sanitized[ $field ] = esc_url_raw( $input[ $field ] ?? '' ); + } + + // Integers - sanitize as integers with min/max. + $sanitized[ 'card_border_radius' ] = $this->sanitize_int_range( $input[ 'card_border_radius' ] ?? 16, 0, 50 ); + $sanitized[ 'button_border_radius' ] = $this->sanitize_int_range( $input[ 'button_border_radius' ] ?? 8, 0, 30 ); + $sanitized[ 'input_border_radius' ] = $this->sanitize_int_range( $input[ 'input_border_radius' ] ?? 8, 0, 20 ); + $sanitized[ 'logo_width' ] = $this->sanitize_int_range( $input[ 'logo_width' ] ?? 120, 50, 300 ); + + // Booleans. + $sanitized[ 'card_shadow' ] = ! empty( $input[ 'card_shadow' ] ); + $sanitized[ 'show_remember_me' ] = ! empty( $input[ 'show_remember_me' ] ); + + // Text fields. + $sanitized[ 'heading_text' ] = sanitize_text_field( $input[ 'heading_text' ] ?? '' ); + $sanitized[ 'button_text' ] = sanitize_text_field( $input[ 'button_text' ] ?? '' ); + $sanitized[ 'footer_text' ] = sanitize_text_field( $input[ 'footer_text' ] ?? '' ); + + // Font family - allow only safe values. + $allowed_fonts = [ + 'system-ui, -apple-system, sans-serif', + "'Segoe UI', Tahoma, Geneva, Verdana, sans-serif", + "Georgia, 'Times New Roman', serif", + "'Courier New', Courier, monospace", + ]; + $font_family = $input[ 'font_family' ] ?? self::CUSTOMIZE_DEFAULTS[ 'font_family' ]; + $sanitized[ 'font_family' ] = in_array( $font_family, $allowed_fonts, true ) ? $font_family : self::CUSTOMIZE_DEFAULTS[ 'font_family' ]; + + return $sanitized; + } + + /** + * Sanitize hex color. + * + * @param string $color Color value. + * @return string Sanitized color or empty string. + */ + private function sanitize_hex_color( string $color ): string { + if ( empty( $color ) ) { + return ''; + } + + // Handle rgba format. + if ( preg_match( '/^rgba?\([^)]+\)$/', $color ) ) { + return $color; + } + + // 3 or 6 hex digits, or the empty string. + if ( preg_match( '/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/', $color ) ) { + return $color; + } + + return ''; + } + + /** + * Sanitize integer within a range. + * + * @param mixed $value Value to sanitize. + * @param int $min Minimum value. + * @param int $max Maximum value. + * @return int Sanitized integer. + */ + private function sanitize_int_range( mixed $value, int $min, int $max ): int { + return max( $min, min( $max, absint( $value ) ) ); + } + /** * AJAX handler for searching posts. */ diff --git a/languages/passwp-posts-nb_NO.l10n.php b/languages/passwp-posts-nb_NO.l10n.php index 7184690..3463287 100644 --- a/languages/passwp-posts-nb_NO.l10n.php +++ b/languages/passwp-posts-nb_NO.l10n.php @@ -1,2 +1,2 @@ 'passwp-posts','plural-forms'=>'nplurals=2; plural=(n != 1);','language'=>'nb_NO','project-id-version'=>'PassWP Posts 1.0.1','pot-creation-date'=>'2025-12-11T22:48:24+00:00','po-revision-date'=>'2025-12-11 23:50+0100','x-generator'=>'WP-CLI 2.12.0','messages'=>['PassWP Posts'=>'PassWP Posts','https://developer.suspended.no/passwp-posts'=>'https://developer.suspended.no/passwp-posts','Password protects all pages and posts except the front page. Logged-in users bypass the password.'=>'Passordbeskytter alle sider og innlegg unntatt forsiden. Innloggede brukere omgår passordet.','Per Soderlind'=>'Per Soderlind','https://soderlind.no'=>'https://soderlind.no','PassWP Posts Settings'=>'PassWP Posts-innstillinger','Password Protection Settings'=>'Innstillinger for passordbeskyttelse','Enable Protection'=>'Aktiver beskyttelse','Password'=>'Passord','Remember Me Duration'=>'Varighet for «Husk meg»','Protection Mode'=>'Beskyttelsesmodus','Excluded Pages/Posts'=>'Ekskluderte sider/innlegg','Protected Pages/Posts'=>'Beskyttede sider/innlegg','Search for pages or posts...'=>'Søk etter sider eller innlegg...','Show password'=>'Vis passord','Hide password'=>'Skjul passord','Save Settings'=>'Lagre innstillinger','Configure password protection for your site. The front page is always public. Logged-in users bypass the password.'=>'Konfigurer passordbeskyttelse for nettstedet ditt. Forsiden er alltid offentlig. Innloggede brukere omgår passordet.','Enable password protection'=>'Aktiver passordbeskyttelse','When enabled, visitors must enter a password to view protected content.'=>'Når aktivert, må besøkende taste inn et passord for å se beskyttet innhold.','Leave blank to keep current password'=>'La stå tomt for å beholde nåværende passord','Enter password'=>'Skriv inn passord','Toggle password visibility'=>'Veksle passordsynlighet','A password is currently set. Enter a new password to change it, or leave blank to keep the current password.'=>'Et passord er allerede satt. Skriv inn et nytt passord for å endre det, eller la stå tomt for å beholde nåværende passord.','Enter the password visitors will use to access protected content.'=>'Skriv inn passordet besøkende skal bruke for å få tilgang til beskyttet innhold.','days'=>'dager','How long visitors stay authenticated after entering the password.'=>'Hvor lenge besøkende forblir autentisert etter å ha tastet inn passordet.','Protect all pages and posts (except front page)'=>'Beskytt alle sider og innlegg (unntatt forsiden)','Protect only selected pages and posts'=>'Beskytt kun valgte sider og innlegg','These pages and posts will not require a password.'=>'Disse sidene og innleggene vil ikke kreve passord.','Only these pages and posts will require a password.'=>'Kun disse sidene og innleggene vil kreve passord.','Permission denied.'=>'Tilgang nektet.','Security check failed.'=>'Sikkerhetssjekk mislyktes.','Incorrect password. Please try again.'=>'Feil passord. Vennligst prøv igjen.','No password has been configured. Please contact the site administrator.'=>'Ingen passord er konfigurert. Vennligst kontakt nettstedets administrator.','Password Required - %s'=>'Passord påkrevd - %s','Password Required'=>'Passord påkrevd','This content is protected. Please enter the password to continue.'=>'Dette innholdet er beskyttet. Vennligst skriv inn passordet for å fortsette.','Remember me'=>'Husk meg','Submit'=>'Send inn','Back to home'=>'Tilbake til forsiden']]; \ No newline at end of file +return ['domain'=>'passwp-posts','plural-forms'=>'nplurals=2; plural=(n != 1);','language'=>'nb_NO','project-id-version'=>'PassWP Posts 1.0.1','pot-creation-date'=>'2025-12-11T22:48:24+00:00','po-revision-date'=>'2025-12-11 23:50+0100','x-generator'=>'WP-CLI 2.12.0','messages'=>['PassWP Posts'=>'PassWP Posts','https://developer.suspended.no/passwp-posts'=>'https://developer.suspended.no/passwp-posts','Password protects all pages and posts except the front page. Logged-in users bypass the password.'=>'Passordbeskytter alle sider og innlegg unntatt forsiden. Innloggede brukere omgår passordet.','Per Soderlind'=>'Per Soderlind','https://soderlind.no'=>'https://soderlind.no','PassWP Posts Settings'=>'PassWP Posts-innstillinger','Password Protection Settings'=>'Innstillinger for passordbeskyttelse','Enable Protection'=>'Aktiver beskyttelse','Password'=>'Passord','Remember Me Duration'=>'Varighet for «Husk meg»','Protection Mode'=>'Beskyttelsesmodus','Excluded Pages/Posts'=>'Ekskluderte sider/innlegg','Protected Pages/Posts'=>'Beskyttede sider/innlegg','Search for pages or posts...'=>'Søk etter sider eller innlegg...','Show password'=>'Vis passord','Hide password'=>'Skjul passord','Save Settings'=>'Lagre innstillinger','Configure password protection for your site. The front page is always public. Logged-in users bypass the password.'=>'Konfigurer passordbeskyttelse for nettstedet ditt. Forsiden er alltid offentlig. Innloggede brukere omgår passordet.','Enable password protection'=>'Aktiver passordbeskyttelse','When enabled, visitors must enter a password to view protected content.'=>'Når aktivert, må besøkende taste inn et passord for å se beskyttet innhold.','Leave blank to keep current password'=>'La stå tomt for å beholde nåværende passord','Enter password'=>'Skriv inn passord','Toggle password visibility'=>'Veksle passordsynlighet','A password is currently set. Enter a new password to change it, or leave blank to keep the current password.'=>'Et passord er allerede satt. Skriv inn et nytt passord for å endre det, eller la stå tomt for å beholde nåværende passord.','Enter the password visitors will use to access protected content.'=>'Skriv inn passordet besøkende skal bruke for å få tilgang til beskyttet innhold.','days'=>'dager','How long visitors stay authenticated after entering the password.'=>'Hvor lenge besøkende forblir autentisert etter å ha tastet inn passordet.','Protect all pages and posts (except front page)'=>'Beskytt alle sider og innlegg (unntatt forsiden)','Protect only selected pages and posts'=>'Beskytt kun valgte sider og innlegg','These pages and posts will not require a password.'=>'Disse sidene og innleggene vil ikke kreve passord.','Only these pages and posts will require a password.'=>'Kun disse sidene og innleggene vil kreve passord.','Permission denied.'=>'Tilgang nektet.','Security check failed.'=>'Sikkerhetssjekk mislyktes.','Incorrect password. Please try again.'=>'Feil passord. Vennligst prøv igjen.','No password has been configured. Please contact the site administrator.'=>'Ingen passord er konfigurert. Vennligst kontakt nettstedets administrator.','Password Required - %s'=>'Passord påkrevd - %s','Password Required'=>'Passord påkrevd','This content is protected. Please enter the password to continue.'=>'Dette innholdet er beskyttet. Vennligst skriv inn passordet for å fortsette.','Remember me'=>'Husk meg','Submit'=>'Send inn','Back to home'=>'Tilbake til forsiden','Are you sure you want to reset all customize settings to defaults?'=>'Er du sikker på at du vil tilbakestille alle tilpasningsinnstillinger til standard?','Select Image'=>'Velg bilde','Use this image'=>'Bruk dette bildet','Remove'=>'Fjern','General'=>'Generelt','Customize'=>'Tilpass','Preset Themes'=>'Forhåndsdefinerte temaer','Default Purple'=>'Standard lilla','Business Blue'=>'Profesjonell blå','Dark Mode'=>'Mørk modus','Background'=>'Bakgrunn','Background Color'=>'Bakgrunnsfarge','Gradient End Color'=>'Gradient sluttfarge','Leave empty for solid color background.'=>'La stå tom for ensfarget bakgrunn.','Background Image'=>'Bakgrunnsbilde','Card Styling'=>'Kortstil','Card Background Color'=>'Kortets bakgrunnsfarge','Card Border Radius'=>'Kortets hjørneradius','Card Shadow'=>'Kortskygge','Logo'=>'Logo','Logo Image'=>'Logobilde','Logo Width'=>'Logobredde','Typography'=>'Typografi','Heading Text'=>'Overskriftstekst','Heading Color'=>'Overskriftsfarge','Text Color'=>'Tekstfarge','Font Family'=>'Skrifttype','System Default'=>'Systemstandard','Segoe UI'=>'Segoe UI','Georgia'=>'Georgia','Courier New'=>'Courier New','Button'=>'Knapp','Button Text'=>'Knappetekst','Button Background Color'=>'Knappens bakgrunnsfarge','Button Text Color'=>'Knappens tekstfarge','Button Border Radius'=>'Knappens hjørneradius','Form Options'=>'Skjemavalg','Show Remember Me'=>'Vis «Husk meg»','Input Border Radius'=>'Inntastingsfeltets hjørneradius','Footer'=>'Bunntekst','Footer Text'=>'Bunntekst','Footer Link URL'=>'Bunntekst lenke-URL','Reset to Defaults'=>'Tilbakestill til standard','Live Preview'=>'Direktevisning','Password Protected'=>'Passordbeskyttet','Enter the password to access this content.'=>'Skriv inn passordet for å få tilgang til dette innholdet.']]; \ No newline at end of file diff --git a/languages/passwp-posts-nb_NO.mo b/languages/passwp-posts-nb_NO.mo index ed6531b..4e72467 100644 Binary files a/languages/passwp-posts-nb_NO.mo and b/languages/passwp-posts-nb_NO.mo differ diff --git a/languages/passwp-posts-nb_NO.po b/languages/passwp-posts-nb_NO.po index a19d279..ad793b7 100644 --- a/languages/passwp-posts-nb_NO.po +++ b/languages/passwp-posts-nb_NO.po @@ -1,26 +1,22 @@ -# Norwegian Bokmål translation for PassWP Posts. -# Copyright (C) 2025 Per Soderlind -# This file is distributed under the GPL-2.0+. -# msgid "" msgstr "" "Project-Id-Version: PassWP Posts 1.0.1\n" "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/passwp-posts\n" "Last-Translator: Per Soderlind \n" "Language-Team: Norwegian Bokmål\n" -"Language: nb_NO\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "POT-Creation-Date: 2025-12-11T22:48:24+00:00\n" "PO-Revision-Date: 2025-12-11 23:50+0100\n" +"Language: nb_NO\n" "X-Generator: WP-CLI 2.12.0\n" "X-Domain: passwp-posts\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #. Plugin Name of the plugin #: passwp-posts.php -#: includes/class-admin-settings.php:52 +#: includes/class-admin-settings.php:79 msgid "PassWP Posts" msgstr "PassWP Posts" @@ -44,113 +40,115 @@ msgstr "Per Soderlind" msgid "https://soderlind.no" msgstr "https://soderlind.no" -#: includes/class-admin-settings.php:51 +#: includes/class-admin-settings.php:78 msgid "PassWP Posts Settings" msgstr "PassWP Posts-innstillinger" -#: includes/class-admin-settings.php:83 +#: includes/class-admin-settings.php:103 msgid "Password Protection Settings" msgstr "Innstillinger for passordbeskyttelse" -#: includes/class-admin-settings.php:91 +#: includes/class-admin-settings.php:111 msgid "Enable Protection" msgstr "Aktiver beskyttelse" -#: includes/class-admin-settings.php:100 -#: templates/password-form.php:88 +#: includes/class-admin-settings.php:120 +#: includes/class-admin-settings.php:623 +#: templates/password-form.php:127 msgid "Password" msgstr "Passord" -#: includes/class-admin-settings.php:109 +#: includes/class-admin-settings.php:129 msgid "Remember Me Duration" msgstr "Varighet for «Husk meg»" -#: includes/class-admin-settings.php:118 +#: includes/class-admin-settings.php:138 msgid "Protection Mode" msgstr "Beskyttelsesmodus" -#: includes/class-admin-settings.php:127 +#: includes/class-admin-settings.php:147 msgid "Excluded Pages/Posts" msgstr "Ekskluderte sider/innlegg" -#: includes/class-admin-settings.php:136 +#: includes/class-admin-settings.php:156 msgid "Protected Pages/Posts" msgstr "Beskyttede sider/innlegg" -#: includes/class-admin-settings.php:202 +#: includes/class-admin-settings.php:253 msgid "Search for pages or posts..." msgstr "Søk etter sider eller innlegg..." -#: includes/class-admin-settings.php:203 +#: includes/class-admin-settings.php:254 msgid "Show password" msgstr "Vis passord" -#: includes/class-admin-settings.php:204 +#: includes/class-admin-settings.php:255 msgid "Hide password" msgstr "Skjul passord" -#: includes/class-admin-settings.php:228 +#: includes/class-admin-settings.php:348 +#: includes/class-admin-settings.php:566 msgid "Save Settings" msgstr "Lagre innstillinger" -#: includes/class-admin-settings.php:239 +#: includes/class-admin-settings.php:661 msgid "Configure password protection for your site. The front page is always public. Logged-in users bypass the password." msgstr "Konfigurer passordbeskyttelse for nettstedet ditt. Forsiden er alltid offentlig. Innloggede brukere omgår passordet." -#: includes/class-admin-settings.php:251 +#: includes/class-admin-settings.php:673 msgid "Enable password protection" msgstr "Aktiver passordbeskyttelse" -#: includes/class-admin-settings.php:254 +#: includes/class-admin-settings.php:676 msgid "When enabled, visitors must enter a password to view protected content." msgstr "Når aktivert, må besøkende taste inn et passord for å se beskyttet innhold." -#: includes/class-admin-settings.php:269 +#: includes/class-admin-settings.php:691 msgid "Leave blank to keep current password" msgstr "La stå tomt for å beholde nåværende passord" -#: includes/class-admin-settings.php:269 -#: templates/password-form.php:91 +#: includes/class-admin-settings.php:691 +#: templates/password-form.php:130 msgid "Enter password" msgstr "Skriv inn passord" -#: includes/class-admin-settings.php:272 +#: includes/class-admin-settings.php:694 msgid "Toggle password visibility" msgstr "Veksle passordsynlighet" -#: includes/class-admin-settings.php:278 +#: includes/class-admin-settings.php:700 msgid "A password is currently set. Enter a new password to change it, or leave blank to keep the current password." msgstr "Et passord er allerede satt. Skriv inn et nytt passord for å endre det, eller la stå tomt for å beholde nåværende passord." -#: includes/class-admin-settings.php:282 +#: includes/class-admin-settings.php:704 msgid "Enter the password visitors will use to access protected content." msgstr "Skriv inn passordet besøkende skal bruke for å få tilgang til beskyttet innhold." -#: includes/class-admin-settings.php:298 +#: includes/class-admin-settings.php:720 msgid "days" msgstr "dager" -#: includes/class-admin-settings.php:300 +#: includes/class-admin-settings.php:722 msgid "How long visitors stay authenticated after entering the password." msgstr "Hvor lenge besøkende forblir autentisert etter å ha tastet inn passordet." -#: includes/class-admin-settings.php:316 +#: includes/class-admin-settings.php:737 msgid "Protect all pages and posts (except front page)" msgstr "Beskytt alle sider og innlegg (unntatt forsiden)" -#: includes/class-admin-settings.php:322 +#: includes/class-admin-settings.php:742 msgid "Protect only selected pages and posts" msgstr "Beskytt kun valgte sider og innlegg" -#: includes/class-admin-settings.php:357 +#: includes/class-admin-settings.php:777 msgid "These pages and posts will not require a password." msgstr "Disse sidene og innleggene vil ikke kreve passord." -#: includes/class-admin-settings.php:392 +#: includes/class-admin-settings.php:812 msgid "Only these pages and posts will require a password." msgstr "Kun disse sidene og innleggene vil kreve passord." -#: includes/class-admin-settings.php:464 +#: includes/class-admin-settings.php:997 msgid "Permission denied." msgstr "Tilgang nektet." @@ -158,36 +156,227 @@ msgstr "Tilgang nektet." msgid "Security check failed." msgstr "Sikkerhetssjekk mislyktes." -#: templates/password-form.php:22 +#: templates/password-form.php:25 msgid "Incorrect password. Please try again." msgstr "Feil passord. Vennligst prøv igjen." -#: templates/password-form.php:23 +#: templates/password-form.php:26 msgid "No password has been configured. Please contact the site administrator." msgstr "Ingen passord er konfigurert. Vennligst kontakt nettstedets administrator." #. translators: %s is the site name. -#: templates/password-form.php:35 +#: templates/password-form.php:48 #, php-format msgid "Password Required - %s" msgstr "Passord påkrevd - %s" -#: templates/password-form.php:63 +#: templates/password-form.php:102 msgid "Password Required" msgstr "Passord påkrevd" -#: templates/password-form.php:65 +#: templates/password-form.php:104 msgid "This content is protected. Please enter the password to continue." msgstr "Dette innholdet er beskyttet. Vennligst skriv inn passordet for å fortsette." -#: templates/password-form.php:98 +#: includes/class-admin-settings.php:628 +#: templates/password-form.php:137 msgid "Remember me" msgstr "Husk meg" -#: templates/password-form.php:103 +#: includes/class-admin-settings.php:633 +#: templates/password-form.php:142 msgid "Submit" msgstr "Send inn" -#: templates/password-form.php:110 +#: includes/class-admin-settings.php:648 +#: templates/password-form.php:156 msgid "Back to home" msgstr "Tilbake til forsiden" + +#: includes/class-admin-settings.php:292 +msgid "Are you sure you want to reset all customize settings to defaults?" +msgstr "Er du sikker på at du vil tilbakestille alle tilpasningsinnstillinger til standard?" + +#: includes/class-admin-settings.php:293 +#: includes/class-admin-settings.php:410 +#: includes/class-admin-settings.php:455 +msgid "Select Image" +msgstr "Velg bilde" + +#: includes/class-admin-settings.php:294 +msgid "Use this image" +msgstr "Bruk dette bildet" + +#: includes/class-admin-settings.php:295 +#: includes/class-admin-settings.php:411 +#: includes/class-admin-settings.php:456 +msgid "Remove" +msgstr "Fjern" + +#: includes/class-admin-settings.php:321 +msgid "General" +msgstr "Generelt" + +#: includes/class-admin-settings.php:324 +msgid "Customize" +msgstr "Tilpass" + +#: includes/class-admin-settings.php:368 +msgid "Preset Themes" +msgstr "Forhåndsdefinerte temaer" + +#: includes/class-admin-settings.php:372 +msgid "Default Purple" +msgstr "Standard lilla" + +#: includes/class-admin-settings.php:376 +msgid "Business Blue" +msgstr "Profesjonell blå" + +#: includes/class-admin-settings.php:380 +msgid "Dark Mode" +msgstr "Mørk modus" + +#: includes/class-admin-settings.php:388 +msgid "Background" +msgstr "Bakgrunn" + +#: includes/class-admin-settings.php:391 +msgid "Background Color" +msgstr "Bakgrunnsfarge" + +#: includes/class-admin-settings.php:396 +msgid "Gradient End Color" +msgstr "Gradient sluttfarge" + +#: includes/class-admin-settings.php:398 +msgid "Leave empty for solid color background." +msgstr "La stå tom for ensfarget bakgrunn." + +#: includes/class-admin-settings.php:402 +msgid "Background Image" +msgstr "Bakgrunnsbilde" + +#: includes/class-admin-settings.php:418 +msgid "Card Styling" +msgstr "Kortstil" + +#: includes/class-admin-settings.php:421 +msgid "Card Background Color" +msgstr "Kortets bakgrunnsfarge" + +#: includes/class-admin-settings.php:426 +msgid "Card Border Radius" +msgstr "Kortets hjørneradius" + +#: includes/class-admin-settings.php:434 +msgid "Card Shadow" +msgstr "Kortskygge" + +#: includes/class-admin-settings.php:444 +msgid "Logo" +msgstr "Logo" + +#: includes/class-admin-settings.php:447 +msgid "Logo Image" +msgstr "Logobilde" + +#: includes/class-admin-settings.php:461 +msgid "Logo Width" +msgstr "Logobredde" + +#: includes/class-admin-settings.php:471 +msgid "Typography" +msgstr "Typografi" + +#: includes/class-admin-settings.php:474 +msgid "Heading Text" +msgstr "Overskriftstekst" + +#: includes/class-admin-settings.php:479 +msgid "Heading Color" +msgstr "Overskriftsfarge" + +#: includes/class-admin-settings.php:484 +msgid "Text Color" +msgstr "Tekstfarge" + +#: includes/class-admin-settings.php:489 +msgid "Font Family" +msgstr "Skrifttype" + +#: includes/class-admin-settings.php:491 +msgid "System Default" +msgstr "Systemstandard" + +#: includes/class-admin-settings.php:492 +msgid "Segoe UI" +msgstr "Segoe UI" + +#: includes/class-admin-settings.php:493 +msgid "Georgia" +msgstr "Georgia" + +#: includes/class-admin-settings.php:494 +msgid "Courier New" +msgstr "Courier New" + +#: includes/class-admin-settings.php:501 +msgid "Button" +msgstr "Knapp" + +#: includes/class-admin-settings.php:504 +msgid "Button Text" +msgstr "Knappetekst" + +#: includes/class-admin-settings.php:509 +msgid "Button Background Color" +msgstr "Knappens bakgrunnsfarge" + +#: includes/class-admin-settings.php:514 +msgid "Button Text Color" +msgstr "Knappens tekstfarge" + +#: includes/class-admin-settings.php:519 +msgid "Button Border Radius" +msgstr "Knappens hjørneradius" + +#: includes/class-admin-settings.php:529 +msgid "Form Options" +msgstr "Skjemavalg" + +#: includes/class-admin-settings.php:532 +msgid "Show Remember Me" +msgstr "Vis «Husk meg»" + +#: includes/class-admin-settings.php:540 +msgid "Input Border Radius" +msgstr "Inntastingsfeltets hjørneradius" + +#: includes/class-admin-settings.php:550 +msgid "Footer" +msgstr "Bunntekst" + +#: includes/class-admin-settings.php:553 +msgid "Footer Text" +msgstr "Bunntekst" + +#: includes/class-admin-settings.php:558 +msgid "Footer Link URL" +msgstr "Bunntekst lenke-URL" + +#: includes/class-admin-settings.php:568 +msgid "Reset to Defaults" +msgstr "Tilbakestill til standard" + +#: includes/class-admin-settings.php:574 +msgid "Live Preview" +msgstr "Direktevisning" + +#: includes/class-admin-settings.php:615 +msgid "Password Protected" +msgstr "Passordbeskyttet" + +#: includes/class-admin-settings.php:619 +msgid "Enter the password to access this content." +msgstr "Skriv inn passordet for å få tilgang til dette innholdet." diff --git a/languages/passwp-posts.pot b/languages/passwp-posts.pot index 70d2962..60aab32 100644 --- a/languages/passwp-posts.pot +++ b/languages/passwp-posts.pot @@ -2,21 +2,21 @@ # This file is distributed under the GPL-2.0+. msgid "" msgstr "" -"Project-Id-Version: PassWP Posts 1.0.2\n" +"Project-Id-Version: PassWP Posts 1.1.0\n" "Report-Msgid-Bugs-To: https://wordpress.org/support/plugin/passwp-posts\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"POT-Creation-Date: 2025-12-11T22:54:39+00:00\n" +"POT-Creation-Date: 2025-12-15T11:56:27+00:00\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "X-Generator: WP-CLI 2.12.0\n" "X-Domain: passwp-posts\n" #. Plugin Name of the plugin #: passwp-posts.php -#: includes/class-admin-settings.php:52 +#: includes/class-admin-settings.php:79 msgid "PassWP Posts" msgstr "" @@ -40,113 +40,318 @@ msgstr "" msgid "https://soderlind.no" msgstr "" -#: includes/class-admin-settings.php:51 +#: includes/class-admin-settings.php:78 msgid "PassWP Posts Settings" msgstr "" -#: includes/class-admin-settings.php:83 +#: includes/class-admin-settings.php:103 msgid "Password Protection Settings" msgstr "" -#: includes/class-admin-settings.php:91 +#: includes/class-admin-settings.php:111 msgid "Enable Protection" msgstr "" -#: includes/class-admin-settings.php:100 -#: templates/password-form.php:88 +#: includes/class-admin-settings.php:120 +#: includes/class-admin-settings.php:623 +#: templates/password-form.php:127 msgid "Password" msgstr "" -#: includes/class-admin-settings.php:109 +#: includes/class-admin-settings.php:129 msgid "Remember Me Duration" msgstr "" -#: includes/class-admin-settings.php:118 +#: includes/class-admin-settings.php:138 msgid "Protection Mode" msgstr "" -#: includes/class-admin-settings.php:127 +#: includes/class-admin-settings.php:147 msgid "Excluded Pages/Posts" msgstr "" -#: includes/class-admin-settings.php:136 +#: includes/class-admin-settings.php:156 msgid "Protected Pages/Posts" msgstr "" -#: includes/class-admin-settings.php:202 +#: includes/class-admin-settings.php:253 msgid "Search for pages or posts..." msgstr "" -#: includes/class-admin-settings.php:203 +#: includes/class-admin-settings.php:254 msgid "Show password" msgstr "" -#: includes/class-admin-settings.php:204 +#: includes/class-admin-settings.php:255 msgid "Hide password" msgstr "" -#: includes/class-admin-settings.php:228 +#: includes/class-admin-settings.php:292 +msgid "Are you sure you want to reset all customize settings to defaults?" +msgstr "" + +#: includes/class-admin-settings.php:293 +#: includes/class-admin-settings.php:410 +#: includes/class-admin-settings.php:455 +msgid "Select Image" +msgstr "" + +#: includes/class-admin-settings.php:294 +msgid "Use this image" +msgstr "" + +#: includes/class-admin-settings.php:295 +#: includes/class-admin-settings.php:411 +#: includes/class-admin-settings.php:456 +msgid "Remove" +msgstr "" + +#: includes/class-admin-settings.php:321 +msgid "General" +msgstr "" + +#: includes/class-admin-settings.php:324 +msgid "Customize" +msgstr "" + +#: includes/class-admin-settings.php:348 +#: includes/class-admin-settings.php:566 msgid "Save Settings" msgstr "" -#: includes/class-admin-settings.php:239 +#: includes/class-admin-settings.php:368 +msgid "Preset Themes" +msgstr "" + +#: includes/class-admin-settings.php:372 +msgid "Default Purple" +msgstr "" + +#: includes/class-admin-settings.php:376 +msgid "Business Blue" +msgstr "" + +#: includes/class-admin-settings.php:380 +msgid "Dark Mode" +msgstr "" + +#: includes/class-admin-settings.php:388 +msgid "Background" +msgstr "" + +#: includes/class-admin-settings.php:391 +msgid "Background Color" +msgstr "" + +#: includes/class-admin-settings.php:396 +msgid "Gradient End Color" +msgstr "" + +#: includes/class-admin-settings.php:398 +msgid "Leave empty for solid color background." +msgstr "" + +#: includes/class-admin-settings.php:402 +msgid "Background Image" +msgstr "" + +#: includes/class-admin-settings.php:418 +msgid "Card Styling" +msgstr "" + +#: includes/class-admin-settings.php:421 +msgid "Card Background Color" +msgstr "" + +#: includes/class-admin-settings.php:426 +msgid "Card Border Radius" +msgstr "" + +#: includes/class-admin-settings.php:434 +msgid "Card Shadow" +msgstr "" + +#: includes/class-admin-settings.php:444 +msgid "Logo" +msgstr "" + +#: includes/class-admin-settings.php:447 +msgid "Logo Image" +msgstr "" + +#: includes/class-admin-settings.php:461 +msgid "Logo Width" +msgstr "" + +#: includes/class-admin-settings.php:471 +msgid "Typography" +msgstr "" + +#: includes/class-admin-settings.php:474 +msgid "Heading Text" +msgstr "" + +#: includes/class-admin-settings.php:479 +msgid "Heading Color" +msgstr "" + +#: includes/class-admin-settings.php:484 +msgid "Text Color" +msgstr "" + +#: includes/class-admin-settings.php:489 +msgid "Font Family" +msgstr "" + +#: includes/class-admin-settings.php:491 +msgid "System Default" +msgstr "" + +#: includes/class-admin-settings.php:492 +msgid "Segoe UI" +msgstr "" + +#: includes/class-admin-settings.php:493 +msgid "Georgia" +msgstr "" + +#: includes/class-admin-settings.php:494 +msgid "Courier New" +msgstr "" + +#: includes/class-admin-settings.php:501 +msgid "Button" +msgstr "" + +#: includes/class-admin-settings.php:504 +msgid "Button Text" +msgstr "" + +#: includes/class-admin-settings.php:509 +msgid "Button Background Color" +msgstr "" + +#: includes/class-admin-settings.php:514 +msgid "Button Text Color" +msgstr "" + +#: includes/class-admin-settings.php:519 +msgid "Button Border Radius" +msgstr "" + +#: includes/class-admin-settings.php:529 +msgid "Form Options" +msgstr "" + +#: includes/class-admin-settings.php:532 +msgid "Show Remember Me" +msgstr "" + +#: includes/class-admin-settings.php:540 +msgid "Input Border Radius" +msgstr "" + +#: includes/class-admin-settings.php:550 +msgid "Footer" +msgstr "" + +#: includes/class-admin-settings.php:553 +msgid "Footer Text" +msgstr "" + +#: includes/class-admin-settings.php:558 +msgid "Footer Link URL" +msgstr "" + +#: includes/class-admin-settings.php:568 +msgid "Reset to Defaults" +msgstr "" + +#: includes/class-admin-settings.php:574 +msgid "Live Preview" +msgstr "" + +#: includes/class-admin-settings.php:615 +msgid "Password Protected" +msgstr "" + +#: includes/class-admin-settings.php:619 +msgid "Enter the password to access this content." +msgstr "" + +#: includes/class-admin-settings.php:628 +#: templates/password-form.php:137 +msgid "Remember me" +msgstr "" + +#: includes/class-admin-settings.php:633 +#: templates/password-form.php:142 +msgid "Submit" +msgstr "" + +#: includes/class-admin-settings.php:648 +#: templates/password-form.php:156 +msgid "Back to home" +msgstr "" + +#: includes/class-admin-settings.php:661 msgid "Configure password protection for your site. The front page is always public. Logged-in users bypass the password." msgstr "" -#: includes/class-admin-settings.php:251 +#: includes/class-admin-settings.php:673 msgid "Enable password protection" msgstr "" -#: includes/class-admin-settings.php:254 +#: includes/class-admin-settings.php:676 msgid "When enabled, visitors must enter a password to view protected content." msgstr "" -#: includes/class-admin-settings.php:269 +#: includes/class-admin-settings.php:691 msgid "Leave blank to keep current password" msgstr "" -#: includes/class-admin-settings.php:269 -#: templates/password-form.php:91 +#: includes/class-admin-settings.php:691 +#: templates/password-form.php:130 msgid "Enter password" msgstr "" -#: includes/class-admin-settings.php:272 +#: includes/class-admin-settings.php:694 msgid "Toggle password visibility" msgstr "" -#: includes/class-admin-settings.php:278 +#: includes/class-admin-settings.php:700 msgid "A password is currently set. Enter a new password to change it, or leave blank to keep the current password." msgstr "" -#: includes/class-admin-settings.php:282 +#: includes/class-admin-settings.php:704 msgid "Enter the password visitors will use to access protected content." msgstr "" -#: includes/class-admin-settings.php:298 +#: includes/class-admin-settings.php:720 msgid "days" msgstr "" -#: includes/class-admin-settings.php:300 +#: includes/class-admin-settings.php:722 msgid "How long visitors stay authenticated after entering the password." msgstr "" -#: includes/class-admin-settings.php:316 +#: includes/class-admin-settings.php:737 msgid "Protect all pages and posts (except front page)" msgstr "" -#: includes/class-admin-settings.php:322 +#: includes/class-admin-settings.php:742 msgid "Protect only selected pages and posts" msgstr "" -#: includes/class-admin-settings.php:357 +#: includes/class-admin-settings.php:777 msgid "These pages and posts will not require a password." msgstr "" -#: includes/class-admin-settings.php:392 +#: includes/class-admin-settings.php:812 msgid "Only these pages and posts will require a password." msgstr "" -#: includes/class-admin-settings.php:464 +#: includes/class-admin-settings.php:997 msgid "Permission denied." msgstr "" @@ -154,36 +359,24 @@ msgstr "" msgid "Security check failed." msgstr "" -#: templates/password-form.php:22 +#: templates/password-form.php:25 msgid "Incorrect password. Please try again." msgstr "" -#: templates/password-form.php:23 +#: templates/password-form.php:26 msgid "No password has been configured. Please contact the site administrator." msgstr "" #. translators: %s is the site name. -#: templates/password-form.php:35 +#: templates/password-form.php:48 #, php-format msgid "Password Required - %s" msgstr "" -#: templates/password-form.php:63 +#: templates/password-form.php:102 msgid "Password Required" msgstr "" -#: templates/password-form.php:65 +#: templates/password-form.php:104 msgid "This content is protected. Please enter the password to continue." msgstr "" - -#: templates/password-form.php:98 -msgid "Remember me" -msgstr "" - -#: templates/password-form.php:103 -msgid "Submit" -msgstr "" - -#: templates/password-form.php:110 -msgid "Back to home" -msgstr "" diff --git a/package.json b/package.json index 5be3dff..e784db6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "passwp-posts", - "version": "1.0.4", + "version": "1.1.0", "description": "Password protects all pages and posts except the front page", "type": "module", "scripts": { diff --git a/passwp-posts.php b/passwp-posts.php index 55e38c1..ef95d41 100644 --- a/passwp-posts.php +++ b/passwp-posts.php @@ -3,7 +3,7 @@ * Plugin Name: PassWP Posts * Plugin URI: https://developer.suspended.no/passwp-posts * Description: Password protects all pages and posts except the front page. Logged-in users bypass the password. - * Version: 1.0.4 + * Version: 1.1.0 * Author: Per Soderlind * Author URI: https://soderlind.no * License: GPL-2.0+ @@ -22,7 +22,7 @@ defined( 'ABSPATH' ) || exit; // Plugin constants. -define( 'PASSWP_POSTS_VERSION', '1.0.4' ); +define( 'PASSWP_POSTS_VERSION', '1.1.0' ); define( 'PASSWP_POSTS_PATH', plugin_dir_path( __FILE__ ) ); define( 'PASSWP_POSTS_URL', plugin_dir_url( __FILE__ ) ); define( 'PASSWP_POSTS_BASENAME', plugin_basename( __FILE__ ) ); diff --git a/readme.txt b/readme.txt index 92e18e3..fe37918 100644 --- a/readme.txt +++ b/readme.txt @@ -4,7 +4,7 @@ Tags: password, protection, privacy, security, access control Requires at least: 6.8 Tested up to: 6.9 Requires PHP: 8.3 -Stable tag: 1.0.4 +Stable tag: 1.1.0 License: GPLv2 or later License URI: https://www.gnu.org/licenses/gpl-2.0.html @@ -20,6 +20,9 @@ PassWP Posts is a simple yet powerful plugin that adds password protection to yo * **Front Page Always Accessible** - Your homepage remains public * **Logged-in User Bypass** - Authenticated users skip the password prompt * **Protection Modes** - Protect all content (with exclusions) or only selected pages/posts +* **Customizable Password Form** - Personalize colors, typography, logo, and more +* **Preset Themes** - Choose from Default Purple, Business Blue, or Dark Mode +* **Live Preview** - See your customizations in real-time before saving * **Remember Me** - Visitors stay authenticated for configurable durations * **Secure** - Uses WordPress native password hashing and secure cookies @@ -39,6 +42,8 @@ PassWP Posts is a simple yet powerful plugin that adds password protection to yo == Configuration == +**General Tab:** + 1. Navigate to **Settings → PassWP Posts** 2. Check **Enable Protection** to activate 3. Enter your desired **Password** @@ -48,6 +53,19 @@ PassWP Posts is a simple yet powerful plugin that adds password protection to yo - *Protect only selected* - then choose which pages/posts to protect 6. Click **Save Settings** +**Customize Tab:** + +1. Click the **Customize** tab +2. Choose a **Preset Theme** or customize individual settings: + - Background color, gradient, and image + - Card styling (background, border radius, shadow) + - Logo with adjustable width + - Typography (heading, colors, font family) + - Button appearance + - Footer text and link +3. Use the **Live Preview** to see changes in real-time +4. Click **Save Settings** + == Frequently Asked Questions == = Does this protect the WordPress admin area? = @@ -68,7 +86,7 @@ Yes, passwords are hashed using `wp_hash_password()`, the same function WordPres = Can I customize the password form? = -Yes, copy `templates/password-form.php` to your theme and modify it. You can also use the `passwp_posts_form_template` filter. +Yes! Use the **Customize** tab in Settings → PassWP Posts to change colors, typography, add a logo, and more—all with live preview. For advanced customization, copy `templates/password-form.php` to your theme and modify it. You can also use the `passwp_posts_form_template` filter. = Does it work with caching plugins? = @@ -82,6 +100,17 @@ You may need to exclude protected pages from caching or configure your caching p == Changelog == += 1.1.0 = +* Added Customize tab with live preview for password form styling +* Added preset themes: Default Purple, Business Blue, Dark Mode +* Added customizable background (color, gradient, image) +* Added card styling options (background, border radius, shadow) +* Added logo upload with adjustable width +* Added typography settings (heading, colors, font family) +* Added button customization (text, colors, border radius) +* Added footer text and link options +* Updated Norwegian Bokmål translations + = 1.0.4 = * Added GitHub Plugin Updater for automatic updates from GitHub releases * Added Plugin Update Checker library as dependency @@ -111,6 +140,9 @@ You may need to exclude protected pages from caching or configure your caching p == Upgrade Notice == += 1.1.0 = +New Customize tab with preset themes and live preview for password form styling. + = 1.0.4 = Added automatic plugin updates from GitHub releases. diff --git a/templates/password-form.php b/templates/password-form.php index 0546b33..57b52e0 100644 --- a/templates/password-form.php +++ b/templates/password-form.php @@ -17,6 +17,9 @@ $site_name = get_bloginfo( 'name' ); $site_url = home_url(); +// Get customize settings. +$customize = PassWP\Posts\Admin_Settings::get_customize_settings(); + // Error messages. $error_messages = array( 'invalid' => __( 'Incorrect password. Please try again.', 'passwp-posts' ), @@ -24,6 +27,16 @@ ); $error_message = isset( $error_messages[ $error ] ) ? $error_messages[ $error ] : ''; + +// Build background style. +$bg_style = ''; +if ( ! empty( $customize[ 'bg_image' ] ) ) { + $bg_style = sprintf( 'background-image: url(%s); background-size: cover; background-position: center;', esc_url( $customize[ 'bg_image' ] ) ); +} elseif ( ! empty( $customize[ 'bg_gradient_end' ] ) ) { + $bg_style = sprintf( 'background: linear-gradient(135deg, %s 0%%, %s 100%%);', esc_attr( $customize[ 'bg_color' ] ), esc_attr( $customize[ 'bg_gradient_end' ] ) ); +} else { + $bg_style = sprintf( 'background-color: %s;', esc_attr( $customize[ 'bg_color' ] ) ); +} ?> > @@ -37,19 +50,71 @@ + - - - - - - - - + + + + + + + + + + + + + + @@ -60,7 +125,9 @@ - + + + @@ -92,7 +159,7 @@ class="passwp-posts-form"> autocomplete="current-password"> - + > @@ -100,14 +167,23 @@ class="passwp-posts-form"> - +
+ +
+ + + + + + + + + + + ← + + +