PluginProbe
User Profile Builder – Beautiful User Registration Forms, User Profiles & User Role Editor / 4.0.3
User Profile Builder – Beautiful User Registration Forms, User Profiles & User Role Editor v4.0.3
4.0.3 4.0.2 4.0.1 4.0.0 3.16.6 3.16.5 3.16.4 3.16.3 3.16.2 3.16.1 3.16.0 3.15.9 3.9.9 3.9.5 3.9.6 3.9.7 3.9.8 1.1.7 1.1.8 1.1.9 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 All 341 releases
← All changes | features/functions.php +155 -5 3.16.04.0.3 View file →
@@ -55,8 +55,24 @@
55 55 }
56 56 }
57 57
58 58
59 +/**
60 + * Whether Profile Builder should load style-block-themes-front-end.css.
61 + */
62 +function wppb_should_load_block_theme_stylesheet() {
63 + $is_block_theme_context = version_compare( get_bloginfo( 'version' ), '5.9', '>=' )
64 + && function_exists( 'wp_is_block_theme' )
65 + && wp_is_block_theme();
66 +
67 + /**
68 + * Filter whether to load the block theme front-end stylesheet.
69 + *
70 + * @param bool $load_block_theme_stylesheet True when WordPress is 5.9+ and the active theme is a block theme.
71 + */
72 + return (bool) apply_filters( 'wppb_load_block_theme_stylesheet', $is_block_theme_context );
73 +}
74 +
59 75 function wppb_add_plugin_stylesheet() {
60 76 $wppb_generalSettings = get_option( 'wppb_general_settings' );
61 77
62 78 if ( ( file_exists( WPPB_PLUGIN_DIR . '/assets/css/style-front-end.css' ) ) && ( isset( $wppb_generalSettings['extraFieldsLayout'] ) && ( $wppb_generalSettings['extraFieldsLayout'] == 'default' ) ) ){
@@ -70,19 +86,15 @@
70 86 wp_enqueue_style( 'wppb_stylesheet_rtl' );
71 87 }
72 88 }
73 89
74 - // load stylesheet for the Default Form Style if the active WP Theme is a Block Theme (Block Themes were introduced in WordPress since the 5.9 release)
75 - if ( version_compare( get_bloginfo( 'version' ), '5.9', '>=' ) && function_exists( 'wp_is_block_theme' ) && wp_is_block_theme() ) {
76 -
90 + if ( wppb_should_load_block_theme_stylesheet() ) {
77 91 $active_design = function_exists( 'wppb_get_active_form_design' ) ? wppb_get_active_form_design() : 'form-style-default';
78 92
79 - // load stylesheet only if the active Form Design is the Default Style
80 93 if ( $active_design === 'form-style-default' && file_exists( WPPB_PLUGIN_DIR . 'assets/css/style-block-themes-front-end.css' ) ) {
81 94 wp_register_style( 'wppb_block_themes_front_end_stylesheet', WPPB_PLUGIN_URL . 'assets/css/style-block-themes-front-end.css', array(), PROFILE_BUILDER_VERSION );
82 95 wp_enqueue_style( 'wppb_block_themes_front_end_stylesheet' );
83 96 }
84 -
85 97 }
86 98 }
87 99
88 100
@@ -467,8 +479,9 @@
467 479
468 480 if ( ( 'wppb-epf-cpt' == $post_type ) || ( 'wppb-rf-cpt' == $post_type ) || ( 'wppb-ul-cpt' == $post_type ) ){
469 481 wp_enqueue_style( 'wppb-back-end-style', WPPB_PLUGIN_URL . 'assets/css/style-back-end.css', false, PROFILE_BUILDER_VERSION );
470 482 wp_enqueue_script( 'wppb-epf-rf', WPPB_PLUGIN_URL . 'assets/js/jquery-epf-rf.js', array(), PROFILE_BUILDER_VERSION, true );
483 + wp_localize_script( 'wppb-epf-rf', 'wppbEpfRf', array( 'nonce' => wp_create_nonce( 'wppb-epf-rf-id-change' ) ) );
471 484 }
472 485 else if( 'wppb-roles-editor' == $post_type ){
473 486 wp_enqueue_style( 'wppb-back-end-style', WPPB_PLUGIN_URL . 'assets/css/style-back-end.css', array(), PROFILE_BUILDER_VERSION );
474 487 }
@@ -827,8 +840,22 @@
827 840 return apply_filters( 'wppb_user_meta_exists_meta_name', $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->usermeta WHERE user_id = %d AND meta_key = %s", $id, $meta_name ) ), $id, $meta_name );
828 841 }
829 842
830 843
844 +/**
845 + * Sanitize a URL from request input. Non-string values (e.g. arrays from bracket notation) return ''.
846 + *
847 + * @param mixed $url Candidate URL.
848 + * @return string
849 + */
850 +function wppb_sanitize_request_url( $url ) {
851 + if ( ! is_string( $url ) || $url === '' ) {
852 + return '';
853 + }
854 +
855 + return esc_url_raw( wp_unslash( $url ) );
856 +}
857 +
831 858 // function to check if there is a need to add the http:// prefix
832 859 function wppb_check_missing_http( $redirectLink ) {
833 860 return preg_match( '#^(?:[a-z\d]+(?:-+[a-z\d]+)*\.)+[a-z]+(?::\d+)?(?:/|$)#i', $redirectLink );
834 861 }
@@ -1108,8 +1135,52 @@
1108 1135 return '';
1109 1136 }
1110 1137
1111 1138
1139 +/**
1140 + * Returns the AJAX actions that check the login/checkout credentials before the real form submission is sent.
1141 + *
1142 + * Those requests run the whole authentication stack, so our CAPTCHA check runs too and the token gets spent
1143 + * with the CAPTCHA provider, but they never log the user in - the browser still submits the form afterwards
1144 + * with the very same token. CAPTCHA tokens are single use, so verifying one a second time comes back as a
1145 + * duplicate and the login fails. For these actions we remember the successful verification and reuse it once,
1146 + * when the actual form submission arrives.
1147 + */
1148 +function wppb_get_captcha_prevalidation_actions() {
1149 + return apply_filters( 'wppb_captcha_prevalidation_actions', array(
1150 + 'pms_validate_checkout', // Paid Member Subscriptions checkout validation
1151 + 'wordfence_ls_authenticate', // Wordfence Login Security login pre-flight, used to decide if it needs to ask for a 2FA code
1152 + ) );
1153 +}
1154 +
1155 +/* Whether the current request is one of the CAPTCHA pre-validation AJAX calls above */
1156 +function wppb_is_captcha_prevalidation_request() {
1157 + if ( ! wp_doing_ajax() || empty( $_POST['action'] ) || ! is_string( $_POST['action'] ) ) /* phpcs:ignore WordPress.Security.NonceVerification.Missing */
1158 + return false;
1159 +
1160 + return in_array( sanitize_text_field( $_POST['action'] ), wppb_get_captcha_prevalidation_actions(), true ); /* phpcs:ignore WordPress.Security.NonceVerification.Missing */
1161 +}
1162 +
1163 +/**
1164 + * Drops pre-validated CAPTCHA tokens that were never claimed by a form submission.
1165 + *
1166 + * A pre-validation that is not followed by a submission (wrong password, abandoned login, bots) leaves its
1167 + * entry behind, so without this the option would keep growing on sites where every login is pre-validated.
1168 + */
1169 +function wppb_prune_captcha_prevalidations( $saved ) {
1170 + if ( ! is_array( $saved ) )
1171 + return array();
1172 +
1173 + $lifetime = apply_filters( 'wppb_captcha_prevalidation_lifetime', 15 * MINUTE_IN_SECONDS );
1174 +
1175 + foreach ( $saved as $token => $validated_at ) {
1176 + if ( ! is_int( $validated_at ) || ( time() - $validated_at ) > $lifetime )
1177 + unset( $saved[ $token ] );
1178 + }
1179 +
1180 + return $saved;
1181 +}
1182 +
1112 1183 /* Function for displaying reCAPTCHA error on Login and Recover Password forms */
1113 1184 function wppb_recaptcha_field_error($field_title='') {
1114 1185
1115 1186 $recaptcha_field = wppb_get_recaptcha_field();
@@ -1457,8 +1528,87 @@
1457 1528 $redirect_url = ( wppb_check_missing_http( $redirect_url ) ? wppb_add_missing_http( $redirect_url ) : $redirect_url );
1458 1529 }
1459 1530
1460 1531 return $redirect_url;
1532 +}
1533 +
1534 +/**
1535 + * Bind an autologin nonce to a user ID server-side (one-time use).
1536 + *
1537 + * @param int $user_id User ID to log in.
1538 + * @param string $nonce Autologin nonce.
1539 + */
1540 +function wppb_store_autologin_user( $user_id, $nonce ) {
1541 + $user_id = absint( $user_id );
1542 +
1543 + if ( ! $user_id || empty( $nonce ) ) {
1544 + return;
1545 + }
1546 +
1547 + set_transient( 'wppb_autologin_' . md5( $nonce ), $user_id, 2 * MINUTE_IN_SECONDS );
1548 +}
1549 +
1550 +/**
1551 + * Resolve the user bound to an autologin nonce.
1552 + *
1553 + * @param string $nonce Autologin nonce.
1554 + * @param bool $consume Whether to delete the stored mapping.
1555 + *
1556 + * @return int User ID, or 0 when not found.
1557 + */
1558 +function wppb_get_autologin_user_id( $nonce, $consume = true ) {
1559 + if ( empty( $nonce ) ) {
1560 + return 0;
1561 + }
1562 +
1563 + $key = 'wppb_autologin_' . md5( $nonce );
1564 + $user_id = absint( get_transient( $key ) );
1565 +
1566 + if ( $user_id && $consume ) {
1567 + delete_transient( $key );
1568 + }
1569 +
1570 + return $user_id;
1571 +}
1572 +
1573 +/**
1574 + * Build autologin query args for a user.
1575 + *
1576 + * @param int $user_id User ID to log in.
1577 + *
1578 + * @return array Query args for add_query_arg().
1579 + */
1580 +function wppb_get_autologin_query_args( $user_id ) {
1581 + $user_id = absint( $user_id );
1582 + $nonce = wp_create_nonce( 'autologin-' . $user_id . '-' . (int) ( time() / 60 ) );
1583 +
1584 + wppb_store_autologin_user( $user_id, $nonce );
1585 +
1586 + return array(
1587 + 'autologin' => 'true',
1588 + '_wpnonce' => $nonce,
1589 + );
1590 +}
1591 +
1592 +/**
1593 + * Verify an autologin nonce for the given user ID.
1594 + *
1595 + * @param string $nonce Autologin nonce.
1596 + * @param int $user_id User ID bound to the nonce.
1597 + *
1598 + * @return bool
1599 + */
1600 +function wppb_verify_autologin_nonce( $nonce, $user_id ) {
1601 + $user_id = absint( $user_id );
1602 +
1603 + if ( ! $user_id || empty( $nonce ) ) {
1604 + return false;
1605 + }
1606 +
1607 + $nonce_action = 'autologin-' . $user_id . '-';
1608 +
1609 + return wp_verify_nonce( $nonce, $nonce_action . (int) ( time() / 60 ) )
1610 + || wp_verify_nonce( $nonce, $nonce_action . (int) ( time() / 60 - 1 ) );
1461 1611 }
1462 1612
1463 1613 /**
1464 1614 * Function that builds the redirect