Files
wp-multisite-waas/inc/checkout/class-legacy-checkout.php
David Stone d88e50df38 Prep Plugin for release on WordPress.org (#23)
* Update translation text domain
* Escape everything that should be escaped.
* Add nonce checks where needed.
* Sanitize all inputs.
* Apply Code style changes across the codebase.
* Correct many deprecation notices.
* Optimize load order of many filters.
* Add Proper Build script
* Use emojii flags
* Fix i18n deprecation  notice for translating too early
* Put all scripts in footer and load async
2025-04-14 11:36:46 -06:00

1347 lines
33 KiB
PHP

<?php
/**
* Handles the processing of new membership purchases.
*
* @package WP_Ultimo
* @subpackage Checkout
* @since 2.0.0
*/
// phpcs:disable
namespace WP_Ultimo\Checkout;
// Exit if accessed directly
defined('ABSPATH') || exit;
use \WP_Ultimo\Checkout\Cart;
/**
* Handles the processing of new membership purchases.
*
* @since 2.0.0
*/
class Legacy_Checkout {
use \WP_Ultimo\Traits\Singleton;
/**
* Holds checkout errors.
*
* @since 2.0.0
* @var \WP_Error|null
*/
public $errors;
/**
* Holds checkout errors.
*
* @since 2.0.0
* @var \WP_Error|null
*/
public $results;
/**
* Current step of the signup flow.
*
* @since 2.0.0
* @var string
*/
public $step;
/**
* List of steps for the signup flow.
*
* @since 2.0.0
* @var array
*/
public $steps;
/**
* Product being purchased, if that exists.
*
* @since 2.0.0
* @var null|\WP_Ultimo\Models\Product
*/
public $product;
/**
* Session object.
*
* @since 2.0.0
* @var \WP_Ultimo\Session.
*/
protected $session;
/**
* Page templates to add.
*
* We use this to inject the legacy-signup.php page template option
* onto the post/page edit page on the main site.
*
* @since 2.0.0
* @var array
*/
protected $templates;
/**
* Initializes the Checkout singleton and adds hooks.
*
* @since 2.0.0
* @return void
*/
public function init(): void {
$this->session = wu_get_session('signup');
$this->templates = [
'signup-main.php' => __('WP Multisite WaaS Legacy Signup', 'wp-multisite-waas'),
];
// add_filter('request', array($this, 'maybe_render_legacy_signup'));
add_action('wu_signup_enqueue_scripts', [$this, 'register_scripts']);
add_filter('theme_page_templates', [$this, 'add_new_template']);
// Add a filter to the save post to inject out template into the page cache
add_filter('wp_insert_post_data', [$this, 'register_legacy_templates']);
// Add a filter to the template include to determine if the page has our
// template assigned and return it's path
add_filter('template_include', [$this, 'view_legacy_template']);
}
/**
* Adds our page templates to the page template dropdown.
*
* @since 2.0.0
*
* @param array $posts_templates Existing page templates.
* @return array
*/
public function add_new_template($posts_templates) {
if (is_main_site()) {
$posts_templates = array_merge($posts_templates, $this->templates);
}
return $posts_templates;
}
/**
* Adds our template to the pages cache in order to trick WordPress
* into thinking the template file exists where it doesn't really exist.
*
* @since 2.0.0
*
* @param array $atts Post data.
* @return array
*/
public function register_legacy_templates($atts) {
// Create the key used for the themes cache
$cache_key = 'page_templates-' . md5(get_theme_root() . '/' . get_stylesheet());
// Retrieve the cache list.
// If it doesn't exist, or it's empty prepare an array
$templates = wp_get_theme()->get_page_templates();
if (empty($templates)) {
$templates = [];
}
// New cache, therefore remove the old one
wp_cache_delete($cache_key, 'themes');
// Now add our template to the list of templates by merging our templates
// with the existing templates array from the cache.
$templates = array_merge($templates, $this->templates);
// Add the modified cache to allow WordPress to pick it up for listing
// available templates
wp_cache_add($cache_key, $templates, 'themes', 1800);
return $atts;
}
/**
* Checks if our custom template is assigned to the page and display it.
*
* @since 2.0.0
*
* @param string $template The template set to a given page.
* @return string
*/
public function view_legacy_template($template) {
// Return the search template if we're searching (instead of the template for the first result)
if (is_search()) {
return $template;
}
// Get global post
global $post, $signup;
// Return template if post is empty
if (!$post) {
return $template;
}
$template_slug = get_post_meta($post->ID, '_wp_page_template', true);
// Return default template if we don't have a custom one defined
if (!isset($this->templates[$template_slug])) {
return $template;
}
$file = wu_path("views/legacy/signup/$template_slug");
// Just to be safe, we check if the file exist first
if (file_exists($file)) {
return $file;
}
// Return template
return $template;
}
/**
* Loads the necessary scripts.
*
* @since 2.0.0
* @return void
*/
public function register_scripts(): void {
wp_enqueue_script('wu-block-ui');
wp_register_script('wu-legacy-signup', wu_get_asset('legacy-signup.js', 'js'), ['wu-functions']);
wp_localize_script('wu-legacy-signup', 'wpu', [
'default_pricing_option' => 1,
]);
wp_enqueue_script('wu-legacy-signup');
wp_enqueue_style('legacy-signup', wu_get_asset('legacy-signup.css', 'css'), ['dashicons', 'install', 'admin-bar']);
wp_enqueue_style('legacy-shortcodes', wu_get_asset('legacy-shortcodes.css', 'css'), ['dashicons', 'install']);
wp_add_inline_style('legacy-signup', $this->get_legacy_dynamic_styles());
// Do not get the login if the first step
if ('plan' != $this->step) {
wp_enqueue_style('login');
}
wp_enqueue_style('common');
}
/**
* Adds the additional dynamic styles.
*
* @since 2.0.0
* @return string
*/
public function get_legacy_dynamic_styles() {
/**
* Get the Colors to be using.
*/
$primary_color = wu_color(wu_get_setting('primary_color', '#00a1ff'));
$accent_color = wu_color(wu_get_setting('accent_color', '#78b336'));
$accent_color_2 = wu_color($accent_color->darken(4));
ob_start();
// phpcs:disable
?>
.wu-content-plan .plan-tier h4 {
background-color: #<?php echo $primary_color->getHex(); ?>;
color: <?php echo $primary_color->isDark() ? "white" : "#333"; ?> !important;
}
.wu-content-plan .plan-tier.callout h6 {
background-color: #<?php echo $accent_color->getHex(); ?>;
color: <?php echo $accent_color->isDark() ? "#f9f9f9" : "rgba(39,65,90,.5)"; ?> !important;
}
.wu-content-plan .plan-tier.callout h4 {
background-color: #<?php echo $accent_color_2->getHex(); ?>;
color: <?php echo $accent_color->isDark() ? "white" : "#333"; ?> !important;
}
<?php
// phpcs:enable
return ob_get_clean();
}
/**
* Checks if we should pre-fill checkout fields based on the request.
*
* We do a couple of clever things here:
* 1. We check for a plan slug right after the checkout/slug of the main page.
*
* @since 2.0.0
*
* @param array $request WordPress request.
* @return array
*/
public function maybe_render_legacy_signup($request) {
$checkout_page_slug = 'register';
$page_name = $request['pagename'] ?? '';
if (str_starts_with((string) $page_name, $checkout_page_slug)) {
$page = explode('/', (string) $page_name);
/**
* Product passed
*
* @todo needs to check for frequency and unit.
*/
if (isset($page[1])) {
$product_slug = $page[1];
$product = wu_get_product_by_slug($product_slug);
$this->product = $product;
}
$request['pagename'] = $checkout_page_slug;
return $this->legacy_signup();
}
return $request;
}
/**
* Renders the legacy checkout.
*
* @since 2.0.0
* @return void
*/
public function legacy_signup(): void {
status_header(200);
$this->session = wu_get_session('signup');
$this->session->set('form', ['not-empty']);
// Apply a filter so we can add steps in the future
$this->steps = $this->get_steps();
// Set the current step based on the get
$this->step = $this->get_current_step();
$this->handle_post();
wu_get_template(
'legacy/signup/signup-main',
[
'signup' => $this,
]
);
exit;
}
/**
* Check Geolocation
*
* @return void
*/
public function check_geolocation(): void {
$location = \WP_Ultimo\Geolocation::geolocate_ip();
$this->session->set('geolocation', $location);
$allowed_countries = wu_get_setting('allowed_countries');
if (isset($location['country']) && $location['country'] && $allowed_countries) {
if ( ! in_array($location['country'], $allowed_countries, true)) {
wp_die(apply_filters('wu_geolocation_error_message', __('Sorry. Our service is not allowed in your country.', 'wp-multisite-waas')));
}
}
}
/**
* Gets the info for the current step.
*
* @since 2.0.0
* @return array
*/
protected function get_current_step_info() {
return $this->steps[ $this->step ];
}
/**
* Handles a post submission.
*
* @since 2.0.0
* @return void
*/
protected function handle_post() {
$is_save = wu_request('save_step');
$current_step = $this->get_current_step_info();
/**
* If we are in the middle of a saving request, we need to call the handler
*/
if ($is_save || $current_step['hidden']) {
/** Checks if the view has a handler of its own */
if (isset($current_step['handler']) && $current_step['handler']) {
$handler_function = $current_step['handler'];
} else {
$handler_function = [$this, 'default_save'];
}
/** Allows for handler rewrite */
$handler_function = apply_filters("wu_signup_step_handler_$this->step", $handler_function);
call_user_func($handler_function);
}
}
/**
* The first invisible step, handles the creation of the transient saver
*
* @since 1.4.0
* @return void
*/
public function begin_signup(): void {
/**
* Check Geo-location
*/
$this->check_geolocation();
/** Create the unique ID we well use from now on */
$uniqid = uniqid('', true);
/** Initializes the content holder with the honeypot unique id */
$content = [
'honeypot_id' => uniqid(''),
];
/**
* Saves the coupon code in the request, only if that option is available
*/
if (isset($_REQUEST['coupon']) && $_REQUEST['coupon'] && wu_get_setting('enable_coupon_codes', 'url_and_field') != 'disabled') {
// Adds to the payload
$content['coupon'] = $_REQUEST['coupon'];
}
/**
* Check if user came from a pricing select table
*/
if (isset($_REQUEST['plan_id']) && isset($_REQUEST['plan_freq']) && WU_Gateway::check_frequency($_REQUEST['plan_freq'])) {
$content['plan_id'] = $_REQUEST['plan_id'];
$content['plan_freq'] = $_REQUEST['plan_freq'];
$content['skip_plan'] = true;
}
/**
* Check if we only have one plan and the skip_plan enabled
*/
$plans = wu_get_plans();
if (wu_get_setting('skip_plan', false) && count($plans) === 1) {
$billing_frequency = wu_get_setting('default_pricing_option', 1);
$plan = reset($plans);
// Append that to the content
$content['plan_id'] = $plan->id;
$content['plan_freq'] = $billing_frequency;
$content['skip_plan'] = true;
$_REQUEST['skip_plan'] = 1;
}
/**
* Check if we are settings the template via the URL
*
* @since 1.7.3
*/
if (isset($_REQUEST['template_id']) && wu_get_setting('allow_template')) {
// Check if the template is valid
$site = new WU_Site_Template($_REQUEST['template_id']);
if ($site->is_template) {
$content['template'] = $_REQUEST['template_id'];
$content['skip_template_selection'] = true;
}
}
$this->session->set('form', $content);
/** Go to the next step */
$this->next_step();
}
/**
* Check if the current page is a customizer page.
*/
public static function is_customizer(): bool {
$exclude_list = apply_filters('wu_replace_signup_urls_exclude', ['wu-signup-customizer-preview']);
foreach ($exclude_list as $replace_word) {
if (isset($_GET[ $replace_word ])) {
return true;
}
}
return false;
}
/**
* Returns the first step of the signup process
*
* @return string
*/
public function get_first_step() {
$keys = array_keys($this->get_steps());
if (isset($keys[1])) {
return $keys[1];
} else {
return false;
}
}
/**
* Get the current step
*
* @return string
*/
public function get_current_step() {
$current_step = wu_request('step', current(array_keys($this->steps)));
// Always get the first step for the customizer //
if (static::is_customizer()) {
$current_step = $this->get_first_step();
}
return apply_filters('wu_current_step', $current_step);
}
/**
* Includes the template for that particular step; If none is set (false), includes the default template
*
* @param string $step The current step.
* @return void
*/
public function get_step_view($step): void {
$transient = $this->session->get('form');
$geo = $this->session->get('geolocation');
/**
* Set the errors
*/
if (null === $this->results) {
$this->results = ['errors' => new \WP_Error()];
}
if (empty($_POST)) {
$this->results = array_merge($this->results, $transient);
}
/**
* Builds the array containing the available elements inside the template
*/
$args = [
'signup' => $this,
'transient' => $transient,
'fields' => $this->steps[ $step ]['fields'] ?? [],
'results' => $this->results,
];
/**
* Checks if anything is passed to the view element
*/
if (isset($this->steps[ $step ]['view']) && $this->steps[ $step ]['view']) {
wu_get_template('legacy/signup/steps/' . $this->steps[ $step ]['view'], $args);
} else {
$found = locate_template("wp-ultimo/signup/steps/step-$step.php");
/**
* Let's try to locate a custom template on the user's theme. If it's there, we use it instead
*/
if ($found) {
wu_get_template("legacy/signup/steps/step-$step", $args);
} else {
wu_get_template('legacy/signup/steps/step-default', $args);
}
}
}
/**
* Set and return the steps and fields of each step.
*
* @since 2.0.0
*
* @param boolean $include_hidden If we should return hidden steps as well.
* @param boolean $filtered If we should apply filters.
* @return array
*/
public function get_steps($include_hidden = true, $filtered = true) {
// Set the Steps
$steps = [];
// Plan Selector
$steps['plan'] = [
'name' => __('Pick a Plan', 'wp-multisite-waas'),
'desc' => __('Which one of our amazing plans you want to get?', 'wp-multisite-waas'),
'view' => 'step-plans',
'handler' => [$this, 'plans_save'],
'order' => 10,
'fields' => false,
'core' => true,
];
$site_templates = [
2,
];
// We add template selection if this has template
if ($site_templates) {
$steps['template'] = [
'name' => __('Template Selection', 'wp-multisite-waas'),
'desc' => __('Select the base template of your new site.', 'wp-multisite-waas'),
'view' => 'step-template',
'order' => 20,
'handler' => false,
'core' => true,
];
}
// Domain registering
$steps['domain'] = [
'name' => __('Site Details', 'wp-multisite-waas'),
'desc' => __('Ok, now it\'s time to pick your site url and title!', 'wp-multisite-waas'),
'handler' => [$this, 'domain_save'],
'view' => false,
'order' => 30,
'core' => true,
'fields' => apply_filters(
'wu_signup_fields_domain',
[
'blog_title' => [
'order' => 10,
'name' => apply_filters('wu_signup_site_title_label', __('Site Title', 'wp-multisite-waas')),
'type' => 'text',
'default' => '',
'placeholder' => '',
'tooltip' => apply_filters('wu_signup_site_title_tooltip', __('Select the title your site is going to have.', 'wp-multisite-waas')),
'required' => true,
'core' => true,
],
'blogname' => [
'order' => 20,
'name' => apply_filters('wu_signup_site_url_label', __('URL', 'wp-multisite-waas')),
'type' => 'text',
'default' => '',
'placeholder' => '',
'tooltip' => apply_filters('wu_signup_site_url_tooltip', __('Site urls can only contain lowercase letters (a-z) and numbers and must be at least 4 characters. .', 'wp-multisite-waas')),
'required' => true,
'core' => true,
],
'url_preview' => [
'order' => 30,
'name' => __('Site URL Preview', 'wp-multisite-waas'),
'type' => 'html',
'content' => wu_get_template_contents('legacy/signup/steps/step-domain-url-preview'),
],
'submit' => [
'order' => 100,
'type' => 'submit',
'name' => __('Continue to the next step', 'wp-multisite-waas'),
'core' => true,
],
]
),
];
/**
* Since there are some conditional fields on the accounts step, we need to declare the variable before
* so we can append items and filter it later
*/
$account_fields = [
'user_name' => [
'order' => 10,
'name' => apply_filters('wu_signup_username_label', __('Username', 'wp-multisite-waas')),
'type' => 'text',
'default' => '',
'placeholder' => '',
'tooltip' => apply_filters('wu_signup_username_tooltip', __('Username must be at least 4 characters.', 'wp-multisite-waas')),
'required' => true,
'core' => true,
],
'user_email' => [
'order' => 20,
'name' => apply_filters('wu_signup_email_label', __('Email', 'wp-multisite-waas')),
'type' => 'email',
'default' => '',
'placeholder' => '',
'tooltip' => apply_filters('wu_signup_email_tooltip', ''),
'required' => true,
'core' => true,
],
'user_pass' => [
'order' => 30,
'name' => apply_filters('wu_signup_password_label', __('Password', 'wp-multisite-waas')),
'type' => 'password',
'default' => '',
'placeholder' => '',
'tooltip' => apply_filters('wu_signup_password_tooltip', __('Your password should be at least 6 characters long.', 'wp-multisite-waas')),
'required' => true,
'core' => true,
],
'user_pass_conf' => [
'order' => 40,
'name' => apply_filters('wu_signup_password_conf_label', __('Confirm Password', 'wp-multisite-waas')),
'type' => 'password',
'default' => '',
'placeholder' => '',
'tooltip' => apply_filters('wu_signup_password_conf_tooltip', ''),
'required' => true,
'core' => true,
],
/**
* HoneyPot Field
*/
'site_url' => [
'order' => random_int(1, 59), // Use random order for Honeypot
'name' => __('Site URL', 'wp-multisite-waas'),
'type' => 'text',
'default' => '',
'placeholder' => '',
'tooltip' => '',
'core' => true,
'wrapper_attributes' => [
'style' => 'display: none;',
],
'attributes' => [
'autocomplete' => 'nope',
],
],
];
/**
* Check and Add Coupon Code Fields
*
* @since 1.4.0
*/
// if (wu_get_setting('enable_coupon_codes', 'url_and_field') == 'url_and_field') {
// **
// * Test default state, if we have a coupon saved
// */
// $coupon = $this->has_coupon_code();
// $account_fields['has_coupon'] = array(
// 'order' => 50,
// 'type' => 'checkbox',
// 'name' => __('Have a coupon code?', 'wp-multisite-waas'),
// 'core' => true,
// 'check_if' => 'coupon', // Check if the input with this name is selected
// 'checked' => $coupon ? true : false,
// );
// $account_fields['coupon'] = array(
// 'order' => 60,
// 'name' => __('Coupon Code', 'wp-multisite-waas'),
// 'type' => 'text',
// 'default' => '',
// 'placeholder' => '',
// 'tooltip' => __('The code should be an exact match. This field is case-sensitive.', 'wp-multisite-waas'),
// 'requires' => array('has_coupon' => true),
// 'core' => true,
// );
// }
// /**
// * Check and Add the Terms field
// * @since 1.0.4
// */
// if (wu_get_setting('enable_terms')) {
// $account_fields['agree_terms'] = array(
// 'order' => 70,
// 'type' => 'checkbox',
// 'checked' => false,
// 'name' => sprintf(__('I agree with the <a href="%s" target="_blank">Terms of Service</a>', 'wp-multisite-waas'), $this->get_terms_url()),
// 'core' => true,
// );
// }
/**
* Submit Field
*/
$account_fields['submit'] = [
'order' => 100,
'type' => 'submit',
'name' => __('Create Account', 'wp-multisite-waas'),
'core' => true,
];
// Account registering
$steps['account'] = [
'name' => __('Account Details', 'wp-multisite-waas'),
'view' => false,
'handler' => [$this, 'account_save'],
'order' => 40,
'core' => true,
'fields' => apply_filters('wu_signup_fields_account', $account_fields),
];
/**
* Add additional steps via filters
*/
$steps = $filtered ? apply_filters('wp_ultimo_registration_steps', $steps) : $steps;
// Sort elements based on their order
uasort($steps, [$this, 'sort_steps_and_fields']);
// Sorts each of the fields block
foreach ($steps as &$step) {
$step = wp_parse_args(
$step,
[
'hidden' => false,
]
);
if (isset($step['fields']) && is_array($step['fields'])) {
// Sort elements based on their order
uasort($step['fields'], [$this, 'sort_steps_and_fields']);
}
}
/**
* Adds the hidden step now responsible for validating data entry and the actual account creation
*
* @since 1.4.0
*/
$begin_signup = [
'begin-signup' => [
'name' => __('Begin Signup Process', 'wp-multisite-waas'),
'handler' => [$this, 'begin_signup'],
'view' => false,
'hidden' => true,
'order' => 0,
'core' => true,
],
];
/**
* Adds the hidden step now responsible for validating data entry and the actual account creation
*
* @since 1.4.0
*/
$create_account = [
'create-account' => [
'name' => __('Creating Account', 'wp-multisite-waas'),
'handler' => [$this, 'create_account'],
'view' => false,
'hidden' => true,
'core' => true,
'order' => 1_000_000_000,
],
];
/**
* Glue the required steps together with the filterable ones
*/
$steps = array_merge($begin_signup, $steps, $create_account);
/**
* Filter the hidden ones, if we need to...
*
* @var array
*/
if ( ! $include_hidden) {
$steps = array_filter($steps, fn($step) => ! (isset($step['hidden']) && $step['hidden']));
}
// If we need to add that
if ( ! $this->has_plan_step()) {
unset($steps['plan']);
}
return $steps;
}
/**
* Check the transient, and if it does not exists, throw fatal
*
* @param bool $die If we should die when there's no transient set.
* @return array The transient information
*/
public static function get_transient($die = true) {
if (self::is_customizer()) {
$transient = [
'not-empty' => '',
];
} else {
$transient = wu_get_session('signup')->get('form');
}
if ($die && empty($transient)) {
// wp_die(__('Try again', 'wp-multisite-waas'));
}
if (is_null($transient)) {
return [];
}
return $transient;
}
/**
* Update the transient data in out database
*
* @param array $transient Array containing the transient data.
*/
public function update_transient($transient): void {
$this->session->set('form', $transient);
$this->session->commit();
}
/**
* Checks transient data to see if the plan step is necessary
*/
public function has_plan_step(): bool {
$transient = static::get_transient();
return ! (isset($transient['skip_plan']) && isset($transient['plan_id']) && isset($transient['plan_freq']));
}
/**
* Get the link for the next step
*
* @param array $params The params.
* @return string The link for the next step
*/
public function get_next_step_link($params = []) {
// Add CS
if (isset($_GET['cs'])) {
$params['cs'] = $_GET['cs'];
}
if (isset($_REQUEST['customized'])) {
$params['customized'] = $_REQUEST['customized'];
}
if (isset($_REQUEST['skip_plan']) && 1 == $_REQUEST['skip_plan']) {
unset($this->steps['plan']);
unset($params['skip_plan']);
}
if (isset($_REQUEST['template_id'])) {
$plan = false;
if (isset($_REQUEST['plan_id'])) {
$plan = wu_get_plan($_REQUEST['plan_id']);
}
$templates = array_keys((array) wu_get_setting('templates'));
if ( ($plan && $plan->is_template_available($_REQUEST['template_id'])) || in_array($_REQUEST['template_id'], $templates)) {
unset($this->steps['template']);
unset($params['skip_template_selection']);
}
}
$keys = array_keys($this->steps);
$url = add_query_arg('step', $keys[ array_search($this->step, array_keys($this->steps)) + 1 ]);
foreach ($params as $param => $value) {
$url = add_query_arg($param, $value, $url);
}
return $url;
}
/**
* Redirects the user to the next step on the signup flow
*
* @param array $args Arguments to build the URL.
* @return void
*/
public function next_step($args = []): void {
/** Redirect the user to the next step */
wp_safe_redirect(esc_url_raw($this->get_next_step_link($args)));
/** Kill the execution after the redirect */
exit;
}
/**
* Get the link for the previous step
*
* @param array $params The params.
* @return string The link for the previous step
*/
public function get_prev_step_link($params = []) {
// Add CS
if (isset($_GET['cs'])) {
$params['cs'] = $_GET['cs'];
}
if (isset($_REQUEST['customized'])) {
$params['customized'] = $_REQUEST['customized'];
}
$keys = array_keys($this->steps);
$search_key = array_search($this->step, array_keys($this->steps)) - 1 >= 0 ? array_search($this->step, array_keys($this->steps)) - 1 : false;
$key = false === $search_key ? '' : $keys[ $search_key ];
if ( ! $key || 'begin-signup' == $key) {
return false;
}
$url = add_query_arg('step', $key);
foreach ($params as $param => $value) {
$url = add_query_arg($param, $value, $url);
}
return $url;
}
/**
* Sorts the steps.
*
* @param array $a Value 1.
* @param array $b Value to compare against.
* @return boolean
*/
public function sort_steps_and_fields($a, $b) {
$a['order'] = isset($a['order']) ? (int) $a['order'] : 50;
$b['order'] = isset($b['order']) ? (int) $b['order'] : 50;
return $a['order'] - $b['order'];
}
/**
* Display the necessary fields for the plan template
*
* @since 1.5.0 Takes the frequency parameter
*
* @param boolean $current_plan The current plan.
* @param string $step The step.
* @param integer $freq The freq.
* @return void
*/
public function form_fields($current_plan = false, $step = 'plan', $freq = false): void {
/** Select the default frequency */
$freq = $freq ?: wu_get_setting('default_pricing_option');
?>
<?php if ('plan' == $step) { ?>
<input type="hidden" name="wu_action" value="wu_new_user">
<input type="hidden" id="wu_plan_freq" name="plan_freq" value="<?php echo $freq; ?>">
<?php
}
?>
<input type="hidden" name="save_step" value="1">
<?php wp_nonce_field('signup_form_1', '_signup_form'); ?>
<!-- if this is a change plan, let us know -->
<?php if ($current_plan) : ?>
<input type="hidden" name="changing-plan" value="1">
<?php endif; ?>
<?php
}
/**
* Get the primary site URL we will use on the URL previewer, during sign-up
*
* @since 1.7.2
* @return string
*/
public function get_site_url_for_previewer() {
$domain_options = [];
$site = get_current_site();
$domain = $site->domain;
if (wu_get_setting('enable_multiple_domains', false) && $domain_options) {
$domain = array_shift($domain_options);
}
$domain = rtrim($domain . $site->path, '/');
/**
* Allow plugin developers to filter the URL used in the previewer
*
* @since 1.7.2
* @param string Default domain being used right now, useful for manipulations
* @param array List of all the domain options entered in the WP Multisite WaaS Settings -> Network Settings -> Domain Options
* @return string New domain to be used
*/
return apply_filters('get_site_url_for_previewer', $domain, $domain_options); // phpcs:ignore
}
/**
* We pass the following info
*/
public function plans_save(): void {
// Get transient
$transient = static::get_transient();
// Check referer
check_admin_referer('signup_form_1', '_signup_form');
// Errors
$this->results['errors'] = new \WP_Error();
// We need now to check for plan
if ( ! isset($_POST['plan_id'])) {
$this->results['errors']->add('plan_id', __('You don\'t have any plan selected.', 'wp-multisite-waas'));
} else {
// We need now to check if the plan exists
$plan = wu_get_product($_POST['plan_id']);
if ( ! $plan->exists()) {
$this->results['errors']->add('plan_id', __('The plan you\'ve selected doesn\'t exist.', 'wp-multisite-waas'));
}
}
$transient = apply_filters('wp_ultimo_registration_step_plans_save_transient', $transient);
// Action hook for users
do_action('wp_ultimo_registration_step_plans_save', $transient);
// Stay on the form if we get any errors
if ($this->results['errors']->get_error_code()) {
return;
}
/** Update Transient Content */
$transient['plan_freq'] = $_POST['plan_freq'];
$transient['plan_id'] = $_POST['plan_id'];
/** Update Data */
$this->update_transient($transient);
/** Go to the next step */
$this->next_step();
}
/**
* Personal Info Settings.
*/
public function domain_save(): void {
// Get transient
$transient = static::get_transient();
// Check referer
check_admin_referer('signup_form_1', '_signup_form');
/**
* Make sure we trim() the contents of the form.
*
* @since 1.9.0
*/
$_POST = array_map('trim', $_POST);
// Get validation errors
$this->results = validate_blog_form();
/** Sanitizes Input */
$transient = array_merge($transient, $this->filter_post_array($_POST));
// Action hook for users
do_action('wp_ultimo_registration_step_domain_save', $transient);
// Stay on the form if we get any errors
if ($this->results['errors']->get_error_code()) {
$this->results = array_merge($this->results, $_POST);
return;
}
// Re-saves the transient
$this->update_transient($transient);
/** Go to the next step */
$this->next_step();
}
/**
* Filters the input variables and sanitizes its contents
*
* @param array $post The post.
* @param array $exclude_list The exclude list.
* @return array
*/
public function filter_post_array($post, $exclude_list = false) {
$exclude_list = $exclude_list ?: ['_signup_form', '_wp_http_referer'];
/** Filter Array */
$post = $this->array_filter_key($post, fn($element_key) => ! in_array($element_key, $exclude_list, true));
/** Sanitizes the input */
$post = array_map(fn($element) => sanitize_text_field($element), $post);
return $post;
}
/**
* Helper function to filter based on key.
*
* @since 2.0.0
*
* @param array $array The array.
* @param callable $callback The callback.
*/
public function array_filter_key(array $array, $callback): array {
$matched_keys = array_filter(array_keys($array), $callback ?? fn($v, $k): bool => ! empty($v), null === $callback ? ARRAY_FILTER_USE_BOTH : 0);
return array_intersect_key($array, array_flip($matched_keys));
}
/**
* Get the active until + trial days, to allow for putting subscription on hold
*
* @since 1.5.5
* @param string $now Time now.
* @param integer $trial_days Trial days.
*/
public static function get_active_until_with_trial($now, $trial_days): string {
$active_until = new \DateTime($now);
$active_until->add(new \DateInterval('P' . $trial_days . 'D'));
return $active_until->format('Y-m-d H:i:s');
}
/**
* Adds a new Step to the sign-up flow
*
* @since 1.4.0
* @param string $id The field id.
* @param integer $order The field order.
* @param array $step The step info.
* @return void
*/
public function add_signup_step($id, $order, $step): void {
add_filter(
'wp_ultimo_registration_steps',
function ($steps) use ($id, $order, $step) {
// Save new order
$step['order'] = $order;
// mark as not core
$step['core'] = false;
$steps[ $id ] = $step;
return $steps;
}
);
}
/**
* Adds a new field to a step the sign-up flow
*
* @since 1.4.0
* @param string $step The step name.
* @param string $id The field id.
* @param integer $order The field order.
* @param array $field The field.
* @return void
*/
public function add_signup_field($step, $id, $order, $field): void {
add_filter(
'wp_ultimo_registration_steps',
function ($steps) use ($step, $id, $order, $field) {
// Checks for honey-trap id
if ('site_url' === $id) {
wp_die(__('Please, do not use the "site_url" as one of your custom fields\' ids. We use it as a honeytrap field to prevent spam registration. Consider alternatives such as "url" or "website".', 'wp-multisite-waas'));
}
// Saves the order
$field['order'] = $order;
// mark as not core
$field['core'] = false;
$steps[ $step ]['fields'][ $id ] = $field;
return $steps;
}
);
}
}