__('General', 'wp-ultimo'),
'desc' => __('General', 'wp-ultimo'),
'type' => 'header',
];
$fields['slug'] = [
'title' => __('Slug', 'wp-ultimo'),
'desc' => __('The checkout form slug.', 'wp-ultimo'),
'type' => 'text',
];
return $fields;
}
/**
* The list of keywords for this element.
*
* Return an array of strings with keywords describing this
* element. Gutenberg uses this to help customers find blocks.
*
* e.g.:
* return array(
* 'WP Multisite WaaS',
* 'Checkout',
* 'Form',
* 'Cart',
* );
*
* @since 2.0.0
* @return array
*/
public function keywords() {
return [
'WP Ultimo',
'WP Multisite WaaS',
'Checkout',
'Form',
'Cart',
];
}
/**
* List of default parameters for the element.
*
* If you are planning to add controls using the fields,
* it might be a good idea to use this method to set defaults
* for the parameters you are expecting.
*
* These defaults will be used inside a 'wp_parse_args' call
* before passing the parameters down to the block render
* function and the shortcode render function.
*
* @since 2.0.0
* @return array
*/
public function defaults() {
return [
'slug' => 'main-form',
'step' => false,
'display_title' => false,
'membership_limitations' => [],
];
}
/**
* Checks if we are on a thank you page.
*
* @since 2.0.0
* @return boolean
*/
public function is_thank_you_page() {
return is_user_logged_in() && wu_request('payment') && wu_request('status') === 'done';
}
/**
* Triggers the setup event to allow the checkout class to hook in.
*
* @since 2.0.0
* @return void
*/
public function setup(): void {
if ($this->is_thank_you_page()) {
\WP_Ultimo\UI\Thank_You_Element::get_instance()->setup();
return;
}
do_action('wu_setup_checkout', $this);
}
/**
* Print the Custom CSS added on the checkout.
*
* @since 2.0.0
*
* @param \WP_Ultimo\Models\Checkout_Form $checkout_form The current checkout form.
* @return void
*/
public function print_custom_css($checkout_form): void {
$scss = new Compiler();
$slug = $checkout_form->get_slug();
$custom_css = $checkout_form->get_custom_css();
if ($custom_css) {
$custom_css = $scss->compileString(
".wu_checkout_form_{$slug} {
{$custom_css}
}"
)->getCss();
printf('', $custom_css);
}
}
/**
* Outputs thank you page.
*
* @since 2.0.0
*
* @param array $atts Parameters of the block/shortcode.
* @param string|null $content The content inside the shortcode.
* @return string
*/
public function output_thank_you($atts, $content = null) {
$slug = $atts['slug'];
$checkout_form = wu_get_checkout_form_by_slug($slug);
$atts = $checkout_form->get_meta('wu_thank_you_settings');
$atts['checkout_form'] = $checkout_form;
\WP_Ultimo\UI\Thank_You_Element::get_instance()->register_scripts();
return \WP_Ultimo\UI\Thank_You_Element::get_instance()->output($atts, $content);
}
/**
* Outputs the registration form.
*
* @since 2.0.0
*
* @param array $atts Parameters of the block/shortcode.
* @param string|null $content The content inside the shortcode.
* @return string
*/
public function output_form($atts, $content = null) {
$atts['step'] = wu_request('step', $atts['step']);
$slug = $atts['slug'];
$customer = wu_get_current_customer();
$membership = WP_Ultimo()->currents->get_membership();
/**
* Allow developers bypass the output and set a new one
*
* @param string|boll $bypass If we should bypass the checkout form or a string to return instead of the form.
* @param array $atts Parameters of the checkout block/shortcode.
*/
$bypass = apply_filters('wu_bypass_checkout_form', false, $atts);
if ($bypass) {
return is_string($bypass) ? $bypass : '';
}
if ($customer && $membership && 'wu-finish-checkout' !== $slug) {
$published_sites = $membership->get_published_sites();
$pending_payment = $membership ? $membership->get_last_pending_payment() : false;
if ($pending_payment && ! $membership->is_active() && $membership->get_status() !== Membership_Status::TRIALING) {
/**
* We are talking about membership with a pending payment
*/
// Translators: Placeholder receives the customer display name
$message = sprintf(__('Hi %s. You have a pending payment for your membership!', 'wp-ultimo'), $customer->get_display_name());
$payment_url = add_query_arg(
[
'payment' => $pending_payment->get_hash(),
],
wu_get_registration_url()
);
// Translators: The link to registration url with payment hash
$message .= '
' . sprintf(__('Click here to pay.', 'wp-ultimo'), $payment_url);
$message = '
' . $message . '
'; /** * Allow developers to change the message if membership have a pending payment * * @param string $message The HTML message to print in screen. * @param WP_Ultimo\Models\Membership $membership The membership in use. * @param WP_Ultimo\Models\Customer $customer The active customer in use. */ return apply_filters('wu_checkout_pending_payment_error_message', $message, $membership, $customer); } $membership_blocked_forms = [ 'wu-add-new-site', ]; if ( ! $membership->is_active() && $membership->get_status() !== Membership_Status::TRIALING && in_array($atts['slug'], $membership_blocked_forms, true)) { // Translators: Placeholder receives the customer display name $message = sprintf(__('Hi %s. You cannot take action on your membership while it is not active!', 'wp-ultimo'), $customer->get_display_name()); if ($membership->get_status() === Membership_Status::PENDING && $customer->get_email_verification() === 'pending') { /** * Enqueue thank you page scripts to handle resend email verification link */ wp_register_script('wu-thank-you', wu_get_asset('thank-you.js', 'js'), [], wu_get_version()); wp_localize_script( 'wu-thank-you', 'wu_thank_you', [ 'ajaxurl' => admin_url('admin-ajax.php'), 'resend_verification_email_nonce' => wp_create_nonce('wu_resend_verification_email_nonce'), 'membership_hash' => $membership->get_hash(), 'i18n' => [ 'resending_verification_email' => __('Resending verification email...', 'wp-ultimo'), 'email_sent' => __('Verification email sent!', 'wp-ultimo'), ], ] ); wp_enqueue_script('wu-thank-you'); $message .= '' . __('Check your inbox and verify your email address.', 'wp-ultimo') . '
'; $message .= ''; $message .= sprintf('%s', __('Resend verification email', 'wp-ultimo')); $message .= ''; } /** * Allow developers to change the message if membership have a pending payment * * @param string $message The HTML message to print in screen. * @param WP_Ultimo\Models\Membership $membership The membership in use. * @param WP_Ultimo\Models\Customer $customer The active customer in use. */ return apply_filters('wu_checkout_membership_status_error_message', $message, $membership, $customer); } if ( ! wu_multiple_memberships_enabled() && $membership) { /** * Allow developers to add new form slugs to bypass this behaviour. * * @param array $slugs a list of form slugs to bypass. */ $allowed_forms = apply_filters( 'wu_get_membership_allowed_forms', [ 'wu-checkout', 'wu-add-new-site', ] ); if ( ! in_array($slug, $allowed_forms, true) && ! wu_request('payment')) { $message = sprintf('%s
', __('You already have a membership!', 'wp-ultimo')); if (isset($published_sites[0])) { $account_link = get_admin_url($published_sites[0]->get_id(), 'admin.php?page=account'); $button_text = __('Go to my account', 'wp-ultimo'); $message .= ""; } /** * Allow developers to change the message about the limitation of a single membership for customer. * * @param string $message The HTML message to print in screen. * @param WP_Ultimo\Models\Customer $customer The active customer in use. */ return apply_filters('wu_checkout_single_membership_message', $message, $customer); } } if ($membership && $membership->get_customer_id() !== $customer->get_id()) { $message = sprintf('
%s
', __('You are not allowed to change this membership!', 'wp-ultimo')); /** * Allow developers to change the message if customer is not part of the membership * * @param string $message The HTML message to print in screen. * @param WP_Ultimo\Models\Membership $membership The membership in use. * @param WP_Ultimo\Models\Customer $customer The active customer in use. */ return apply_filters('wu_checkout_customer_error_message', $message, $membership, $customer); } /** * Now we filter the current membership for each membership_limitations * field in element atts to check if we can show the form, if not we show * a error message informing the user about and with buttons to allow * account upgrade and/or to buy a new membership. */ if ($membership && ! empty($atts['membership_limitations'])) { $limits = $membership->get_limitations(); foreach ($atts['membership_limitations'] as $limitation) { if ( ! method_exists($membership, "get_$limitation")) { continue; } $current_limit = $limits->{$limitation}; $limit_max = $current_limit->is_enabled() ? $current_limit->get_limit() : PHP_INT_MAX; $limit_max = ! empty($limit_max) ? (int) $limit_max : 1; $used_limit = $membership->{"get_$limitation"}(); $used_limit = is_array($used_limit) ? count($used_limit) : (int) $used_limit; if ($used_limit >= $limit_max) { // Translators: Placeholder receives the limit name $message = '' . sprintf(__('You reached your membership %s limit!', 'wp-ultimo'), $limitation) . '
'; $message .= ''; if (wu_multiple_memberships_enabled()) { $register_page = wu_get_registration_url(); $button_text = __('Buy a new membership', 'wp-ultimo'); $message .= "$button_text"; } if ('sites' !== $limitation || wu_get_setting('enable_multiple_sites')) { $update_link = ''; $checkout_pages = \WP_Ultimo\Checkout\Checkout_Pages::get_instance(); $update_url = $checkout_pages->get_page_url('update'); if ($update_url) { $update_link = add_query_arg( [ 'membership' => $membership->get_hash(), ], $update_url ); } elseif (is_admin()) { $update_link = admin_url('admin.php?page=wu-checkout&membership=' . $membership->get_hash()); } elseif (isset($published_sites[0])) { $update_link = get_admin_url($published_sites[0]->get_id(), 'admin.php?page=wu-checkout&membership=' . $membership->get_hash()); } if ( ! empty($update_link)) { $button_text = __('Upgrade your account', 'wp-ultimo'); $message .= "$button_text"; } } $message .= ''; /** * Allow developers to change the message about the membership limit * * @param string $message The HTML message to print in screen. * @param string $limitation The limitation name. * @param int $limit_max The allowed limit. * @param int $used_limit The limit used in membership. * @param WP_Ultimo\Models\Membership $membership The membership in use. * @param WP_Ultimo\Models\Customer $customer The active customer in use. */ return apply_filters('wu_checkout_membership_limit_message', $message, $limitation, $limit_max, $used_limit, $membership, $customer); } } } } elseif ( ! $customer && 'wu-finish-checkout' === $slug) { if (is_user_logged_in()) { $message = __('You need to be the account owner to complete this payment.', 'wp-ultimo'); } else { $message = __('You need to be logged in to complete a payment', 'wp-ultimo'); // Translators: The link to login url with redirect_to url $message .= '' . $message . '
'; /** * Allow developers to change the message * * @param string $message The HTML message to print in screen. */ return apply_filters('wu_checkout_payment_login_error_message', $message); } $checkout_form = wu_get_checkout_form_by_slug($slug); if ( ! $checkout_form) { // translators: %s is the id of the form. e.g. main-form return sprintf(__('Checkout form %s not found.', 'wp-ultimo'), $slug); } if ($checkout_form->get_field_count() === 0) { // translators: %s is the id of the form. e.g. main-form return sprintf(__('Checkout form %s contains no fields.', 'wp-ultimo'), $slug); } if ( ! $checkout_form->is_active() || ! wu_get_setting('enable_registration')) { return sprintf('%s
', __('Registration is not available at this time.', 'wp-ultimo')); } if ($checkout_form->has_country_lock()) { $geolocation = \WP_Ultimo\Geolocation::geolocate_ip('', true); if ( ! in_array($geolocation['country'], $checkout_form->get_allowed_countries(), true)) { return sprintf('%s
', __('Registration is closed for your location.', 'wp-ultimo')); } } $checkout = \WP_Ultimo\Checkout\Checkout::get_instance(); $checkout_form->get_steps_to_show(); $this->steps = $checkout_form->get_steps_to_show(); $step = $checkout_form->get_step($atts['step'], true); $this->step = $step ?: current($this->steps); $this->step = wp_parse_args( $this->step, [ 'classes' => '', 'fields' => [], ] ); $this->step_name = $this->step['id'] ?? ''; /* * Hack-y way to make signup available on the template. */ global $signup; $signup = new Mocked_Signup($this->step_name, $this->steps); // phpcs:ignore $this->signup = $signup; add_action( 'wp_print_footer_scripts', function () use ($checkout_form) { $this->print_custom_css($checkout_form); } ); /* * Load the checkout class with the parameters * so we can access them inside the layouts. */ $checkout->checkout_form = $checkout_form; $checkout->steps = $this->steps; $checkout->step = $this->step; $checkout->step_name = $this->step_name; $auto_submittable_field = $checkout->contains_auto_submittable_field($this->step['fields']); $final_fields = wu_create_checkout_fields($this->step['fields']); /* * Adds the product fields to keep them. */ $final_fields['products[]'] = [ 'type' => 'hidden', 'html_attr' => [ 'v-for' => '(product, index) in unique_products', 'v-model' => 'products[index]', 'v-bind:id' => '"products-" + index', ], ]; $this->inject_inline_auto_submittable_field($auto_submittable_field); $final_fields = apply_filters('wu_checkout_form_final_fields', $final_fields, $this); return wu_get_template_contents( 'checkout/form', [ 'step' => $this->step, 'step_name' => $this->step_name, 'checkout_form_name' => $atts['slug'], 'errors' => $checkout->errors, 'display_title' => $atts['display_title'], 'final_fields' => $final_fields, ] ); } /** * Injects the auto-submittable field inline snippet. * * @since 2.0.11 * * @param string $auto_submittable_field The auto-submittable field. * @return void */ public function inject_inline_auto_submittable_field($auto_submittable_field): void { $callback = function () use ($auto_submittable_field) { wp_add_inline_script( 'wu-checkout', sprintf( ' /** * Set the auto-submittable field, if one exists. */ window.wu_auto_submittable_field = %s; ', json_encode($auto_submittable_field) ), 'after' ); }; if (wu_is_block_theme() && ! is_admin()) { add_action('wu_checkout_scripts', $callback, 100); } else { call_user_func($callback); } } /** * The content to be output on the screen. * * Should return HTML markup to be used to display the block. * This method is shared between the block render method and * the shortcode implementation. * * @since 2.0.0 * * @param array $atts Parameters of the block/shortcode. * @param string|null $content The content inside the shortcode. * @return string */ public function output($atts, $content = null) { if (wu_is_update_page()) { $atts = [ 'slug' => apply_filters('wu_membership_update_form', 'wu-checkout'), 'step' => false, 'display_title' => false, ]; } if (wu_is_new_site_page()) { $atts = [ 'slug' => apply_filters('wu_membership_new_site_form', 'wu-add-new-site'), 'step' => false, 'display_title' => false, 'membership_limitations' => ['sites'], ]; } if ($this->is_thank_you_page()) { return $this->output_thank_you($atts, $content); } /** * Allow developers to add new update form slugs. * * @param array $slugs a list of form slugs to bypass. */ $update_forms = apply_filters( 'wu_membership_update_forms', [ 'wu-checkout', ] ); if ( ! in_array($atts['slug'], $update_forms, true) && (wu_request('payment') || wu_request('payment_id'))) { $atts = [ 'slug' => 'wu-finish-checkout', 'step' => false, 'display_title' => false, ]; } if (wu_request('wu_form') && in_array(wu_request('wu_form'), $update_forms, true)) { $atts = [ 'slug' => wu_request('wu_form'), 'step' => false, 'display_title' => false, ]; } return $this->output_form($atts, $content); } } /** * Replacement of the old WU_Signup class for templates. * * @since 2.0.0 */ class Mocked_Signup { /** * @var string */ public $step; /** * @var array */ public $steps; /** * Constructs the class. * * @since 2.0.0 * * @param string $step Current step. * @param array $steps List of all steps. */ public function __construct($step, $steps) { $this->step = $step; $this->steps = $steps; } /** * Get the value of steps. * * @since 2.0.0 * @return mixed */ public function get_steps() { return $this->steps; } /** * Deprecated: returns the prev step link. * * @since 2.0.0 */ public function get_prev_step_link(): string { return ''; } }