Source: includes/core/class-permalinks.php

<?php
namespace um\core;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

if ( ! class_exists( 'um\core\Permalinks' ) ) {

	/**
	 * Class Permalinks
	 * @package um\core
	 */
	class Permalinks {

		/**
		 * @var
		 */
		var $core;

		/**
		 * @var
		 */
		var $current_url;

		/**
		 * Permalinks constructor.
		 */
		public function __construct() {
			add_action( 'init',  array( &$this, 'set_current_url' ), 0 );

			add_action( 'init',  array( &$this, 'check_for_querystrings' ), 1 );

			// don't use lower than 2 priority because there is sending email inside, but Action Scheduler is init on 1st priority.
			add_action( 'init',  array( &$this, 'activate_account_via_email_link' ), 2 );
		}

		/**
		 * Set current URL variable
		 */
		public function set_current_url() {
			$this->current_url = $this->get_current_url();
		}

		/**
		 * Get query as array
		 *
		 * @return array
		 */
		public function get_query_array() {
			$parts = parse_url( $this->get_current_url() );
			if ( isset( $parts['query'] ) ) {
				parse_str( $parts['query'], $query );
				return $query;
			}

			return array();
		}

		/**
		 * Get current URL anywhere
		 *
		 * @param bool $no_query_params
		 *
		 * @return string
		 */
		public function get_current_url( $no_query_params = false ) {
			//use WP native function for fill $_SERVER variables by correct values
			wp_fix_server_vars();

			//check if WP-CLI there isn't set HTTP_HOST, use localhost instead
			if ( defined( 'WP_CLI' ) && WP_CLI ) {
				$host = isset( $_SERVER['HTTP_HOST'] ) ? $_SERVER['HTTP_HOST'] : 'localhost';
			} else {
				if ( isset( $_SERVER['HTTP_HOST'] ) ) {
					$host = $_SERVER['HTTP_HOST'];
				} else {
					$host = 'localhost';
				}
			}

			$page_url = ( is_ssl() ? 'https://' : 'http://' ) . $host . $_SERVER['REQUEST_URI'];

			if ( false !== $no_query_params ) {
				$page_url = strtok( $page_url, '?' );
			}

			/**
			 * Filters current page URL.
			 *
			 * @param {string} $page_url        Current page URL.
			 * @param {bool}   $no_query_params Ignore $_GET attributes in URL. false !== ignore.
			 *
			 * @return {string} Current page URL.
			 *
			 * @since 1.3.x
			 * @hook um_get_current_page_url
			 *
			 * @example <caption>Add your custom $_GET attribute to all links.</caption>
			 * function my_um_get_current_page_url( $page_url, $no_query_params ) {
			 *     $page_url = add_query_arg( '{attr_value}', '{attr_key}', $page_url ); // replace to your custom value and key.
			 *     return $page_url;
			 * }
			 * add_filter( 'um_get_current_page_url', 'my_um_get_current_page_url', 10, 2 );
			 */
			return apply_filters( 'um_get_current_page_url', $page_url, $no_query_params );
		}

		/**
		 * Activates an account via email
		 */
		public function activate_account_via_email_link() {
			if ( isset( $_REQUEST['act'] ) && 'activate_via_email' === sanitize_key( $_REQUEST['act'] ) && isset( $_REQUEST['hash'] ) && is_string( $_REQUEST['hash'] ) && strlen( $_REQUEST['hash'] ) == 40 &&
				 isset( $_REQUEST['user_id'] ) && is_numeric( $_REQUEST['user_id'] ) ) { // valid token

				$user_id = absint( $_REQUEST['user_id'] );
				if ( is_user_logged_in() && get_current_user_id() !== $user_id ) {
					// Cannot activate another user account. Please log out and try again.
					wp_safe_redirect( um_user_profile_url( get_current_user_id() ) );
					exit;
				}

				delete_option( "um_cache_userdata_{$user_id}" );

				$account_secret_hash = get_user_meta( $user_id, 'account_secret_hash', true );
				if ( empty( $account_secret_hash ) || strtolower( sanitize_text_field( $_REQUEST['hash'] ) ) !== strtolower( $account_secret_hash ) ) {
					wp_safe_redirect( add_query_arg( 'err', 'activation_link_used', um_get_core_page( 'login' ) ) );
					exit;
				}

				$account_secret_hash_expiry = get_user_meta( $user_id, 'account_secret_hash_expiry', true );
				if ( ! empty( $account_secret_hash_expiry ) && time() > $account_secret_hash_expiry ) {
					wp_safe_redirect( add_query_arg( 'err', 'activation_link_expired', um_get_core_page( 'login' ) ) );
					exit;
				}

				$redirect              = um_get_core_page( 'login', 'account_active' );
				$set_password_required = get_user_meta( $user_id, 'um_set_password_required', true );

				um_fetch_user( $user_id );
				UM()->common()->users()->approve( $user_id, true );
				if ( ! empty( $set_password_required ) ) {
					$redirect = um_user( 'password_reset_link' );
				}
				um_reset_user();

				$user_role      = UM()->roles()->get_priority_user_role( $user_id );
				$user_role_data = UM()->roles()->role_data( $user_role );

				// log in automatically
				$login = ! empty( $user_role_data['login_email_activate'] ); // Role setting "Login user after validating the activation link?"
				if ( ! is_user_logged_in() && $login ) {
					UM()->user()->auto_login( $user_id );
				}

				/**
				 * UM hook
				 *
				 * @type action
				 * @title um_after_email_confirmation
				 * @description Action on user activation
				 * @input_vars
				 * [{"var":"$user_id","type":"int","desc":"User ID"}]
				 * @change_log
				 * ["Since: 2.0"]
				 * @usage add_action( 'um_after_email_confirmation', 'function_name', 10, 1 );
				 * @example
				 * <?php
				 * add_action( 'um_after_email_confirmation', 'my_after_email_confirmation', 10, 1 );
				 * function my_after_email_confirmation( $user_id ) {
				 *     // your code here
				 * }
				 * ?>
				 */
				do_action( 'um_after_email_confirmation', $user_id );

				if ( empty( $set_password_required ) ) {
					$redirect = empty( $user_role_data['url_email_activate'] ) ? um_get_core_page( 'login', 'account_active' ) : trim( $user_role_data['url_email_activate'] ); // Role setting "URL redirect after email activation"
				}
				$redirect = apply_filters( 'um_after_email_confirmation_redirect', $redirect, $user_id, $login );

				exit( wp_redirect( $redirect ) );
			}
		}

		/**
		 * Makes an activate link for any user
		 *
		 * @return bool|string
		 */
		public function activate_url() {
			if ( ! um_user( 'account_secret_hash' ) ) {
				return false;
			}

			/**
			 * UM hook
			 *
			 * @type filter
			 * @title um_activate_url
			 * @description Change activate user URL
			 * @input_vars
			 * [{"var":"$url","type":"string","desc":"Activate URL"}]
			 * @change_log
			 * ["Since: 2.0"]
			 * @usage
			 * <?php add_filter( 'um_activate_url', 'function_name', 10, 1 ); ?>
			 * @example
			 * <?php
			 * add_filter( 'um_activate_url', 'my_activate_url', 10, 1 );
			 * function my_activate_url( $url ) {
			 *     // your code here
			 *     return $url;
			 * }
			 * ?>
			 */
			$url =  apply_filters( 'um_activate_url', home_url() );
			$url =  add_query_arg( 'act', 'activate_via_email', $url );
			$url =  add_query_arg( 'hash', um_user( 'account_secret_hash' ), $url );
			$url =  add_query_arg( 'user_id', um_user( 'ID' ), $url );

			return $url;
		}

		/**
		 * Checks for UM query strings
		 */
		public function check_for_querystrings() {
			if ( isset( $_REQUEST['message'] ) ) {
				UM()->shortcodes()->message_mode = true;
			}
		}

		/**
		 * Add a query param to url
		 *
		 * @param $key
		 * @param $value
		 *
		 * @return string
		 */
		public function add_query( $key, $value ) {
			$this->current_url = add_query_arg( $key, $value, $this->get_current_url() );
			return $this->current_url;
		}

		/**
		 * Remove a query param from url
		 *
		 * @param $key
		 * @param $value
		 *
		 * @return string
		 */
		public function remove_query( $key, $value ) {
			$this->current_url = remove_query_arg( $key, $this->current_url );
			return $this->current_url;
		}

		/**
		* @param string $slug
		*
		* @return int|bool
		*/
		public function slug_exists_user_id( $slug ) {
			global $wpdb;

			$permalink_base = UM()->options()->get( 'permalink_base' );
			if ( 'custom_meta' === $permalink_base ) {
				$custom_meta = UM()->options()->get( 'permalink_base_custom_meta' );
				if ( empty( $custom_meta ) ) {
					// Set default permalink base if custom meta is empty.
					$permalink_base = 'user_login';
					$meta_key       = 'um_user_profile_url_slug_' . $permalink_base;
				} else {
					$meta_key = $custom_meta;
				}
			} else {
				$meta_key = 'um_user_profile_url_slug_' . $permalink_base;
			}

			$user_id = $wpdb->get_var(
				$wpdb->prepare(
					"SELECT user_id
					FROM {$wpdb->usermeta}
					WHERE meta_key = %s AND
						  meta_value = %s
					ORDER BY umeta_id ASC
					LIMIT 1",
					$meta_key,
					$slug
				)
			);

			if ( ! empty( $user_id ) ) {
				return absint( $user_id );
			}

			return false;
		}

		/**
		 * Get Profile Permalink
		 *
		 * @param  string $slug
		 *
		 * @return string
		 */
		public function profile_permalink( $slug ) {
			/**
			 * Filters user profile URL externally with own logic.
			 *
			 * @since 2.6.3
			 * @hook um_external_profile_url
			 *
			 * @param {bool|string} $profile_url Profile URL.
			 * @param {string}      $slug        User profile slug.
			 *
			 * @return {string} Profile URL.
			 *
			 * @example <caption>Change profile URL to your custom link and ignore native profile permalink handlers.</caption>
			 * function my_um_external_profile_url( $profile_url, $slug ) {
			 *     $profile_url = '{some your custom URL}'; // replace to your custom link.
			 *     return $profile_url;
			 * }
			 * add_filter( 'um_external_profile_url', 'my_um_external_profile_url', 10, 2 );
			 */
			$external_profile_url = apply_filters( 'um_external_profile_url', false, $slug );
			if ( false !== $external_profile_url ) {
				return ! empty( $external_profile_url ) ? $external_profile_url : '';
			}

			$page_id     = UM()->config()->permalinks['user'];
			$profile_url = get_permalink( $page_id );

			/**
			 * Filters the base URL of the UM profile page.
			 *
			 * @since 1.3.x
			 * @deprecated 2.6.3 Use <a href="https://developer.wordpress.org/reference/hooks/post_link/" target="_blank" title="'post_link' hook article on developer.wordpress.org">'post_link'</a> instead.
			 * @hook um_localize_permalink_filter
			 * @todo fully remove since 2.7.0
			 *
			 * @param {string} $profile_url Profile URL.
			 * @param {int}    $page_id     Profile Page ID.
			 *
			 * @return {string} Profile URL.
			 *
			 * @example <caption>Change profile base URL to your custom link.</caption>
			 * function my_localize_permalink( $profile_url, $page_id ) {
			 *     $profile_url = '{some your custom URL}'; // replace to your custom link.
			 *     return $profile_url;
			 * }
			 * add_filter( 'um_localize_permalink_filter', 'my_localize_permalink', 10, 2 );
			 */
			$profile_url = apply_filters( 'um_localize_permalink_filter', $profile_url, $page_id );

			if ( UM()->is_permalinks ) {
				$profile_url  = trailingslashit( untrailingslashit( $profile_url ) );
				$profile_url .= trailingslashit( strtolower( $slug ) );
			} else {
				$profile_url = add_query_arg( 'um_user', strtolower( $slug ), $profile_url );
			}

			/**
			 * Filters user profile URL.
			 *
			 * @since 2.6.3
			 * @hook um_profile_permalink
			 *
			 * @param {string} $profile_url Profile URL.
			 * @param {int}    $page_id     Profile Page ID.
			 * @param {string} $slug        User profile slug.
			 *
			 * @return {string} Profile URL.
			 *
			 * @example <caption>Change profile URL to your custom link.</caption>
			 * function my_um_profile_permalink( $profile_url, $page_id, $slug ) {
			 *     $profile_url = '{some your custom URL}'; // replace to your custom link.
			 *     return $profile_url;
			 * }
			 * add_filter( 'um_profile_permalink', 'my_um_profile_permalink', 10, 3 );
			 */
			$profile_url = apply_filters( 'um_profile_permalink', $profile_url, $page_id, $slug );

			return ! empty( $profile_url ) ? $profile_url : '';
		}

		/**
		 * Generate profile slug
		 *
		 * @param string $full_name
		 * @param string $first_name
		 * @param string $last_name
		 * @return string
		 */
		public function profile_slug( $full_name, $first_name, $last_name ) {
			$permalink_base = UM()->options()->get( 'permalink_base' );

			$user_in_url = '';

			$full_name = str_replace( array( "'", '&', '/' ), '', $full_name );

			switch ( $permalink_base ) {
				case 'name': // dotted
					$full_name_slug = $full_name;
					$difficulties = 0;

					if ( strpos( $full_name, '.' ) > -1 ) {
						$full_name = str_replace( ".", "_", $full_name );
						$difficulties++;
					}

					$full_name = strtolower( str_replace( " ", ".", $full_name ) );

					if ( strpos( $full_name, '_.' ) > -1 ) {
						$full_name = str_replace( '_.', '_', $full_name );
						$difficulties++;
					}

					$full_name_slug = str_replace( '-', '.', $full_name_slug );
					$full_name_slug = str_replace( ' ', '.', $full_name_slug );
					$full_name_slug = str_replace( '..', '.', $full_name_slug );

					if ( strpos( $full_name, '.' ) > -1 ) {
						$full_name = str_replace( '.', ' ', $full_name );
						$difficulties++;
					}

					$user_in_url = rawurlencode( $full_name_slug );

					break;

				case 'name_dash': // dashed
					$difficulties = 0;

					$full_name_slug = strtolower( $full_name );

					// if last name has dashed replace with underscore
					if ( strpos( $last_name, '-' ) > -1 && strpos( $full_name, '-' ) > -1 ) {
						$difficulties++;
						$full_name = str_replace( '-', '_', $full_name );
					}
					// if first name has dashed replace with underscore
					if ( strpos( $first_name, '-' ) > -1 && strpos( $full_name, '-' ) > -1 ) {
						$difficulties++;
						$full_name = str_replace( '-', '_', $full_name );
					}
					// if name has space, replace with dash
					$full_name_slug = str_replace( ' ', '-', $full_name_slug );

					// if name has period
					if ( strpos( $last_name, '.' ) > -1 && strpos( $full_name, '.' ) > -1 ) {
						$difficulties++;
					}

					$full_name_slug = str_replace( '.', '-', $full_name_slug );
					$full_name_slug = str_replace( '--', '-', $full_name_slug );

					$user_in_url = rawurlencode( $full_name_slug );

					break;

				case 'name_plus': // plus
					$difficulties = 0;

					$full_name_slug = strtolower( $full_name );

					// if last name has dashed replace with underscore
					if ( strpos( $last_name, '+' ) > -1 && strpos( $full_name, '+' ) > -1 ) {
						$difficulties++;
						$full_name = str_replace( '-', '_', $full_name );
					}
					// if first name has dashed replace with underscore
					if ( strpos( $first_name, '+' ) > -1 && strpos( $full_name, '+' ) > -1 ) {
						$difficulties++;
						$full_name = str_replace( '-', '_', $full_name );
					}
					if ( strpos( $last_name, '-' ) > -1 || strpos( $first_name, '-' ) > -1 || strpos( $full_name, '-' ) > -1 ) {
						$difficulties++;
					}
					// if name has space, replace with dash
					$full_name_slug = str_replace( ' ', '+', $full_name_slug );
					$full_name_slug = str_replace( '-', '+', $full_name_slug );

					// if name has period
					if ( strpos( $last_name, '.' ) > -1 && strpos( $full_name, '.' ) > -1 ) {
						$difficulties++;
					}

					$full_name_slug = str_replace( '.', '+', $full_name_slug );
					$full_name_slug = str_replace( '++', '+', $full_name_slug );

					$user_in_url = $full_name_slug;

					break;
			}

			return $user_in_url;
		}
	}
}