'', // Single capability or comma-separated multiple capabilities.
'role' => '', // Single role or comma-separated multiple roles.
'user_id' => '', // Single user ID or comma-separated multiple IDs.
'user_name' => '', // Single user name or comma-separated multiple names.
'user_email' => '', // Single user email or comma-separated multiple emails.
'operator' => 'or' // Only the `!` operator is supported for now. Everything else falls back to `or`.
);
// Merge the input attributes and the defaults.
$attr = shortcode_atts( $defaults, $attr, 'members_access' );
// Get the operator.
$operator = strtolower( $attr['operator'] );
// If the current user has the capability, show the content.
if ( $attr['capability'] ) {
// Get the capabilities.
$caps = explode( ',', $attr['capability'] );
if ( '!' === $operator )
return members_current_user_can_any( $caps ) ? '' : do_shortcode( $content );
return members_current_user_can_any( $caps ) ? do_shortcode( $content ) : '';
}
// If the current user has the role, show the content.
if ( $attr['role'] ) {
// Get the roles.
$roles = explode( ',', $attr['role'] );
if ( '!' === $operator )
return members_current_user_has_role( $roles ) ? '' : do_shortcode( $content );
return members_current_user_has_role( $roles ) ? do_shortcode( $content ) : '';
}
$user_id = 0;
$user_name = $user_email = '';
if ( is_user_logged_in() ) {
$user = wp_get_current_user();
$user_id = get_current_user_id();
$user_name = $user->user_login;
$user_email = $user->user_email;
}
// If the current user has one of the user ids.
if ( $attr['user_id'] ) {
// Get the user IDs.
$ids = array_map( 'trim', explode( ',', $attr['user_id'] ) );
if ( '!' === $operator ) {
return in_array( $user_id, $ids ) ? '' : do_shortcode( $content );
}
return in_array( $user_id, $ids ) ? do_shortcode( $content ) : '';
}
// If the current user has one of the user names.
if ( $attr['user_name'] ) {
// Get the user names.
$names = array_map( 'trim', explode( ',', $attr['user_name'] ) );
if ( '!' === $operator ) {
return in_array( $user_name, $names ) ? '' : do_shortcode( $content );
}
return in_array( $user_name, $names ) ? do_shortcode( $content ) : '';
}
// If the current user has one of the user emails.
if ( $attr['user_email'] ) {
// Get the user emails.
$emails = array_map( 'trim', explode( ',', $attr['user_email'] ) );
if ( '!' === $operator ) {
return in_array( $user_email, $emails ) ? '' : do_shortcode( $content );
}
return in_array( $user_email, $emails ) ? do_shortcode( $content ) : '';
}
// Return an empty string if we've made it to this point.
return '';
}
/**
* Displays a login form.
*
* @since 0.1.0
* @access public
* @param array $attr Shortcode attributes.
* @return string
*/
function members_login_form_shortcode( $attr = [] ) {
// Default attributes
$defaults = array(
'echo' => false,
'redirect' => members_get_login_form_page_url(),
);
// Merge user attributes with defaults
$attr = shortcode_atts( $defaults, $attr, 'members_login_form' );
// Visitors see the form; members see "You are already logged in."
members_do_not_cache_page( 'login_form' );
ob_start();
if ( is_user_logged_in() ) { ?>
_login_enqueue_scripts();
}
}
/**
* Fires when a Members login form is shown, for plugins that need to add their login scripts.
*
* @since 3.2.28
*/
do_action( 'members_login_form_enqueue_scripts' );
}
/**
* Whether the current login request came from a Members login form.
*
* @since 3.2.28
* @access public
* @return bool
*/
function members_is_login_form_request() {
if ( ! empty( $_POST['members_login_form'] ) ) {
return true;
}
// Forms rendered before 3.2.28 (e.g. still in a page cache) send a nonce instead.
return isset( $_POST['members_login_nonce'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['members_login_nonce'] ) ), 'members_login_form' );
}
/**
* Returns the message to show for a failed login. Errors that would reveal whether a username or
* email exists all get the same generic message.
*
* @since 3.2.28
* @access public
* @param \WP_Error|mixed $error Login error.
* @return string
*/
function members_get_login_error_message( $error ) {
$generic = __( 'Invalid username or password.', 'members' );
if ( ! is_wp_error( $error ) ) {
return $generic;
}
$code = $error->get_error_code();
if ( ! $code || in_array( $code, array( 'invalid_username', 'invalid_email', 'incorrect_password', 'invalidcombo' ), true ) ) {
return $generic;
}
// Other errors (e.g. a security plugin's lockout notice) are shown, minus any username.
$message = preg_replace( '/[^<]+<\/strong>\s*(is not registered|was not found)/i', __( 'the username or email', 'members' ), $error->get_error_message() );
return '' !== trim( wp_strip_all_tags( $message ) ) ? $message : $generic;
}
/**
* Sends failed logins from a Members login form back to the form with an error message, and
* successful logins on to the form's redirect URL.
*
* @since 3.2.18
*
* @param string $redirect_to The redirect destination URL.
* @param string $request The request URL.
* @param object $user The user object.
* @return string The redirect URL.
*/
function members_login_redirect( $redirect_to, $request, $user ) {
if ( ! members_is_login_form_request() ) {
return $redirect_to;
}
if ( $user instanceof \WP_User ) {
return remove_query_arg( array( 'login', 'members_login_error' ), $redirect_to );
}
// Send them back to the page the form is on. Only same-site URLs are allowed.
$form_page = isset( $_POST['members_login_page'] ) ? wp_validate_redirect( esc_url_raw( wp_unslash( $_POST['members_login_page'] ) ) ) : '';
if ( ! $form_page ) {
$form_page = wp_get_referer() ? wp_get_referer() : home_url( '/' );
}
// Keep the message for the next page load. A random key in the URL (instead of a PHP session)
// keeps it tied to this one redirect and doesn't stop the page from being cached.
$key = wp_generate_password( 20, false );
set_transient( 'members_login_error_' . $key, members_get_login_error_message( $user ), 5 * MINUTE_IN_SECONDS );
$form_page = add_query_arg(
array(
'login' => 'failed',
'members_login_error' => $key,
),
remove_query_arg( array( 'login', 'members_login_error' ), $form_page )
);
wp_safe_redirect( $form_page );
exit;
}
/**
* Filters the login form bottom output to mark the form as a Members form and show the error
* message after a failed login. This is only added to Members shortcode forms.
*
* @since 3.2.18
*
* @return string The HTML to output below the login form.
*/
function members_login_form_bottom() {
// Marks the submission as a Members form and tells us where to send failed logins.
$output = '';
$output .= '';
if ( isset( $_GET['login'] ) && 'failed' === $_GET['login'] ) {
$key = isset( $_GET['members_login_error'] ) ? sanitize_key( wp_unslash( $_GET['members_login_error'] ) ) : '';
$error_message = $key ? get_transient( 'members_login_error_' . $key ) : '';
if ( ! $error_message || ! is_string( $error_message ) ) {
$error_message = __( 'Invalid username or password.', 'members' );
}
// Allow specific HTML tags in error messages
$allowed_html = array(
'a' => array(
'href' => array(),
'title' => array(),
'target' => array(),
'rel' => array(),
'class' => array(),
),
'br' => array(),
'em' => array(),
'strong' => array(),
'p' => array('class' => array()),
'span' => array('class' => array()),
'div' => array('class' => array()),
);
$output .= '