Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,18 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.3.0] - 2026-01-08

### Added

- New `[passwp_login]` shortcode for rendering a password form on public pages
- New Customize option for the password input placeholder

### Changed

- Unified default texts: "Enter password" placeholder and "Login" button
- Shortcode output uses common WordPress login form CSS classes

## [1.2.2] - 2025-12-15

### Security & Fixed
Expand Down
20 changes: 16 additions & 4 deletions assets/js/customize.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
heading_color: '#1e1e1e',
text_color: '#666666',
font_family: 'system-ui, -apple-system, sans-serif',
password_placeholder: '',
button_text: '',
button_bg_color: '#667eea',
button_text_color: '#ffffff',
Expand All @@ -79,6 +80,7 @@
heading_color: '#1e1e1e',
text_color: '#666666',
font_family: 'system-ui, -apple-system, sans-serif',
password_placeholder: '',
button_text: '',
button_bg_color: '#2193b0',
button_text_color: '#ffffff',
Expand All @@ -101,6 +103,7 @@
heading_color: '#e5e5e5',
text_color: '#a0a0a0',
font_family: 'system-ui, -apple-system, sans-serif',
password_placeholder: '',
button_text: '',
button_bg_color: '#6366f1',
button_text_color: '#ffffff',
Expand Down Expand Up @@ -227,6 +230,7 @@

// Text fields.
$('#passwp_heading_text').val(values.heading_text);
$('#passwp_password_placeholder').val(values.password_placeholder);
$('#passwp_button_text').val(values.button_text);
$('#passwp_footer_text').val(values.footer_text);
$('#passwp_footer_link').val(values.footer_link);
Expand Down Expand Up @@ -290,6 +294,7 @@
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 passwordPlaceholder = $('#passwp_password_placeholder').val();
const buttonText = $('#passwp_button_text').val();
const buttonBgColor = $('#passwp_button_bg_color').val() || '#667eea';
const buttonTextColor = $('#passwp_button_text_color').val() || '#ffffff';
Expand Down Expand Up @@ -353,19 +358,26 @@
$preview.find('.passwp-preview-text').css('color', textColor);

// Form input.
$preview.find('.passwp-preview-form input[type="password"]').css('border-radius', inputBorderRadius + 'px');
const $passwordInput = $preview.find('.passwp-preview-form input[type="password"]');
$passwordInput.css('border-radius', inputBorderRadius + 'px');
if ($passwordInput.length) {
const defaultPlaceholder = $passwordInput.data('defaultPlaceholder') || $passwordInput.attr('placeholder') || '';
$passwordInput.attr('placeholder', passwordPlaceholder || defaultPlaceholder);
}

// Remember me.
$preview.find('.passwp-preview-remember').toggle(showRememberMe).css('color', textColor);

// Button.
$preview.find('.passwp-preview-form button').css({
const $button = $preview.find('.passwp-preview-form button');
$button.css({
'background-color': buttonBgColor,
'color': buttonTextColor,
'border-radius': buttonBorderRadius + 'px'
});
if (buttonText) {
$preview.find('.passwp-preview-form button').text(buttonText);
if ($button.length) {
const defaultButtonText = $button.data('defaultText') || $button.text() || '';
$button.text(buttonText || defaultButtonText);
}

// Footer.
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"description": "Password protects all pages and posts except the front page",
"type": "wordpress-plugin",
"license": "GPL-2.0+",
"version": "1.2.2",
"version": "1.3.0",
"require": {
"php": ">=8.3",
"yahnis-elsts/plugin-update-checker": "^5.6"
Expand Down
32 changes: 26 additions & 6 deletions includes/AdminSettings.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ final class AdminSettings {
'heading_color' => '#1a1a2e',
'text_color' => '#4a5568',
'font_family' => 'system-ui, -apple-system, sans-serif',
'password_placeholder' => '',
'button_text' => '',
'button_bg_color' => '#667eea',
'button_text_color' => '#ffffff',
Expand Down Expand Up @@ -605,6 +606,18 @@ class="passwp-range-value"><?php echo esc_html( $settings[ 'button_border_radius
<div class="passwp-section">
<h2><?php esc_html_e( 'Form Options', 'passwp-posts' ); ?></h2>

<div class="passwp-form-row">
<label
for="passwp_password_placeholder"><?php esc_html_e( 'Password Placeholder', 'passwp-posts' ); ?></label>
<input type="text" id="passwp_password_placeholder"
name="<?php echo esc_attr( self::OPTION_NAME ); ?>[customize][password_placeholder]"
value="<?php echo esc_attr( $settings[ 'password_placeholder' ] ); ?>" class="regular-text"
placeholder="<?php echo esc_attr__( 'Enter password', 'passwp-posts' ); ?>" />
<p class="description">
<?php esc_html_e( 'Leave empty to use the default text.', 'passwp-posts' ); ?>
</p>
</div>

<div class="passwp-form-row">
<label
for="passwp_show_remember_me"><?php esc_html_e( 'Show Remember Me', 'passwp-posts' ); ?></label>
Expand Down Expand Up @@ -679,6 +692,11 @@ class="passwp-range-value"><?php echo esc_html( $settings[ 'input_border_radius'
* @param array<string, mixed> $settings The customize settings.
*/
private function render_preview_content( array $settings ): void {
$default_password_placeholder = __( 'Enter password', 'passwp-posts' );
$password_placeholder = $settings[ 'password_placeholder' ] ?: $default_password_placeholder;
$default_button_text = __( 'Login', 'passwp-posts' );
$button_text = $settings[ 'button_text' ] ?: $default_button_text;

$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' ] ) );
Expand Down Expand Up @@ -712,7 +730,8 @@ private function render_preview_content( array $settings ): void {
</p>

<div class="passwp-preview-form">
<input type="password" placeholder="<?php esc_attr_e( 'Password', 'passwp-posts' ); ?>"
<input type="password" placeholder="<?php echo esc_attr( $password_placeholder ); ?>"
data-default-placeholder="<?php echo esc_attr( $default_password_placeholder ); ?>"
style="border-radius: <?php echo absint( $settings[ 'input_border_radius' ] ); ?>px;" readonly />

<?php if ( $settings[ 'show_remember_me' ] ) : ?>
Expand All @@ -722,9 +741,9 @@ private function render_preview_content( array $settings ): void {
</label>
<?php endif; ?>

<button type="button"
<button type="button" data-default-text="<?php echo esc_attr( $default_button_text ); ?>"
style="background-color: <?php echo esc_attr( $settings[ 'button_bg_color' ] ); ?>; color: <?php echo esc_attr( $settings[ 'button_text_color' ] ); ?>; border-radius: <?php echo absint( $settings[ 'button_border_radius' ] ); ?>px;">
<?php echo esc_html( $settings[ 'button_text' ] ?: __( 'Submit', 'passwp-posts' ) ); ?>
<?php echo esc_html( $button_text ); ?>
</button>
</div>

Expand Down Expand Up @@ -1031,9 +1050,10 @@ private function sanitize_customize_settings( array $input ): array {
$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' ] ?? '' );
$sanitized[ 'heading_text' ] = sanitize_text_field( $input[ 'heading_text' ] ?? '' );
$sanitized[ 'password_placeholder' ] = sanitize_text_field( $input[ 'password_placeholder' ] ?? '' );
$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 = [
Expand Down
129 changes: 129 additions & 0 deletions includes/Shortcodes.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
<?php
/**
* Shortcodes for PassWP Posts.
*
* @package PassWP\Posts
*/

declare(strict_types=1);

namespace PassWP\Posts;

// Prevent direct access.
defined( 'ABSPATH' ) || exit;

/**
* Class Shortcodes
*/
final class Shortcodes {

/**
* Constructor.
*/
public function __construct(
private readonly CookieHandler $cookie_handler = new CookieHandler(),
) {
add_action( 'init', $this->register_shortcodes( ... ) );
}

/**
* Register plugin shortcodes.
*/
public function register_shortcodes(): void {
add_shortcode( 'passwp_login', $this->render_passwp_login( ... ) );
}

/**
* Render the [passwp_login] shortcode.
*
* @param array<string, mixed>|string $atts Shortcode attributes.
*/
public function render_passwp_login( array|string $atts = [] ): string {
$settings = get_option( 'passwp_posts_settings', [] );

if ( empty( $settings[ 'enabled' ] ) || empty( $settings[ 'password_hash' ] ) ) {
return '';
}

if ( is_user_logged_in() ) {
return '';
}

$password_hash = (string) $settings[ 'password_hash' ];
if ( $this->cookie_handler->is_valid_cookie( $password_hash ) ) {
return '';
}

$customize = AdminSettings::get_customize_settings();

$placeholder = ! empty( $customize[ 'password_placeholder' ] )
? (string) $customize[ 'password_placeholder' ]
: __( 'Enter password', 'passwp-posts' );

$button_text = ! empty( $customize[ 'button_text' ] )
? (string) $customize[ 'button_text' ]
: __( 'Login', 'passwp-posts' );

$redirect_attr = '';
if ( is_array( $atts ) && isset( $atts[ 'redirect' ] ) ) {
$redirect_attr = (string) $atts[ 'redirect' ];
}

$default_redirect = home_url( '/' );
$raw_referer = wp_get_raw_referer();
$redirect_url_raw = $redirect_attr !== '' ? $redirect_attr : ( $raw_referer ?: $default_redirect );
$redirect_url_raw = esc_url_raw( $redirect_url_raw );
$redirect_url = $redirect_url_raw !== '' ? $redirect_url_raw : $default_redirect;
if ( function_exists( '\\wp_validate_redirect' ) ) {
$redirect_url = wp_validate_redirect( $redirect_url, $default_redirect );
}

$error = isset( $_GET[ 'passwp_error' ] )
? sanitize_text_field( wp_unslash( $_GET[ 'passwp_error' ] ) )
: '';

$error_messages = [
'invalid' => __( 'Incorrect password. Please try again.', 'passwp-posts' ),
'no_password' => __( 'No password has been configured. Please contact the site administrator.', 'passwp-posts' ),
];
$error_message = isset( $error_messages[ $error ] ) ? $error_messages[ $error ] : '';

$nonce_field = wp_nonce_field( 'passwp_posts_auth', 'passwp_posts_nonce', true, false );
if ( ! is_string( $nonce_field ) ) {
$nonce_field = '';
}

$show_remember_me = ! empty( $customize[ 'show_remember_me' ] );

$html = '<div class="passwp-login">';
if ( $error_message !== '' ) {
$html .= '<p role="alert">' . esc_html( $error_message ) . '</p>';
}
$html .= '<form method="post" action="' . esc_url( admin_url( 'admin-post.php' ) ) . '" class="loginform">';
$html .= '<input type="hidden" name="action" value="passwp_posts_auth" />';
$html .= '<input type="hidden" name="passwp_redirect" value="' . esc_url( $redirect_url ) . '" />';
$html .= $nonce_field;
$html .= '<p class="login-password">';
$html .= '<label for="passwp_password">' . esc_html__( 'Password', 'passwp-posts' ) . '</label>';
$html .= '<input type="password" id="passwp_password" name="passwp_password" class="input" required';
$html .= ' placeholder="' . esc_attr( $placeholder ) . '" autocomplete="current-password" />';
$html .= '</p>';

if ( $show_remember_me ) {
$html .= '<p class="login-remember">';
$html .= '<label>';
$html .= '<input type="checkbox" name="passwp_remember" value="1" checked /> ';
$html .= esc_html__( 'Remember me', 'passwp-posts' );
$html .= '</label>';
$html .= '</p>';
}

$html .= '<p class="login-submit">';
$html .= '<button type="submit" class="button wp-element-button">' . esc_html( $button_text ) . '</button>';
$html .= '</p>';
$html .= '</form>';
$html .= '</div>';

return $html;
}
}
Loading