| @@ -219,8 +219,16 @@ | ||
| 219 | 219 | if ( strpos( $_image_url, $content_url ) !== 0 ) { |
| 220 | 220 | return new WP_Error( 'invalid_image', __( 'Invalid image url.', 'userswp' ) ); |
| 221 | 221 | } |
| 222 | 222 | |
| 223 | + // Only allow cropping the image the current user just uploaded (normalized like $image_url). | |
| 224 | + $pending_key = '_uwp_pending_' . $type . '_upload'; | |
| 225 | + $pending_url = get_user_meta( get_current_user_id(), $pending_key, true ); | |
| 226 | + $pending_url = $pending_url ? str_replace( array( 'https://', 'http://' ), '', $this->normalize_url( esc_url( $pending_url ) ) ) : ''; | |
| 227 | + if ( empty( $pending_url ) || $pending_url !== $_image_url ) { | |
| 228 | + return new WP_Error( 'crop_session_expired', __( 'Your image upload could not be verified. Please upload the image again.', 'userswp' ) ); | |
| 229 | + } | |
| 230 | + | |
| 223 | 231 | $filetype = wp_check_filetype( $image_url ); |
| 224 | 232 | |
| 225 | 233 | if ( empty( $filetype['ext'] ) ) { |
| 226 | 234 | return new WP_Error( 'invalid_image', __( 'Invalid image type.', 'userswp' ) ); |
| @@ -281,8 +289,15 @@ | ||
| 281 | 289 | wp_die( esc_html__( 'Something went wrong. Please contact site admin.', 'userswp' ), 403 ); |
| 282 | 290 | } |
| 283 | 291 | |
| 284 | 292 | $cropped = uwp_resizeThumbnailImage( $thumb_image_location, $image_path, $x, $y, $w, $h, $scale ); |
| 293 | + | |
| 294 | + // Resize returns a path even on failure; bail before touching meta or files so the crop can be retried. | |
| 295 | + clearstatcache( true, $thumb_image_location ); | |
| 296 | + if ( ! is_file( $thumb_image_location ) ) { | |
| 297 | + return new WP_Error( 'crop_failed', __( 'Could not crop the image. Please try again.', 'userswp' ) ); | |
| 298 | + } | |
| 299 | + | |
| 285 | 300 | $cropped = str_replace( $upload_path, $upload_url, $cropped ); |
| 286 | 301 | |
| 287 | 302 | // Remove previous avatar/banner |
| 288 | 303 | $unlink_img = ''; |
| @@ -297,13 +312,34 @@ | ||
| 297 | 312 | } else { |
| 298 | 313 | uwp_update_usermeta( $user_id, 'banner_thumb', $cropped ); |
| 299 | 314 | } |
| 300 | 315 | |
| 301 | - if ( $unlink_img && $unlink_img != $thumb_image_location && is_file( $unlink_img ) && file_exists( $unlink_img ) ) { | |
| 302 | - @unlink( $unlink_img ); | |
| 303 | - $unlink_ori_img = str_replace( '_uwp_' . $type . '_thumb' . '.', '.', $unlink_img ); | |
| 304 | - if ( is_file( $unlink_ori_img ) && file_exists( $unlink_ori_img ) ) { | |
| 305 | - @unlink( $unlink_ori_img ); | |
| 316 | + $original_key = '_uwp_' . $type . '_original'; | |
| 317 | + $prev_original = get_user_meta( $user_id, $original_key, true ); | |
| 318 | + | |
| 319 | + delete_user_meta( get_current_user_id(), $pending_key ); | |
| 320 | + $relative_original = ltrim( wp_normalize_path( str_replace( wp_normalize_path( untrailingslashit( $upload_path ) ), '', wp_normalize_path( $image_path ) ) ), '/' ); | |
| 321 | + update_user_meta( $user_id, $original_key, $relative_original ); | |
| 322 | + | |
| 323 | + // Enforce containment inside uploads before deleting, matching upload_file_remove(). | |
| 324 | + $real_upload_path = realpath( $upload_path ); | |
| 325 | + $real_unlink_img = $unlink_img ? realpath( $unlink_img ) : false; | |
| 326 | + | |
| 327 | + if ( $real_upload_path && $real_unlink_img && realpath( $thumb_image_location ) !== $real_unlink_img | |
| 328 | + && false !== strpos( basename( $real_unlink_img ), $thumb_postfix . '.' ) | |
| 329 | + && 0 === strpos( $real_unlink_img, $real_upload_path . DIRECTORY_SEPARATOR ) | |
| 330 | + && is_file( $real_unlink_img ) ) { | |
| 331 | + wp_delete_file( $real_unlink_img ); | |
| 332 | + | |
| 333 | + // Delete the previous source only if it is the exact file this user cropped. | |
| 334 | + $unlink_ori_img = str_replace( $thumb_postfix . '.', '.', $real_unlink_img ); | |
| 335 | + $real_unlink_ori_img = realpath( $unlink_ori_img ); | |
| 336 | + $expected_original = $prev_original ? realpath( untrailingslashit( $upload_path ) . '/' . $prev_original ) : false; | |
| 337 | + if ( $expected_original && $real_unlink_ori_img && $expected_original === $real_unlink_ori_img | |
| 338 | + && realpath( $image_path ) !== $real_unlink_ori_img | |
| 339 | + && 0 === strpos( $real_unlink_ori_img, $real_upload_path . DIRECTORY_SEPARATOR ) | |
| 340 | + && is_file( $real_unlink_ori_img ) ) { | |
| 341 | + wp_delete_file( $real_unlink_ori_img ); | |
| 306 | 342 | } |
| 307 | 343 | } |
| 308 | 344 | } |
| 309 | 345 | |
| @@ -390,8 +426,13 @@ | ||
| 390 | 426 | } else { |
| 391 | 427 | // Do nothing |
| 392 | 428 | } |
| 393 | 429 | |
| 430 | + if ( in_array( $type, array( 'avatar', 'banner' ), true ) ) { | |
| 431 | + delete_user_meta( $user_id, '_uwp_' . $type . '_original' ); | |
| 432 | + delete_user_meta( get_current_user_id(), '_uwp_pending_' . $type . '_upload' ); | |
| 433 | + } | |
| 434 | + | |
| 394 | 435 | if ( is_admin() ) { |
| 395 | 436 | if ( $user_id == get_current_user_id() ) { |
| 396 | 437 | $redirect_url = admin_url( 'profile.php' ); |
| 397 | 438 | } else { |
| @@ -1216,8 +1257,20 @@ | ||
| 1216 | 1257 | } |
| 1217 | 1258 | } |
| 1218 | 1259 | } |
| 1219 | 1260 | |
| 1261 | + if ( wp_doing_ajax() && is_wp_error( $user ) && $this->wordfence_2fa_available() ) { | |
| 1262 | + $wfls_2fa = $this->check_wordfence_2fa( $user, $result ); | |
| 1263 | + if ( ! empty( $wfls_2fa ) ) { | |
| 1264 | + wp_send_json_success( | |
| 1265 | + array( | |
| 1266 | + 'html' => $wfls_2fa, | |
| 1267 | + 'is_2fa' => true, | |
| 1268 | + ) | |
| 1269 | + ); | |
| 1270 | + } | |
| 1271 | + } | |
| 1272 | + | |
| 1220 | 1273 | if ( is_wp_error( $user ) ) { |
| 1221 | 1274 | $message = aui()->alert( |
| 1222 | 1275 | array( |
| 1223 | 1276 | 'type' => 'error', |
| @@ -1436,8 +1489,110 @@ | ||
| 1436 | 1489 | |
| 1437 | 1490 | return ob_get_clean(); |
| 1438 | 1491 | } |
| 1439 | 1492 | |
| 1493 | + /** | |
| 1494 | + * Checks if the Wordfence Login Security module (2FA) is available. | |
| 1495 | + * | |
| 1496 | + * @since 1.2.5 | |
| 1497 | + * @package userswp | |
| 1498 | + * | |
| 1499 | + * @return bool | |
| 1500 | + */ | |
| 1501 | + public function wordfence_2fa_available() { | |
| 1502 | + return class_exists( '\WordfenceLS\Controller_Users' ) && class_exists( '\WordfenceLS\Controller_TOTP' ); | |
| 1503 | + } | |
| 1504 | + | |
| 1505 | + /** | |
| 1506 | + * Checks whether Wordfence's 2FA requires a verification code for the | |
| 1507 | + * failed login attempt and, if so, returns the markup for the code entry form. | |
| 1508 | + * | |
| 1509 | + * @since 1.2.5 | |
| 1510 | + * @package userswp | |
| 1511 | + * | |
| 1512 | + * @param WP_Error $error The error returned by wp_signon(). | |
| 1513 | + * @param array $result The validated login fields (username/password). | |
| 1514 | + * | |
| 1515 | + * @return string|void The 2FA form markup, or nothing if not applicable. | |
| 1516 | + */ | |
| 1517 | + public function check_wordfence_2fa( $error, $result ) { | |
| 1518 | + if ( 1 == uwp_get_option( 'disable_wordfence_2fa' ) ) { | |
| 1519 | + return; | |
| 1520 | + } | |
| 1521 | + | |
| 1522 | + if ( ! $this->wordfence_2fa_available() ) { | |
| 1523 | + return; | |
| 1524 | + } | |
| 1525 | + | |
| 1526 | + if ( ! is_wp_error( $error ) || 'wfls_twofactor_required' !== $error->get_error_code() ) { | |
| 1527 | + return; | |
| 1528 | + } | |
| 1529 | + | |
| 1530 | + $username = ! empty( $result['username'] ) ? $result['username'] : ''; | |
| 1531 | + if ( empty( $username ) ) { | |
| 1532 | + return; | |
| 1533 | + } | |
| 1534 | + | |
| 1535 | + $user = is_email( $username ) ? get_user_by( 'email', $username ) : get_user_by( 'login', $username ); | |
| 1536 | + if ( ! $user ) { | |
| 1537 | + return; | |
| 1538 | + } | |
| 1539 | + | |
| 1540 | + if ( ! \WordfenceLS\Controller_Users::shared()->has_2fa_active( $user ) ) { | |
| 1541 | + return; | |
| 1542 | + } | |
| 1543 | + | |
| 1544 | + if ( \WordfenceLS\Controller_Users::shared()->has_remembered_2fa( $user ) ) { | |
| 1545 | + return; | |
| 1546 | + } | |
| 1547 | + | |
| 1548 | + $login_nonce = wp_create_nonce( 'uwp-wfls-2fa-' . $user->ID ); | |
| 1549 | + | |
| 1550 | + ob_start(); | |
| 1551 | + ?> | |
| 1552 | + | |
| 1553 | + <div class="uwp-2fa-methods-wrap"> | |
| 1554 | + <form name="validate_2fa_form" id="validate_2fa_form" class="validate_2fa_form" action="" method="post" | |
| 1555 | + autocomplete="off"> | |
| 1556 | + <input type="hidden" name="provider" id="provider" value="wordfence"/> | |
| 1557 | + <input type="hidden" name="uwp-auth-id" id="uwp-auth-id" value="<?php echo esc_attr( $user->ID ); ?>"/> | |
| 1558 | + <input type="hidden" name="wp-auth-nonce" id="wp-auth-nonce" | |
| 1559 | + value="<?php echo esc_attr( $login_nonce ); ?>"/> | |
| 1560 | + | |
| 1561 | + <p><?php esc_html_e( 'Please enter the authentication code from your two-factor authentication app, or a recovery code, to login:', 'userswp' ); ?></p> | |
| 1562 | + | |
| 1563 | + <?php | |
| 1564 | + echo aui()->input( | |
| 1565 | + array( // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped | |
| 1566 | + 'type' => 'text', | |
| 1567 | + 'id' => 'authcode', | |
| 1568 | + 'name' => 'authcode', | |
| 1569 | + 'placeholder' => esc_attr__( 'Authentication Code', 'userswp' ), | |
| 1570 | + 'value' => '', | |
| 1571 | + 'label' => esc_html__( 'Authentication Code', 'userswp' ), | |
| 1572 | + 'extra_attributes' => array( | |
| 1573 | + 'autocomplete' => 'one-time-code', | |
| 1574 | + ), | |
| 1575 | + ) | |
| 1576 | + ); | |
| 1577 | + | |
| 1578 | + echo aui()->button( | |
| 1579 | + array( // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped | |
| 1580 | + 'type' => 'submit', | |
| 1581 | + 'class' => 'btn btn-primary btn-block text-uppercase uwp-2fa-submit', | |
| 1582 | + 'name' => 'submit', | |
| 1583 | + 'icon' => '', | |
| 1584 | + 'content' => esc_html__( 'Log In', 'userswp' ), | |
| 1585 | + ) | |
| 1586 | + ); | |
| 1587 | + ?> | |
| 1588 | + </form> | |
| 1589 | + </div> | |
| 1590 | + | |
| 1591 | + <?php | |
| 1592 | + return ob_get_clean(); | |
| 1593 | + } | |
| 1594 | + | |
| 1440 | 1595 | public function get_wp2fa_provider_for_user( $user ) { |
| 1441 | 1596 | if ( class_exists( '\WP2FA\Authenticator\Login' ) && method_exists( '\WP2FA\Authenticator\Login', 'get_available_providers_for_user' ) ) { |
| 1442 | 1597 | $provider = \WP2FA\Authenticator\Login::get_available_providers_for_user( $user ); |
| 1443 | 1598 | if ( is_array( $provider ) ) { |
| @@ -1501,8 +1656,77 @@ | ||
| 1501 | 1656 | |
| 1502 | 1657 | return false; |
| 1503 | 1658 | } |
| 1504 | 1659 | |
| 1660 | + /** | |
| 1661 | + * Validates the Wordfence 2FA code submitted from the uwp-2fa form and, | |
| 1662 | + * if valid, completes the login by setting the auth cookie. | |
| 1663 | + * | |
| 1664 | + * @since 1.2.5 | |
| 1665 | + * @package userswp | |
| 1666 | + * | |
| 1667 | + * @param WP_User $user The user attempting to complete 2FA login. | |
| 1668 | + * | |
| 1669 | + * @return void | |
| 1670 | + */ | |
| 1671 | + public function process_login_wordfence_2fa( $user ) { | |
| 1672 | + if ( ! $this->wordfence_2fa_available() ) { | |
| 1673 | + $message = aui()->alert( | |
| 1674 | + array( | |
| 1675 | + 'type' => 'error', | |
| 1676 | + 'content' => __( 'Invalid request! Please try again.', 'userswp' ), | |
| 1677 | + ) | |
| 1678 | + ); | |
| 1679 | + | |
| 1680 | + wp_send_json_error( array( 'message' => $message ) ); | |
| 1681 | + } | |
| 1682 | + | |
| 1683 | + $nonce = ( isset( $_POST['wp-auth-nonce'] ) ) ? sanitize_textarea_field( wp_unslash( $_POST['wp-auth-nonce'] ) ) : ''; | |
| 1684 | + | |
| 1685 | + if ( ! wp_verify_nonce( $nonce, 'uwp-wfls-2fa-' . $user->ID ) ) { | |
| 1686 | + $message = aui()->alert( | |
| 1687 | + array( | |
| 1688 | + 'type' => 'error', | |
| 1689 | + 'content' => __( 'Invalid request! Please try again.', 'userswp' ), | |
| 1690 | + ) | |
| 1691 | + ); | |
| 1692 | + | |
| 1693 | + wp_send_json_error( array( 'message' => $message ) ); | |
| 1694 | + } | |
| 1695 | + | |
| 1696 | + $code = isset( $_POST['authcode'] ) ? sanitize_text_field( wp_unslash( $_POST['authcode'] ) ) : ''; | |
| 1697 | + | |
| 1698 | + if ( empty( $code ) || true !== \WordfenceLS\Controller_TOTP::shared()->validate_2fa( $user, $code ) ) { | |
| 1699 | + do_action( 'wp_login_failed', $user->user_login ); | |
| 1700 | + | |
| 1701 | + $message = aui()->alert( | |
| 1702 | + array( | |
| 1703 | + 'type' => 'error', | |
| 1704 | + 'content' => __( 'Invalid verification code.', 'userswp' ), | |
| 1705 | + ) | |
| 1706 | + ); | |
| 1707 | + | |
| 1708 | + wp_send_json_error( array( 'message' => $message ) ); | |
| 1709 | + } | |
| 1710 | + | |
| 1711 | + $remember = ( isset( $_REQUEST['rememberme'] ) ) ? filter_var( $_REQUEST['rememberme'], FILTER_VALIDATE_BOOLEAN ) : false; | |
| 1712 | + | |
| 1713 | + // Complete the login the same way wp_signon() would have, now that 2FA has been verified. | |
| 1714 | + wp_set_auth_cookie( $user->ID, $remember ); | |
| 1715 | + wp_set_current_user( $user->ID ); | |
| 1716 | + | |
| 1717 | + do_action( 'wp_login', $user->user_login, $user ); | |
| 1718 | + | |
| 1719 | + $message = aui()->alert( | |
| 1720 | + array( | |
| 1721 | + 'type' => 'success', | |
| 1722 | + 'content' => __( 'Validation successful. Redirecting...', 'userswp' ), | |
| 1723 | + ) | |
| 1724 | + ); | |
| 1725 | + | |
| 1726 | + wp_send_json_success( array( 'message' => $message ) ); | |
| 1727 | + } | |
| 1728 | + | |
| 1505 | 1729 | public function process_login_2fa() { |
| 1506 | 1730 | global $wp2fa; |
| 1507 | 1731 | |
| 1508 | 1732 | if ( ! isset( $_POST['uwp-auth-id'], $_POST['wp-auth-nonce'] ) ) { |
| @@ -1522,8 +1746,20 @@ | ||
| 1522 | 1746 | |
| 1523 | 1747 | wp_send_json_error( array( 'message' => $message ) ); |
| 1524 | 1748 | } |
| 1525 | 1749 | |
| 1750 | + if ( isset( $_POST['provider'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing | |
| 1751 | + $provider = sanitize_textarea_field( wp_unslash( $_POST['provider'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing | |
| 1752 | + } else { | |
| 1753 | + $provider = ''; | |
| 1754 | + } | |
| 1755 | + | |
| 1756 | + if ( 'wordfence' === $provider ) { | |
| 1757 | + $this->process_login_wordfence_2fa( $user ); | |
| 1758 | + | |
| 1759 | + return; | |
| 1760 | + } | |
| 1761 | + | |
| 1526 | 1762 | $nonce = ( isset( $_POST['wp-auth-nonce'] ) ) ? sanitize_textarea_field( wp_unslash( $_POST['wp-auth-nonce'] ) ) : ''; |
| 1527 | 1763 | |
| 1528 | 1764 | if ( true !== \WP2FA\Authenticator\Login::verify_login_nonce( $user->ID, $nonce ) ) { |
| 1529 | 1765 | $message = aui()->alert( |
| @@ -1535,14 +1771,8 @@ | ||
| 1535 | 1771 | |
| 1536 | 1772 | wp_send_json_error( array( 'message' => $message ) ); |
| 1537 | 1773 | } |
| 1538 | 1774 | |
| 1539 | - if ( isset( $_POST['provider'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing | |
| 1540 | - $provider = sanitize_textarea_field( wp_unslash( $_POST['provider'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing | |
| 1541 | - } else { | |
| 1542 | - $provider = ''; | |
| 1543 | - } | |
| 1544 | - | |
| 1545 | 1775 | $error = ''; |
| 1546 | 1776 | |
| 1547 | 1777 | try { |
| 1548 | 1778 | $is_enabled = \WP2FA\Admin\Controllers\Settings::is_provider_enabled_for_role( \WP2FA\Admin\Helpers\User_Helper::get_user_role( $user ), $provider ); |
| @@ -1744,9 +1974,12 @@ | ||
| 1744 | 1974 | } |
| 1745 | 1975 | |
| 1746 | 1976 | do_action( 'uwp_after_validate', $result, 'forgot', $data ); |
| 1747 | 1977 | |
| 1748 | - $user_data = get_user_by( 'email', $data['email'] ); | |
| 1978 | + $login_or_email = trim( $data['email'] ); | |
| 1979 | + $user_data = is_email( $login_or_email ) | |
| 1980 | + ? get_user_by( 'email', $login_or_email ) | |
| 1981 | + : get_user_by( 'login', $login_or_email ); | |
| 1749 | 1982 | |
| 1750 | 1983 | // if no user we fake it and bail |
| 1751 | 1984 | if ( ! $user_data ) { |
| 1752 | 1985 | $args = apply_filters( |
| @@ -1752,9 +1985,9 @@ | ||
| 1752 | 1985 | $args = apply_filters( |
| 1753 | 1986 | 'uwp_forgot_error_message', |
| 1754 | 1987 | array( |
| 1755 | 1988 | 'type' => 'error', |
| 1756 | - 'content' => __( 'Invalid email or user doesn\'t exists.', 'userswp' ), | |
| 1989 | + 'content' => __( 'Invalid username/email or user doesn\'t exist.', 'userswp' ), | |
| 1757 | 1990 | ) |
| 1758 | 1991 | ); |
| 1759 | 1992 | |
| 1760 | 1993 | $message = aui()->alert( $args ); |
| @@ -2124,8 +2357,21 @@ | ||
| 2124 | 2357 | unset( $uploads_result[ $upload_file_key ] ); |
| 2125 | 2358 | } |
| 2126 | 2359 | } |
| 2127 | 2360 | |
| 2361 | + global $wpdb; | |
| 2362 | + $file_field_names = $wpdb->get_col( | |
| 2363 | + $wpdb->prepare( | |
| 2364 | + "SELECT htmlvar_name FROM " . uwp_get_table_prefix() . "uwp_form_fields WHERE form_type = %s AND field_type IN ('file','image')", | |
| 2365 | + 'account' | |
| 2366 | + ) | |
| 2367 | + ); | |
| 2368 | + foreach ( $file_field_names as $file_field_name ) { | |
| 2369 | + if ( isset( $result[ $file_field_name ] ) && ! isset( $uploads_result[ $file_field_name ] ) ) { | |
| 2370 | + unset( $result[ $file_field_name ] ); | |
| 2371 | + } | |
| 2372 | + } | |
| 2373 | + | |
| 2128 | 2374 | $result = array_merge( $result, $uploads_result ); |
| 2129 | 2375 | |
| 2130 | 2376 | $args = array( |
| 2131 | 2377 | 'ID' => get_current_user_id(), |
| @@ -2424,22 +2670,39 @@ | ||
| 2424 | 2670 | } |
| 2425 | 2671 | |
| 2426 | 2672 | $unlink_file = untrailingslashit( $upload_path ) . '/' . trim( $value, '/\\' ); |
| 2427 | 2673 | |
| 2428 | - if ( is_file( $unlink_file ) && file_exists( $unlink_file ) ) { | |
| 2429 | - wp_delete_file( $unlink_file ); | |
| 2674 | + // Canonicalize and enforce containment inside the uploads directory before deleting. | |
| 2675 | + $real_upload_path = realpath( $upload_path ); | |
| 2676 | + $real_unlink_file = realpath( $unlink_file ); | |
| 2430 | 2677 | |
| 2431 | - // For avatar/banner, also remove the original (non-thumb) file. | |
| 2678 | + if ( $real_upload_path && $real_unlink_file && is_file( $real_unlink_file ) | |
| 2679 | + && strpos( $real_unlink_file, $real_upload_path . DIRECTORY_SEPARATOR ) === 0 ) { | |
| 2680 | + wp_delete_file( $real_unlink_file ); | |
| 2681 | + | |
| 2682 | + // For avatar/banner, also remove the original (non-thumb) file, only if it is the exact file this user cropped. | |
| 2432 | 2683 | if ( $type ) { |
| 2433 | - $unlink_ori_file = str_replace( '_uwp_' . $type . '_thumb' . '.', '.', $unlink_file ); | |
| 2684 | + $unlink_ori_file = str_replace( '_uwp_' . $type . '_thumb' . '.', '.', $real_unlink_file ); | |
| 2685 | + $real_unlink_ori_file = realpath( $unlink_ori_file ); | |
| 2686 | + $prev_original = get_user_meta( $user_id, '_uwp_' . $type . '_original', true ); | |
| 2687 | + $expected_original = $prev_original ? realpath( untrailingslashit( $upload_path ) . '/' . $prev_original ) : false; | |
| 2434 | 2688 | |
| 2435 | - if ( is_file( $unlink_ori_file ) && file_exists( $unlink_ori_file ) ) { | |
| 2436 | - wp_delete_file( $unlink_ori_file ); | |
| 2689 | + if ( $expected_original && $real_unlink_ori_file && $expected_original === $real_unlink_ori_file | |
| 2690 | + && $real_unlink_ori_file !== $real_unlink_file | |
| 2691 | + && is_file( $real_unlink_ori_file ) | |
| 2692 | + && strpos( $real_unlink_ori_file, $real_upload_path . DIRECTORY_SEPARATOR ) === 0 ) { | |
| 2693 | + wp_delete_file( $real_unlink_ori_file ); | |
| 2437 | 2694 | } |
| 2438 | 2695 | } |
| 2439 | 2696 | } |
| 2440 | 2697 | } |
| 2441 | 2698 | |
| 2699 | + // Clear crop bookkeeping meta (pending upload is stored against the uploader). | |
| 2700 | + if ( $type ) { | |
| 2701 | + delete_user_meta( $user_id, '_uwp_' . $type . '_original' ); | |
| 2702 | + delete_user_meta( get_current_user_id(), '_uwp_pending_' . $type . '_upload' ); | |
| 2703 | + } | |
| 2704 | + | |
| 2442 | 2705 | wp_send_json_success(); |
| 2443 | 2706 | |
| 2444 | 2707 | wp_die(); |
| 2445 | 2708 | } |
| @@ -3917,17 +4180,26 @@ | ||
| 3917 | 4180 | $site_title = uwp_get_form_label( $field ); |
| 3918 | 4181 | $required_msg = ( ! empty( $field->is_required ) && $field->required_msg != '') ? __( stripslashes( $field->required_msg ), 'userswp' ) : ''; |
| 3919 | 4182 | $validation_text = ! empty( $field->validation_msg ) ? __( stripslashes( $field->validation_msg ), 'userswp' ) : ''; |
| 3920 | 4183 | |
| 4184 | + $is_forgot_email = ( $form_type === 'forgot' && $field->htmlvar_name === 'email' ); | |
| 4185 | + $input_type = $is_forgot_email ? 'text' : 'email'; | |
| 4186 | + if ( $is_forgot_email ) { | |
| 4187 | + $site_title = __( 'Username or Email', 'userswp' ); | |
| 4188 | + $placeholder = $site_title . ( ! empty( $field->is_required ) ? ' *' : '' ); | |
| 4189 | + } else { | |
| 4190 | + $placeholder = uwp_get_field_placeholder( $field ); | |
| 4191 | + } | |
| 4192 | + | |
| 3921 | 4193 | if ( $design_style ) { |
| 3922 | 4194 | $required = ! empty( $field->is_required ) ? ' <span class="text-danger">*</span>' : ''; |
| 3923 | 4195 | |
| 3924 | 4196 | echo aui()->input( |
| 3925 | 4197 | array( // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped |
| 3926 | - 'type' => 'email', | |
| 4198 | + 'type' => $input_type, | |
| 3927 | 4199 | 'id' => esc_attr( $field->htmlvar_name ), |
| 3928 | 4200 | 'name' => esc_attr( $field->htmlvar_name ), |
| 3929 | - 'placeholder' => esc_attr( uwp_get_field_placeholder( $field ) ), | |
| 4201 | + 'placeholder' => esc_attr( $placeholder ), | |
| 3930 | 4202 | 'title' => esc_html( $site_title ), |
| 3931 | 4203 | 'value' => esc_attr( wp_unslash( $value ) ), |
| 3932 | 4204 | 'required' => (bool) $field->is_required, |
| 3933 | 4205 | 'validation_text' => $validation_text != '' ? esc_attr( $validation_text ) : esc_attr( $required_msg ), |
| @@ -3963,9 +4235,9 @@ | ||
| 3963 | 4235 | |
| 3964 | 4236 | <input name="<?php echo esc_attr( $field->htmlvar_name ); ?>" |
| 3965 | 4237 | class="<?php echo esc_attr( $field->css_class ); ?> uwp_textfield <?php echo esc_attr( $bs_form_control ); ?>" |
| 3966 | 4238 | id="<?php echo esc_attr( $field->htmlvar_name ); ?>" |
| 3967 | - placeholder="<?php echo esc_attr( uwp_get_field_placeholder( $field ) ); ?>" | |
| 4239 | + placeholder="<?php echo esc_attr( $placeholder ); ?>" | |
| 3968 | 4240 | value="<?php echo esc_attr( stripslashes( $value ) ); ?>" |
| 3969 | 4241 | title="<?php echo esc_attr( $site_title ); ?>" |
| 3970 | 4242 | <?php |
| 3971 | 4243 | if ( $field->is_required == 1 ) { |
| @@ -3971,9 +4243,9 @@ | ||
| 3971 | 4243 | if ( $field->is_required == 1 ) { |
| 3972 | 4244 | echo 'required="required"'; |
| 3973 | 4245 | } |
| 3974 | 4246 | ?> |
| 3975 | - type="email" | |
| 4247 | + type="<?php echo esc_attr( $input_type ); ?>" | |
| 3976 | 4248 | /> |
| 3977 | 4249 | <span class="uwp_message_note"><?php echo wp_kses_post( uwp_get_field_description( $field ) ); ?></span> |
| 3978 | 4250 | <?php if ( $field->is_required ) { ?> |
| 3979 | 4251 | <span class="uwp_message_error invalid-feedback"><?php echo esc_html__( stripslashes( $field->required_msg ), 'userswp' ); ?></span> |