Password helpers and security
3 min read
Password fields (and password Global Data variables) are designed so that a stored secret never appears in output. Two functions let your own code use them. How the three storage modes work is described under Password.
wpmcf_check_password()
wpmcf_check_password( string $group_key, string $field_key, string $password, mixed $object = null, array $args = [] ): boolTrue when the plain $password matches the stored value of a top-level Password field. Works for hashed, encrypted and plain-text storage.
It returns false when:
- the password does not match (the comparison is exact and case-sensitive);
$passwordis empty;- the field is empty (never set, or cleared);
- the field is not a Password field;
- the group, field or object is unknown, or the object reference is invalid.
$args takes context (post, user, term, comment, options, widget) and the widget_* arguments; $object accepts every object reference.
// Gate a download behind a per-post password field.
if ( wpmcf_check_password( 'download', 'access_code', sanitize_text_field( wp_unslash( $_POST['code'] ?? '' ) ), $post_id ) ) {
// serve the file
}
// Options-page secret.
wpmcf_check_password( 'integration', 'webhook_secret', $supplied, 'option' );Verified for all three storage modes on posts, users and options.
wpmcf_get_password()
wpmcf_get_password( string $group_key, string $field_key, mixed $object = null, array $args = [] ): ?stringReturns the readable secret of a Password field stored encrypted or as plain text. Returns null for a hashed password, an empty field, a non-Password field, or a failed read.
$apiKey = wpmcf_get_password( 'integration', 'api_secret', 'option' );
if ( $apiKey !== null ) {
wp_remote_get( $url, [ 'headers' => [ 'Authorization' => 'Bearer ' . $apiKey ] ] );
}Never print the result. Encrypted values use a key derived from the site's SECURE_AUTH_SALT: if the salts change, they can no longer be decrypted and null is returned.
What the other functions do with a Password field
Verified for a hashed, an encrypted and a plain-text field:
Call | Result |
|---|---|
| the stored sealed string: |
|
|
| prints nothing |
| stores the value sealed according to the field's Store as setting |
| keeps the stored value, returns |
| clears it |
|
|
| not allowed: matches nothing |
REST | never returned and refused on write ( |
| empty |
Letting a Password field print
The filter wpmcf/field/the_password (default false) lets the printing functions reveal plain and encrypted values (never a hash). Verified: with the filter returning true, a plain-text password printed; a hash still printed nothing. wpmcf/global/the_password does the same for Global Data (verified: with it on, wpmcf_the_global() and [wpmcf_global] print the decrypted value with auto). Leave both off on public output; enable only in code paths you control.
Global Data passwords
A Global Data variable of type password is encrypted at rest. wpmcf_get_global() returns the decrypted value, so never echo it. wpmcf_the_global(), [wpmcf_global] and {{ glb.key }} print nothing for it. See Global Data functions.
Security checklist
- Escape every raw value.
wpmcf_get_*returns unescaped data. Useesc_html(),esc_attr(),esc_url(),wp_kses_post()orwp_json_encode()for the place you print into, or use awpmcf_the_*function. - Writes are not capability-checked.
wpmcf_update_field(),wpmcf_delete_field(),wpmcf_update_option_field(),wpmcf_delete_option_field()andwpmcf_update_global()trust the caller. Verify a nonce andcurrent_user_can()before calling them with visitor input. - Reads are not restricted either.
wpmcf_get_field( ..., 'user_5' )returns another user's value;wpmcf_get_field( ..., $private_post_id )returns a private post's value. Only the shortcode, the block and the bindings enforce visibility. - The REST
wpmcfattribute is public for published posts. Anyone who can read a post reads its REST-enabled groups. Writing needsedit_post. - Do not put secrets in non-Password fields. Text fields are readable by REST, the shortcode and exports.
- Prefer hashed passwords and compare with
wpmcf_check_password(). Use encrypted storage only when your code must send the secret to another service. - Values with
{{ }}run only for trusted writers. Expressions in post values run only when the post's author may use unfiltered HTML; comments never run them. See Reading values. - Queries are injection-safe.
wpmcf_querybinds every value and validates every identifier; bad input matches nothing instead of failing open. See Querying posts.
Still stuck? Contact support