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.
1715 lines
49 KiB
PHP
1715 lines
49 KiB
PHP
<?php
|
|
/**
|
|
* WP Multisite WaaS Membership Edit/Add New Admin Page.
|
|
*
|
|
* @package WP_Ultimo
|
|
* @subpackage Admin_Pages
|
|
* @since 2.0.0
|
|
*/
|
|
|
|
namespace WP_Ultimo\Admin_Pages;
|
|
|
|
// Exit if accessed directly
|
|
defined('ABSPATH') || exit;
|
|
|
|
use WP_Ultimo\Database\Memberships\Membership_Status;
|
|
|
|
/**
|
|
* WP Multisite WaaS Membership Edit/Add New Admin Page.
|
|
*/
|
|
class Membership_Edit_Admin_Page extends Edit_Admin_Page {
|
|
|
|
/**
|
|
* Holds the ID for this page, this is also used as the page slug.
|
|
*
|
|
* @var string
|
|
*/
|
|
protected $id = 'wp-ultimo-edit-membership';
|
|
|
|
/**
|
|
* Is this a top-level menu or a submenu?
|
|
*
|
|
* @since 1.8.2
|
|
* @var string
|
|
*/
|
|
protected $type = 'submenu';
|
|
|
|
/**
|
|
* Object ID being edited.
|
|
*
|
|
* @since 1.8.2
|
|
* @var string
|
|
*/
|
|
public $object_id = 'membership';
|
|
|
|
/**
|
|
* Is this a top-level menu or a submenu?
|
|
*
|
|
* @since 1.8.2
|
|
* @var string
|
|
*/
|
|
protected $parent = 'none';
|
|
|
|
/**
|
|
* This page has no parent, so we need to highlight another sub-menu.
|
|
*
|
|
* @since 2.0.0
|
|
* @var string
|
|
*/
|
|
protected $highlight_menu_slug = 'wp-ultimo-memberships';
|
|
|
|
/**
|
|
* If this number is greater than 0, a badge with the number will be displayed alongside the menu title
|
|
*
|
|
* @since 1.8.2
|
|
* @var integer
|
|
*/
|
|
protected $badge_count = 0;
|
|
|
|
/**
|
|
* Marks the page as a swap preview.
|
|
*
|
|
* @since 2.0.0
|
|
* @var boolean
|
|
*/
|
|
protected $is_swap_preview = false;
|
|
|
|
/**
|
|
* Holds the admin panels where this page should be displayed, as well as which capability to require.
|
|
*
|
|
* To add a page to the regular admin (wp-admin/), use: 'admin_menu' => 'capability_here'
|
|
* To add a page to the network admin (wp-admin/network), use: 'network_admin_menu' => 'capability_here'
|
|
* To add a page to the user (wp-admin/user) admin, use: 'user_admin_menu' => 'capability_here'
|
|
*
|
|
* @since 2.0.0
|
|
* @var array
|
|
*/
|
|
protected $supported_panels = [
|
|
'network_admin_menu' => 'wu_edit_memberships',
|
|
];
|
|
|
|
/**
|
|
* Override the page load.
|
|
*
|
|
* @since 2.0.0
|
|
* @return void
|
|
*/
|
|
public function page_loaded(): void {
|
|
|
|
parent::page_loaded();
|
|
|
|
/*
|
|
* Adds the swap notices, if needed.
|
|
*/
|
|
$this->add_swap_notices();
|
|
}
|
|
|
|
/**
|
|
* Displays swap notices, if necessary.
|
|
*
|
|
* @since 2.0.0
|
|
* @return void
|
|
*/
|
|
protected function add_swap_notices() {
|
|
|
|
$swap_order = $this->get_object()->get_scheduled_swap();
|
|
|
|
if ( ! $swap_order || wu_request('preview-swap')) {
|
|
return;
|
|
}
|
|
|
|
$actions = [
|
|
'preview' => [
|
|
'title' => __('Preview', 'wp-multisite-waas'),
|
|
'url' => add_query_arg('preview-swap', 1),
|
|
],
|
|
];
|
|
|
|
$date = new \DateTime($swap_order->scheduled_date);
|
|
|
|
// translators: %s is the date, using the site format options
|
|
$message = sprintf(__('There is a change scheduled to take place on this membership in <strong>%s</strong>. You can preview the changes here. Scheduled changes are usually created by downgrades.', 'wp-multisite-waas'), $date->format(get_option('date_format')));
|
|
|
|
WP_Ultimo()->notices->add($message, 'warning', 'network-admin', false, $actions);
|
|
}
|
|
|
|
/**
|
|
* Registers the necessary scripts and styles for this admin page.
|
|
*
|
|
* @since 2.0.4
|
|
* @return void
|
|
*/
|
|
public function register_scripts(): void {
|
|
|
|
parent::register_scripts();
|
|
|
|
wp_enqueue_editor();
|
|
}
|
|
|
|
/**
|
|
* Register ajax forms that we use for membership.
|
|
*
|
|
* @since 2.0.0
|
|
* @return void
|
|
*/
|
|
public function register_forms(): void {
|
|
/*
|
|
* Transfer membership - Confirmation modal
|
|
*/
|
|
wu_register_form(
|
|
'transfer_membership',
|
|
[
|
|
'render' => [$this, 'render_transfer_membership_modal'],
|
|
'handler' => [$this, 'handle_transfer_membership_modal'],
|
|
'capability' => 'wu_transfer_memberships',
|
|
]
|
|
);
|
|
|
|
/*
|
|
* Edit/Add product
|
|
*/
|
|
wu_register_form(
|
|
'edit_membership_product',
|
|
[
|
|
'render' => [$this, 'render_edit_membership_product_modal'],
|
|
'handler' => [$this, 'handle_edit_membership_product_modal'],
|
|
]
|
|
);
|
|
|
|
/*
|
|
* Change Plan
|
|
*/
|
|
wu_register_form(
|
|
'change_membership_plan',
|
|
[
|
|
'render' => [$this, 'render_change_membership_plan_modal'],
|
|
'handler' => [$this, 'handle_change_membership_plan_modal'],
|
|
]
|
|
);
|
|
|
|
/*
|
|
* Delete Product
|
|
*/
|
|
wu_register_form(
|
|
'remove_membership_product',
|
|
[
|
|
'render' => [$this, 'render_remove_membership_product'],
|
|
'handler' => [$this, 'handle_remove_membership_product'],
|
|
]
|
|
);
|
|
|
|
add_filter(
|
|
'wu_data_json_success_delete_membership_modal',
|
|
fn($data_json) => [
|
|
'redirect_url' => wu_network_admin_url('wp-ultimo-memberships', ['deleted' => 1]),
|
|
]
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Renders the deletion confirmation form.
|
|
*
|
|
* @since 2.0.0
|
|
* @return void
|
|
*/
|
|
function render_transfer_membership_modal(): void {
|
|
|
|
$membership = wu_get_membership(wu_request('id'));
|
|
|
|
if ( ! $membership) {
|
|
return;
|
|
}
|
|
|
|
$fields = [
|
|
'confirm' => [
|
|
'type' => 'toggle',
|
|
'title' => __('Confirm Transfer', 'wp-multisite-waas'),
|
|
'desc' => __('This will start the transfer of assets from one customer to another.', 'wp-multisite-waas'),
|
|
'html_attr' => [
|
|
'v-model' => 'confirmed',
|
|
],
|
|
],
|
|
'submit_button' => [
|
|
'type' => 'submit',
|
|
'title' => __('Start Transfer', 'wp-multisite-waas'),
|
|
'placeholder' => __('Start Transfer', 'wp-multisite-waas'),
|
|
'value' => 'save',
|
|
'classes' => 'button button-primary wu-w-full',
|
|
'wrapper_classes' => 'wu-items-end',
|
|
'html_attr' => [
|
|
'v-bind:disabled' => '!confirmed',
|
|
],
|
|
],
|
|
'id' => [
|
|
'type' => 'hidden',
|
|
'value' => $membership->get_id(),
|
|
],
|
|
'target_customer_id' => [
|
|
'type' => 'hidden',
|
|
'value' => wu_request('target_customer_id'),
|
|
],
|
|
];
|
|
|
|
$form = new \WP_Ultimo\UI\Form(
|
|
'total-actions',
|
|
$fields,
|
|
[
|
|
'views' => 'admin-pages/fields',
|
|
'classes' => 'wu-modal-form wu-widget-list wu-striped wu-m-0 wu-mt-0',
|
|
'field_wrapper_classes' => 'wu-w-full wu-box-border wu-items-center wu-flex wu-justify-between wu-p-4 wu-m-0 wu-border-t wu-border-l-0 wu-border-r-0 wu-border-b-0 wu-border-gray-300 wu-border-solid',
|
|
'html_attr' => [
|
|
'data-wu-app' => 'true',
|
|
'data-state' => wp_json_encode(
|
|
[
|
|
'confirmed' => false,
|
|
]
|
|
),
|
|
],
|
|
]
|
|
);
|
|
|
|
$form->render();
|
|
}
|
|
|
|
/**
|
|
* Handles the deletion of line items.
|
|
*
|
|
* @since 2.0.0
|
|
* @return void
|
|
*/
|
|
public function handle_transfer_membership_modal(): void {
|
|
|
|
$membership = wu_get_membership(wu_request('id'));
|
|
|
|
if ( ! $membership) {
|
|
wp_send_json_error(new \WP_Error('not-found', __('Membership not found.', 'wp-multisite-waas')));
|
|
}
|
|
|
|
$target_customer = wu_get_customer(wu_request('target_customer_id'));
|
|
|
|
if ( ! $target_customer) {
|
|
wp_send_json_error(new \WP_Error('not-found', __('Target customer not found.', 'wp-multisite-waas')));
|
|
}
|
|
|
|
if ($target_customer->get_id() === $membership->get_customer_id()) {
|
|
wp_send_json_error(new \WP_Error('not-found', __('Cannot transfer to the same customer.', 'wp-multisite-waas')));
|
|
}
|
|
|
|
/*
|
|
* Lock the membership to prevent memberships.
|
|
*/
|
|
$membership->lock();
|
|
|
|
/*
|
|
* Enqueue task
|
|
*/
|
|
wu_enqueue_async_action(
|
|
'wu_async_transfer_membership',
|
|
[
|
|
'membership_id' => $membership->get_id(),
|
|
'target_customer_id' => $target_customer->get_id(),
|
|
],
|
|
'membership'
|
|
);
|
|
|
|
wp_send_json_success(
|
|
[
|
|
'redirect_url' => wu_network_admin_url(
|
|
'wp-ultimo-edit-membership',
|
|
[
|
|
'id' => $membership->get_id(),
|
|
'transfer-started' => 1,
|
|
]
|
|
),
|
|
]
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Allow child classes to register widgets, if they need them.
|
|
*
|
|
* @since 1.8.2
|
|
* @return void
|
|
*/
|
|
public function register_widgets(): void {
|
|
|
|
parent::register_widgets();
|
|
|
|
$labels = $this->get_labels();
|
|
|
|
$label = $this->get_object()->get_status_label();
|
|
|
|
$class = $this->get_object()->get_status_class();
|
|
|
|
$tag = "<span class='wu-bg-gray-200 wu-text-gray-700 wu-py-1 wu-px-2 wu-rounded-sm wu-text-xs wu-font-mono $class'>{$label}</span>";
|
|
|
|
$gateway_message = false;
|
|
|
|
if ( ! empty($this->get_object()->get_gateway())) {
|
|
$gateway = wu_get_gateway($this->get_object()->get_gateway());
|
|
|
|
$gateway_message = $gateway ? $gateway->get_amount_update_message() : '';
|
|
}
|
|
|
|
$this->add_fields_widget(
|
|
'at_a_glance',
|
|
[
|
|
'title' => __('At a Glance', 'wp-multisite-waas'),
|
|
'position' => 'normal',
|
|
'classes' => 'wu-overflow-hidden wu-widget-inset',
|
|
'field_wrapper_classes' => 'wu-w-1/3 wu-box-border wu-items-center wu-flex wu-justify-between wu-p-4 wu-m-0 wu-border-t-0 wu-border-l-0 wu-border-r wu-border-b-0 wu-border-gray-300 wu-border-solid wu-float-left wu-relative',
|
|
'fields' => [
|
|
'status' => [
|
|
'type' => 'text-display',
|
|
'title' => __('Membership Status', 'wp-multisite-waas'),
|
|
'display_value' => $tag,
|
|
'tooltip' => '',
|
|
],
|
|
'hash' => [
|
|
'copy' => true,
|
|
'type' => 'text-display',
|
|
'title' => __('Reference ID', 'wp-multisite-waas'),
|
|
'display_value' => $this->get_object()->get_hash(),
|
|
],
|
|
'total_grossed' => [
|
|
'type' => 'text-display',
|
|
'title' => __('Total Grossed', 'wp-multisite-waas'),
|
|
'display_value' => wu_format_currency($this->get_object()->get_total_grossed(), $this->get_object()->get_currency()),
|
|
'wrapper_classes' => 'sm:wu-border-r-0',
|
|
],
|
|
],
|
|
]
|
|
);
|
|
|
|
$this->add_list_table_widget(
|
|
'membership-products',
|
|
[
|
|
'position' => 'normal',
|
|
'title' => __('Products', 'wp-multisite-waas'),
|
|
'table' => new \WP_Ultimo\List_Tables\Membership_Line_Item_List_Table(),
|
|
'after' => $this->output_widget_products(),
|
|
]
|
|
);
|
|
|
|
$this->add_list_table_widget(
|
|
'payments',
|
|
[
|
|
'title' => __('Payments', 'wp-multisite-waas'),
|
|
'table' => new \WP_Ultimo\List_Tables\Customers_Payment_List_Table(),
|
|
'query_filter' => [$this, 'payments_query_filter'],
|
|
]
|
|
);
|
|
|
|
$this->add_list_table_widget(
|
|
'sites',
|
|
[
|
|
'title' => __('Sites', 'wp-multisite-waas'),
|
|
'table' => new \WP_Ultimo\List_Tables\Memberships_Site_List_Table(),
|
|
'query_filter' => [$this, 'sites_query_filter'],
|
|
]
|
|
);
|
|
|
|
$this->add_list_table_widget(
|
|
'customer',
|
|
[
|
|
'title' => __('Linked Customer', 'wp-multisite-waas'),
|
|
'table' => new \WP_Ultimo\List_Tables\Site_Customer_List_Table(),
|
|
'query_filter' => [$this, 'customer_query_filter'],
|
|
]
|
|
);
|
|
|
|
$this->add_tabs_widget(
|
|
'options',
|
|
[
|
|
'title' => __('Membership Options', 'wp-multisite-waas'),
|
|
'position' => 'normal',
|
|
'sections' => apply_filters(
|
|
'wu_membership_options_sections',
|
|
[
|
|
'general' => [
|
|
'title' => __('General', 'wp-multisite-waas'),
|
|
'desc' => __('General membership options', 'wp-multisite-waas'),
|
|
'icon' => 'dashicons-wu-globe',
|
|
'fields' => [
|
|
'blocking' => [
|
|
'type' => 'toggle',
|
|
'title' => __('Is Blocking?', 'wp-multisite-waas'),
|
|
'desc' => __('Should we block access to the site, plugins, themes, and services after the expiration date is reached?', 'wp-multisite-waas'),
|
|
'value' => true,
|
|
],
|
|
],
|
|
],
|
|
'billing_info' => [
|
|
'title' => __('Billing Info', 'wp-multisite-waas'),
|
|
'desc' => __('Billing information for this particular membership.', 'wp-multisite-waas'),
|
|
'icon' => 'dashicons-wu-address',
|
|
'fields' => $this->get_object()->get_billing_address()->get_fields(),
|
|
],
|
|
],
|
|
$this->get_object()
|
|
),
|
|
]
|
|
);
|
|
|
|
/*
|
|
* Hide sensitive things when in swap preview.
|
|
*/
|
|
if ( ! $this->is_swap_preview) {
|
|
$this->add_list_table_widget(
|
|
'events',
|
|
[
|
|
'title' => __('Events', 'wp-multisite-waas'),
|
|
'table' => new \WP_Ultimo\List_Tables\Inside_Events_List_Table(),
|
|
'query_filter' => [$this, 'events_query_filter'],
|
|
]
|
|
);
|
|
}
|
|
|
|
$regular_fields = [
|
|
'status' => [
|
|
'type' => 'select',
|
|
'title' => __('Status', 'wp-multisite-waas'),
|
|
'desc' => __('The membership current status.', 'wp-multisite-waas'),
|
|
'value' => $this->get_object()->get_status(),
|
|
'options' => Membership_Status::to_array(),
|
|
'tooltip' => '',
|
|
'html_attr' => [
|
|
'v-model' => 'status',
|
|
],
|
|
'wrapper_html_attr' => [
|
|
'v-cloak' => '1',
|
|
],
|
|
],
|
|
'cancellation_reason' => [
|
|
'type' => 'textarea',
|
|
'title' => __('Cancellation Reason', 'wp-multisite-waas'),
|
|
'desc' => __('The reason why the customer cancelled this membership.', 'wp-multisite-waas'),
|
|
'value' => $this->get_object()->get_cancellation_reason(),
|
|
'wrapper_html_attr' => [
|
|
'v-show' => 'status == \'cancelled\'',
|
|
'v-cloak' => '1',
|
|
],
|
|
],
|
|
'cancel_gateway' => [
|
|
'type' => 'toggle',
|
|
'title' => __('Cancel on gateway', 'wp-multisite-waas'),
|
|
'desc' => __('If enable we will cancel the subscription on payment method', 'wp-multisite-waas'),
|
|
'value' => false,
|
|
'wrapper_html_attr' => [
|
|
'v-show' => ! empty($this->get_object()->get_gateway_customer_id()) ? 'status == \'cancelled\'' : 'false',
|
|
'v-cloak' => '1',
|
|
],
|
|
],
|
|
'preview-swap' => [
|
|
'type' => 'hidden',
|
|
'value' => wu_request('preview-swap', 0),
|
|
],
|
|
'customer_id' => [
|
|
'type' => 'model',
|
|
'title' => __('Customer', 'wp-multisite-waas'),
|
|
'placeholder' => __('Search a Customer...', 'wp-multisite-waas'),
|
|
'desc' => __('The owner of this membership.', 'wp-multisite-waas'),
|
|
'value' => $this->get_object()->get_customer_id(),
|
|
'tooltip' => '',
|
|
'html_attr' => [
|
|
'data-base-link' => wu_network_admin_url('wp-ultimo-edit-customer', ['id' => '']),
|
|
'v-model' => 'customer_id',
|
|
'data-model' => 'customer',
|
|
'data-value-field' => 'id',
|
|
'data-label-field' => 'display_name',
|
|
'data-search-field' => 'display_name',
|
|
'data-max-items' => 1,
|
|
'data-selected' => $this->get_object()->get_customer() ? wp_json_encode($this->get_object()->get_customer()->to_search_results()) : '',
|
|
],
|
|
'wrapper_html_attr' => [
|
|
'v-cloak' => '1',
|
|
],
|
|
],
|
|
'transfer_note' => [
|
|
'type' => 'note',
|
|
'desc' => __('Changing the customer will transfer this membership and all its assets, including sites, to the new customer.', 'wp-multisite-waas'),
|
|
'classes' => 'wu-p-2 wu-bg-red-100 wu-text-red-600 wu-rounded wu-w-full',
|
|
'wrapper_html_attr' => [
|
|
'v-show' => '(original_customer_id != customer_id) && customer_id',
|
|
'v-cloak' => '1',
|
|
],
|
|
],
|
|
'submit_save' => [
|
|
'type' => 'submit',
|
|
'title' => $labels['save_button_label'],
|
|
'placeholder' => $labels['save_button_label'],
|
|
'value' => 'save',
|
|
'classes' => 'button button-primary wu-w-full',
|
|
'html_attr' => [],
|
|
'wrapper_html_attr' => [
|
|
'v-show' => 'original_customer_id == customer_id || !customer_id',
|
|
'v-cloak' => '1',
|
|
],
|
|
],
|
|
'transfer' => [
|
|
'type' => 'link',
|
|
'display_value' => __('Transfer Membership', 'wp-multisite-waas'),
|
|
'wrapper_classes' => 'wu-bg-gray-200',
|
|
'classes' => 'button wubox wu-w-full wu-text-center',
|
|
'wrapper_html_attr' => [
|
|
'v-show' => 'original_customer_id != customer_id && customer_id',
|
|
'v-cloak' => '1',
|
|
],
|
|
'html_attr' => [
|
|
'v-bind:href' => "'" . wu_get_form_url(
|
|
'transfer_membership',
|
|
[
|
|
'id' => $this->get_object()->get_id(),
|
|
'target_customer_id' => '',
|
|
]
|
|
) . "=' + customer_id",
|
|
'title' => __('Transfer Membership', 'wp-multisite-waas'),
|
|
],
|
|
],
|
|
];
|
|
|
|
if ($this->get_object()->is_locked()) {
|
|
unset($regular_fields['transfer_note']);
|
|
|
|
unset($regular_fields['transfer']);
|
|
|
|
$regular_fields['submit_save']['title'] = __('Locked', 'wp-multisite-waas');
|
|
$regular_fields['submit_save']['value'] = 'none';
|
|
$regular_fields['submit_save']['html_attr']['disabled'] = 'disabled';
|
|
}
|
|
|
|
$this->add_fields_widget(
|
|
'save',
|
|
[
|
|
'html_attr' => [
|
|
'data-wu-app' => 'membership_save',
|
|
'data-state' => wp_json_encode(
|
|
[
|
|
'status' => $this->get_object()->get_status(),
|
|
'original_customer_id' => $this->get_object()->get_customer_id(),
|
|
'customer_id' => $this->get_object()->get_customer_id(),
|
|
'plan_id' => $this->get_object()->get_plan_id(),
|
|
]
|
|
),
|
|
],
|
|
'fields' => $regular_fields,
|
|
]
|
|
);
|
|
|
|
$this->add_fields_widget(
|
|
'pricing',
|
|
[
|
|
'title' => __('Billing Amount', 'wp-multisite-waas'),
|
|
'html_attr' => [
|
|
'data-wu-app' => 'true',
|
|
'data-state' => wp_json_encode(
|
|
[
|
|
'is_recurring' => $this->get_object()->is_recurring(),
|
|
'is_auto_renew' => $this->get_object()->should_auto_renew(),
|
|
'amount' => $this->get_object()->get_amount(),
|
|
'initial_amount' => $this->get_object()->get_initial_amount(),
|
|
'duration' => $this->get_object()->get_duration(),
|
|
'duration_unit' => $this->get_object()->get_duration_unit(),
|
|
'gateway' => $this->get_object()->get_gateway(),
|
|
'gateway_subscription_id' => $this->get_object()->get_gateway_subscription_id(),
|
|
'gateway_customer_id' => $this->get_object()->get_gateway_customer_id(),
|
|
]
|
|
),
|
|
],
|
|
'fields' => [
|
|
// Fields for price
|
|
'_initial_amount' => [
|
|
'type' => 'text',
|
|
'title' => __('Initial Amount', 'wp-multisite-waas'),
|
|
// translators: %s is a price placeholder value.
|
|
'placeholder' => sprintf(__('E.g. %s', 'wp-multisite-waas'), wu_format_currency(199)),
|
|
'desc' => __('The initial amount collected on the first payment.', 'wp-multisite-waas'),
|
|
'value' => $this->get_object()->get_initial_amount(),
|
|
'money' => true,
|
|
'html_attr' => [
|
|
'v-model' => 'initial_amount',
|
|
],
|
|
'wrapper_html_attr' => [
|
|
'v-cloak' => '1',
|
|
],
|
|
],
|
|
'initial_amount' => [
|
|
'type' => 'hidden',
|
|
'html_attr' => [
|
|
'v-model' => 'initial_amount',
|
|
],
|
|
],
|
|
'recurring' => [
|
|
'type' => 'toggle',
|
|
'title' => __('Is Recurring', 'wp-multisite-waas'),
|
|
'desc' => __('Use this option to manually enable or disable this membership.', 'wp-multisite-waas'),
|
|
'value' => $this->get_object()->is_recurring(),
|
|
'html_attr' => [
|
|
'v-model' => 'is_recurring',
|
|
],
|
|
'wrapper_html_attr' => [
|
|
'v-cloak' => '1',
|
|
],
|
|
],
|
|
'amount' => [
|
|
'type' => 'hidden',
|
|
'html_attr' => [
|
|
'v-model' => 'amount',
|
|
],
|
|
],
|
|
'recurring_amount_group' => [
|
|
'type' => 'group',
|
|
'title' => __('Recurring Amount', 'wp-multisite-waas'),
|
|
// translators: placeholder %1$s is the amount, %2$s is the duration (such as 1, 2, 3), and %3$s is the unit (such as month, year, week)
|
|
'desc' => sprintf(__('The customer will be charged %1$s every %2$s %3$s(s).', 'wp-multisite-waas'), '{{ wu_format_money(amount) }}', '{{ duration }}', '{{ duration_unit }}'),
|
|
'wrapper_html_attr' => [
|
|
'v-show' => 'is_recurring',
|
|
'v-cloak' => '1',
|
|
],
|
|
'fields' => [
|
|
'_amount' => [
|
|
'type' => 'text',
|
|
'value' => $this->get_object()->get_amount(),
|
|
'placeholder' => wu_format_currency('99'),
|
|
'wrapper_classes' => '',
|
|
'money' => true,
|
|
'html_attr' => [
|
|
'v-model' => 'amount',
|
|
],
|
|
],
|
|
'duration' => [
|
|
'type' => 'number',
|
|
'value' => $this->get_object()->get_duration(),
|
|
'placeholder' => '',
|
|
'wrapper_classes' => 'wu-mx-2 wu-w-1/3',
|
|
'min' => 0,
|
|
'html_attr' => [
|
|
'v-model' => 'duration',
|
|
'steps' => 1,
|
|
],
|
|
],
|
|
'duration_unit' => [
|
|
'type' => 'select',
|
|
'value' => $this->get_object()->get_duration_unit(),
|
|
'placeholder' => '',
|
|
'wrapper_classes' => 'wu-w-2/3',
|
|
'html_attr' => [
|
|
'v-model' => 'duration_unit',
|
|
],
|
|
'options' => [
|
|
'day' => __('Days', 'wp-multisite-waas'),
|
|
'week' => __('Weeks', 'wp-multisite-waas'),
|
|
'month' => __('Months', 'wp-multisite-waas'),
|
|
'year' => __('Years', 'wp-multisite-waas'),
|
|
],
|
|
],
|
|
],
|
|
],
|
|
'recurring_note' => [
|
|
'type' => 'note',
|
|
'desc' => $gateway_message,
|
|
'classes' => 'wu-p-2 wu-bg-red-100 wu-text-red-600 wu-rounded wu-w-full',
|
|
'wrapper_html_attr' => [
|
|
'v-show' => implode(
|
|
' && ',
|
|
[
|
|
'is_recurring',
|
|
'gateway',
|
|
'gateway === "' . $this->get_object()->get_gateway() . '"',
|
|
'gateway_subscription_id === "' . $this->get_object()->get_gateway_subscription_id() . '"',
|
|
'gateway_customer_id === "' . $this->get_object()->get_gateway_customer_id() . '"',
|
|
'(' . implode(
|
|
' || ',
|
|
[
|
|
$this->get_object()->get_amount() . ' !== amount',
|
|
$this->get_object()->get_duration() . ' != duration',
|
|
'"' . $this->get_object()->get_duration_unit() . '" !== duration_unit',
|
|
]
|
|
) . ')',
|
|
]
|
|
),
|
|
'v-cloak' => '1',
|
|
],
|
|
],
|
|
'billing_cycles' => [
|
|
'type' => 'number',
|
|
'title' => __('Billing Cycles', 'wp-multisite-waas'),
|
|
'placeholder' => __('E.g. 0', 'wp-multisite-waas'),
|
|
'desc' => __('How many times should we bill this customer. Leave 0 to charge until cancelled.', 'wp-multisite-waas'),
|
|
'value' => $this->get_object()->get_billing_cycles(),
|
|
'min' => 0,
|
|
'wrapper_html_attr' => [
|
|
'v-show' => 'is_recurring',
|
|
'v-cloak' => '1',
|
|
],
|
|
],
|
|
'times_billed' => [
|
|
'type' => 'number',
|
|
'title' => __('Times Billed', 'wp-multisite-waas'),
|
|
'desc' => __('The number of times this membership was billed so far.', 'wp-multisite-waas'),
|
|
'value' => $this->get_object()->get_times_billed(),
|
|
'min' => 0,
|
|
'wrapper_html_attr' => [
|
|
'v-show' => 'is_recurring',
|
|
'v-cloak' => '1',
|
|
],
|
|
],
|
|
|
|
'auto_renew' => [
|
|
'type' => 'toggle',
|
|
'title' => __('Auto-Renew?', 'wp-multisite-waas'),
|
|
'desc' => __('Activating this will tell the gateway to try to automatically charge for this membership.', 'wp-multisite-waas'),
|
|
'value' => $this->get_object()->should_auto_renew(),
|
|
'wrapper_html_attr' => [
|
|
'v-show' => 'is_recurring',
|
|
'v-cloak' => '1',
|
|
],
|
|
'html_attr' => [
|
|
'v-model' => 'is_auto_renew',
|
|
],
|
|
],
|
|
'gateway' => [
|
|
'type' => 'text',
|
|
'title' => __('Gateway', 'wp-multisite-waas'),
|
|
'placeholder' => __('e.g. stripe', 'wp-multisite-waas'),
|
|
'description' => __('e.g. stripe', 'wp-multisite-waas'),
|
|
'desc' => __('Payment gateway used to process the payment.', 'wp-multisite-waas'),
|
|
'value' => $this->get_object()->get_gateway(),
|
|
'wrapper_classes' => 'wu-w-full',
|
|
'html_attr' => [
|
|
'v-on:input' => 'gateway = $event.target.value.toLowerCase().replace(/[^a-z0-9-_]+/g, "")',
|
|
'v-bind:value' => 'gateway',
|
|
],
|
|
'wrapper_html_attr' => [
|
|
'v-cloak' => '1',
|
|
],
|
|
],
|
|
'gateway_customer_id_group' => [
|
|
'type' => 'group',
|
|
'desc' => function (): string {
|
|
|
|
$gateway_id = $this->get_object()->get_gateway();
|
|
|
|
if (empty($this->get_object()->get_gateway_customer_id())) {
|
|
return '';
|
|
}
|
|
|
|
$url = apply_filters("wu_{$gateway_id}_remote_customer_url", $this->get_object()->get_gateway_customer_id());
|
|
|
|
if ($url) {
|
|
return sprintf('<a class="wu-text-gray-800 wu-text-center wu-w-full wu-no-underline" href="%s" target="_blank">%s</a>', esc_attr($url), __('View on Gateway →', 'wp-multisite-waas'));
|
|
}
|
|
|
|
return '';
|
|
},
|
|
'wrapper_html_attr' => [
|
|
'v-show' => 'is_recurring && is_auto_renew',
|
|
'v-cloak' => '1',
|
|
],
|
|
'fields' => [
|
|
'gateway_customer_id' => [
|
|
'type' => 'text',
|
|
'title' => __('Gateway Customer ID', 'wp-multisite-waas'),
|
|
'placeholder' => __('Gateway Customer ID', 'wp-multisite-waas'),
|
|
'value' => $this->get_object()->get_gateway_customer_id(),
|
|
'tooltip' => '',
|
|
'wrapper_classes' => 'wu-w-full',
|
|
'wrapper_html_attr' => [],
|
|
'html_attr' => [
|
|
'v-model' => 'gateway_customer_id',
|
|
],
|
|
],
|
|
],
|
|
],
|
|
|
|
'gateway_subscription_id_group' => [
|
|
'type' => 'group',
|
|
'desc' => function (): string {
|
|
|
|
$gateway_id = $this->get_object()->get_gateway();
|
|
|
|
if (empty($this->get_object()->get_gateway_subscription_id())) {
|
|
return '';
|
|
}
|
|
|
|
$url = apply_filters("wu_{$gateway_id}_remote_subscription_url", $this->get_object()->get_gateway_subscription_id());
|
|
|
|
if ($url) {
|
|
return sprintf('<a class="wu-text-gray-800 wu-text-center wu-w-full wu-no-underline" href="%s" target="_blank">%s</a>', esc_attr($url), __('View on Gateway →', 'wp-multisite-waas'));
|
|
}
|
|
|
|
return '';
|
|
},
|
|
'wrapper_html_attr' => [
|
|
'v-show' => 'is_recurring && is_auto_renew',
|
|
'v-cloak' => '1',
|
|
],
|
|
'fields' => [
|
|
'gateway_subscription_id' => [
|
|
'type' => 'text',
|
|
'title' => __('Gateway Subscription ID', 'wp-multisite-waas'),
|
|
'placeholder' => __('Gateway Subscription ID', 'wp-multisite-waas'),
|
|
'value' => $this->get_object()->get_gateway_subscription_id(),
|
|
'tooltip' => '',
|
|
'wrapper_classes' => 'wu-w-full',
|
|
'wrapper_html_attr' => [],
|
|
'html_attr' => [
|
|
'v-model' => 'gateway_subscription_id',
|
|
],
|
|
],
|
|
],
|
|
],
|
|
|
|
'gateway_note' => [
|
|
'type' => 'note',
|
|
'desc' => __('We will try to cancel the old subscription on the gateway.', 'wp-multisite-waas'),
|
|
'classes' => 'wu-p-2 wu-bg-red-100 wu-text-red-600 wu-rounded wu-w-full',
|
|
'wrapper_html_attr' => [
|
|
'v-show' => 'is_recurring && (' . implode(
|
|
' || ',
|
|
[
|
|
'"' . $this->get_object()->get_gateway() . '" !== "" && gateway !== "' . $this->get_object()->get_gateway() . '"',
|
|
'"' . $this->get_object()->get_gateway_subscription_id() . '" !== "" && gateway_subscription_id !== "' . $this->get_object()->get_gateway_subscription_id() . '"',
|
|
'"' . $this->get_object()->get_gateway_customer_id() . '" !== "" && gateway_customer_id !== "' . $this->get_object()->get_gateway_customer_id() . '"',
|
|
]
|
|
) . ')',
|
|
'v-cloak' => '1',
|
|
],
|
|
],
|
|
],
|
|
]
|
|
);
|
|
|
|
$timestamp_fields = [];
|
|
|
|
$timestamps = [
|
|
'date_expiration' => __('Expires at', 'wp-multisite-waas'),
|
|
'date_renewed' => __('Last Renewed at', 'wp-multisite-waas'),
|
|
'date_trial_end' => __('Trial Ends at', 'wp-multisite-waas'),
|
|
'date_cancellation' => __('Cancelled at', 'wp-multisite-waas'),
|
|
];
|
|
|
|
foreach ($timestamps as $timestamp_name => $timestamp_label) {
|
|
$value = $this->get_object()->{"get_$timestamp_name"}();
|
|
|
|
$timestamp_fields[ $timestamp_name ] = [
|
|
'title' => $timestamp_label,
|
|
'type' => 'text-edit',
|
|
'date' => true,
|
|
'edit' => true,
|
|
'display_value' => $this->edit ? $value : '',
|
|
'value' => $value,
|
|
'placeholder' => '2020-04-04 12:00:00',
|
|
'html_attr' => [
|
|
'wu-datepicker' => 'true',
|
|
'data-format' => 'Y-m-d H:i:S',
|
|
'data-allow-time' => 'true',
|
|
],
|
|
];
|
|
}
|
|
|
|
if ( ! $this->get_object()->is_lifetime()) {
|
|
$timestamp_fields['convert_to_lifetime'] = [
|
|
'type' => 'submit',
|
|
'title' => __('Convert to Lifetime', 'wp-multisite-waas'),
|
|
'value' => 'convert_to_lifetime',
|
|
'classes' => 'button wu-w-full',
|
|
'wrapper_html_attr' => [],
|
|
];
|
|
}
|
|
|
|
$this->add_fields_widget(
|
|
'membership-timestamps',
|
|
[
|
|
'title' => __('Important Timestamps', 'wp-multisite-waas'),
|
|
'fields' => $timestamp_fields,
|
|
]
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Renders the widget used to display the product list.
|
|
*
|
|
* @since 2.0.0
|
|
* @return string
|
|
*/
|
|
public function output_widget_products() {
|
|
|
|
return wu_get_template_contents(
|
|
'memberships/product-list',
|
|
[
|
|
'membership' => $this->get_object(),
|
|
]
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Returns the title of the page.
|
|
*
|
|
* @since 2.0.0
|
|
* @return string Title of the page.
|
|
*/
|
|
public function get_title() {
|
|
|
|
return $this->edit ? __('Edit Membership', 'wp-multisite-waas') : __('Add new Membership', 'wp-multisite-waas');
|
|
}
|
|
|
|
/**
|
|
* Returns the title of menu for this page.
|
|
*
|
|
* @since 2.0.0
|
|
* @return string Menu label of the page.
|
|
*/
|
|
public function get_menu_title() {
|
|
|
|
return __('Edit Membership', 'wp-multisite-waas');
|
|
}
|
|
|
|
/**
|
|
* Returns the action links for that page.
|
|
*
|
|
* @since 1.8.2
|
|
* @return array
|
|
*/
|
|
public function action_links() {
|
|
|
|
return [];
|
|
}
|
|
|
|
/**
|
|
* Returns the labels to be used on the admin page.
|
|
*
|
|
* @since 2.0.0
|
|
* @return array
|
|
*/
|
|
public function get_labels() {
|
|
|
|
return [
|
|
'edit_label' => __('Edit Membership', 'wp-multisite-waas'),
|
|
'add_new_label' => __('Add new Membership', 'wp-multisite-waas'),
|
|
'updated_message' => __('Membership updated with success!', 'wp-multisite-waas'),
|
|
'title_placeholder' => __('Enter Membership Name', 'wp-multisite-waas'),
|
|
'title_description' => __('This name will be used on pricing tables, invoices, and more.', 'wp-multisite-waas'),
|
|
'save_button_label' => __('Save Membership', 'wp-multisite-waas'),
|
|
'save_description' => '',
|
|
'delete_button_label' => __('Delete Membership', 'wp-multisite-waas'),
|
|
'delete_description' => __('Be careful. This action is irreversible.', 'wp-multisite-waas'),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Filters the list table to return only relevant payments.
|
|
*
|
|
* @since 2.0.0
|
|
*
|
|
* @param array $args Query args passed to the list table.
|
|
* @return array Modified query args.
|
|
*/
|
|
public function payments_query_filter($args) {
|
|
|
|
$args['membership_id'] = $this->get_object()->get_id();
|
|
|
|
return $args;
|
|
}
|
|
|
|
/**
|
|
* Filters the list table to return only relevant sites.
|
|
*
|
|
* @since 2.0.0
|
|
*
|
|
* @param array $args Query args passed to the list table.
|
|
* @return array Modified query args.
|
|
*/
|
|
public function sites_query_filter($args) {
|
|
|
|
$args['meta_query'] = [
|
|
'membership_id' => [
|
|
'key' => 'wu_membership_id',
|
|
'value' => $this->get_object()->get_id(),
|
|
],
|
|
];
|
|
|
|
return $args;
|
|
}
|
|
|
|
/**
|
|
* Filters the list table to return only relevant customer.
|
|
*
|
|
* @since 2.0.0
|
|
*
|
|
* @param array $args Query args passed to the list table.
|
|
* @return array Modified query args.
|
|
*/
|
|
public function customer_query_filter($args) {
|
|
|
|
$args['id'] = $this->get_object()->get_customer_id();
|
|
|
|
return $args;
|
|
}
|
|
|
|
/**
|
|
* Filters the list table to return only relevant events.
|
|
*
|
|
* @since 2.0.0
|
|
*
|
|
* @param array $args Query args passed to the list table.
|
|
* @return array Modified query args.
|
|
*/
|
|
public function events_query_filter($args) {
|
|
|
|
$extra_args = [
|
|
'object_type' => 'membership',
|
|
'object_id' => absint($this->get_object()->get_id()),
|
|
];
|
|
|
|
return array_merge($args, $extra_args);
|
|
}
|
|
|
|
/**
|
|
* Returns the object being edit at the moment.
|
|
*
|
|
* @since 2.0.0
|
|
* @return \WP_Ultimo\Models\Membership
|
|
*/
|
|
public function get_object() {
|
|
|
|
if (null !== $this->object) {
|
|
return $this->object;
|
|
}
|
|
|
|
$item_id = wu_request('id', 0);
|
|
|
|
$item = wu_get_membership($item_id);
|
|
|
|
if ( ! $item) {
|
|
wp_safe_redirect(wu_network_admin_url('wp-ultimo-memberships'));
|
|
|
|
exit;
|
|
}
|
|
|
|
$this->object = $item;
|
|
|
|
/**
|
|
* Deal with scheduled swaps.
|
|
*/
|
|
if (wu_request('preview-swap')) {
|
|
$swap_order = $this->get_object()->get_scheduled_swap();
|
|
|
|
if ( ! $swap_order) {
|
|
return $this->object;
|
|
}
|
|
|
|
$this->is_swap_preview = true;
|
|
|
|
$actions = [
|
|
'preview' => [
|
|
'title' => __('← Go back', 'wp-multisite-waas'),
|
|
'url' => remove_query_arg('preview-swap', wu_get_current_url()),
|
|
],
|
|
];
|
|
|
|
$date = new \DateTime($swap_order->scheduled_date);
|
|
|
|
// translators: %s is the date, using the site format options
|
|
$message = sprintf(__('This is a <strong>preview</strong>. This page displays the final stage of the membership after the changes scheduled for <strong>%s</strong>. Saving here will persist these changes, so be careful.', 'wp-multisite-waas'), $date->format(get_option('date_format')));
|
|
|
|
WP_Ultimo()->notices->add($message, 'info', 'network-admin', false, $actions);
|
|
|
|
$this->object->swap($swap_order->order);
|
|
}
|
|
|
|
return $this->object;
|
|
}
|
|
|
|
/**
|
|
* Memberships have titles.
|
|
*
|
|
* @since 2.0.0
|
|
*/
|
|
public function has_title(): bool {
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Handle convert to lifetime.
|
|
*
|
|
* @since 2.0.0
|
|
*/
|
|
protected function handle_convert_to_lifetime(): bool {
|
|
|
|
$object = $this->get_object();
|
|
|
|
$object->set_date_expiration(null);
|
|
|
|
$save = $object->save();
|
|
|
|
if (is_wp_error($save)) {
|
|
$errors = implode('<br>', $save->get_error_messages());
|
|
|
|
WP_Ultimo()->notices->add($errors, 'error', 'network-admin');
|
|
|
|
return false;
|
|
}
|
|
|
|
$array_params = [
|
|
'updated' => 1,
|
|
];
|
|
|
|
if (false === $this->edit) {
|
|
$array_params['id'] = $object->get_id();
|
|
}
|
|
|
|
$url = add_query_arg($array_params);
|
|
|
|
wp_safe_redirect($url);
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Should implement the processes necessary to save the changes made to the object.
|
|
*
|
|
* @since 2.0.0
|
|
* @return true
|
|
*/
|
|
public function handle_save() {
|
|
|
|
$object = $this->get_object();
|
|
|
|
// Cancel membership on gateway
|
|
if ( (bool) wu_request('cancel_gateway', false) && wu_request('status', Membership_Status::CANCELLED)) {
|
|
$gateway = wu_get_gateway(wu_request('gateway'));
|
|
|
|
if ($gateway) {
|
|
$gateway->process_cancellation($object, $object->get_customer());
|
|
|
|
$_POST['gateway'] = '';
|
|
}
|
|
}
|
|
|
|
if (wu_request('submit_button') === 'convert_to_lifetime') {
|
|
return $this->handle_convert_to_lifetime();
|
|
}
|
|
|
|
$_POST['auto_renew'] = (bool) wu_request('auto_renew', false);
|
|
|
|
$billing_address = $object->get_billing_address();
|
|
|
|
$billing_address->attributes($_POST);
|
|
|
|
$valid_address = $billing_address->validate();
|
|
|
|
if (is_wp_error($valid_address)) {
|
|
$errors = implode('<br>', $valid_address->get_error_messages());
|
|
|
|
WP_Ultimo()->notices->add($errors, 'error', 'network-admin');
|
|
|
|
return false;
|
|
}
|
|
|
|
$object->set_billing_address($billing_address);
|
|
|
|
ob_start();
|
|
|
|
$status = parent::handle_save();
|
|
|
|
if ($this->is_swap_preview) {
|
|
ob_clean();
|
|
|
|
$object->delete_scheduled_swap();
|
|
|
|
$array_params = [
|
|
'updated' => 1,
|
|
];
|
|
|
|
$url = add_query_arg($array_params);
|
|
|
|
$url = remove_query_arg('preview-swap', $url);
|
|
|
|
wp_safe_redirect($url);
|
|
|
|
return true;
|
|
}
|
|
|
|
return $status;
|
|
}
|
|
|
|
/**
|
|
* Renders the add/edit line items form.
|
|
*
|
|
* @since 2.0.0
|
|
* @return void
|
|
*/
|
|
public function render_edit_membership_product_modal(): void {
|
|
|
|
$membership = wu_get_membership(wu_request('id'));
|
|
|
|
if ( ! $membership) {
|
|
return;
|
|
}
|
|
|
|
$gateway_message = false;
|
|
|
|
if ( ! empty($membership->get_gateway())) {
|
|
$gateway = wu_get_gateway($membership->get_gateway());
|
|
|
|
$gateway_message = $gateway ? $gateway->get_amount_update_message() : '';
|
|
}
|
|
|
|
$fields = [
|
|
'product_id' => [
|
|
'type' => 'model',
|
|
'title' => __('Product', 'wp-multisite-waas'),
|
|
'placeholder' => __('Search product...', 'wp-multisite-waas'),
|
|
'value' => '',
|
|
'tooltip' => '',
|
|
'html_attr' => [
|
|
'data-model' => 'product',
|
|
'data-value-field' => 'id',
|
|
'data-label-field' => 'name',
|
|
'data-search-field' => 'name',
|
|
'data-max-items' => 1,
|
|
'data-selected' => '',
|
|
],
|
|
],
|
|
'quantity' => [
|
|
'type' => 'number',
|
|
'title' => __('Quantity', 'wp-multisite-waas'),
|
|
'value' => 1,
|
|
'placeholder' => 1,
|
|
'wrapper_classes' => 'wu-w-1/2',
|
|
'html_attr' => [
|
|
'min' => 1,
|
|
'required' => 'required',
|
|
],
|
|
],
|
|
'update_price' => [
|
|
'type' => 'toggle',
|
|
'title' => __('Update Pricing', 'wp-multisite-waas'),
|
|
'desc' => __('Checking this box will update the membership pricing. Otherwise, the products will be added without changing the membership prices.', 'wp-multisite-waas'),
|
|
'html_attr' => [
|
|
'v-model' => 'update_pricing',
|
|
],
|
|
],
|
|
'transfer_note' => [
|
|
'type' => 'note',
|
|
'desc' => $gateway_message,
|
|
'classes' => 'sm:wu-p-2 wu-bg-red-100 wu-text-red-600 wu-rounded wu-w-full',
|
|
'wrapper_html_attr' => [
|
|
'v-show' => 'update_pricing',
|
|
'v-cloak' => '1',
|
|
],
|
|
],
|
|
'submit_button' => [
|
|
'type' => 'submit',
|
|
'title' => __('Add Product', 'wp-multisite-waas'),
|
|
'placeholder' => __('Add Product', 'wp-multisite-waas'),
|
|
'value' => 'save',
|
|
'classes' => 'wu-w-full button button-primary',
|
|
'wrapper_classes' => 'wu-items-end',
|
|
],
|
|
'id' => [
|
|
'type' => 'hidden',
|
|
'value' => $membership->get_id(),
|
|
],
|
|
];
|
|
|
|
if ( ! $gateway_message) {
|
|
unset($fields['transfer_note']);
|
|
}
|
|
|
|
$form = new \WP_Ultimo\UI\Form(
|
|
'edit_membership_product',
|
|
$fields,
|
|
[
|
|
'views' => 'admin-pages/fields',
|
|
'classes' => 'wu-modal-form wu-widget-list wu-striped wu-m-0 wu-mt-0',
|
|
'field_wrapper_classes' => 'wu-w-full wu-box-border wu-items-center wu-flex wu-justify-between wu-p-4 wu-m-0 wu-border-t wu-border-l-0 wu-border-r-0 wu-border-b-0 wu-border-gray-300 wu-border-solid',
|
|
'html_attr' => [
|
|
'data-wu-app' => 'edit_membership_product',
|
|
'data-state' => wu_convert_to_state(
|
|
[
|
|
'update_pricing' => 0,
|
|
]
|
|
),
|
|
],
|
|
]
|
|
);
|
|
|
|
$form->render();
|
|
}
|
|
|
|
/**
|
|
* Handles the add/edit of line items.
|
|
*
|
|
* @since 2.0.0
|
|
* @return mixed
|
|
*/
|
|
public function handle_edit_membership_product_modal(): void {
|
|
|
|
$membership = wu_get_membership(wu_request('id'));
|
|
|
|
if ( ! $membership) {
|
|
$error = new \WP_Error('membership-not-found', __('Membership not found.', 'wp-multisite-waas'));
|
|
|
|
wp_send_json_error($error);
|
|
}
|
|
|
|
$product = wu_get_product(wu_request('product_id'));
|
|
|
|
if ( ! $product) {
|
|
$error = new \WP_Error('product-not-found', __('Product not found.', 'wp-multisite-waas'));
|
|
|
|
wp_send_json_error($error);
|
|
}
|
|
|
|
$membership->add_product($product->get_id(), (int) wu_request('quantity', 1));
|
|
|
|
// if we are updating the pricing, we need to update the membership price.
|
|
if (wu_request('update_price')) {
|
|
$value_to_add = wu_get_membership_product_price($membership, $product->get_id(), (int) wu_request('quantity', 1));
|
|
|
|
if (is_wp_error($value_to_add)) {
|
|
wp_send_json_error($value_to_add);
|
|
}
|
|
|
|
$membership->set_amount($membership->get_amount() + $value_to_add);
|
|
}
|
|
|
|
$saved = $membership->save();
|
|
|
|
if (is_wp_error($saved)) {
|
|
wp_send_json_error($saved);
|
|
}
|
|
|
|
wp_send_json_success(
|
|
[
|
|
'redirect_url' => add_query_arg('updated', 1, $_SERVER['HTTP_REFERER']),
|
|
]
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Renders the deletion confirmation form.
|
|
*
|
|
* @since 2.0.0
|
|
* @return void
|
|
*/
|
|
public function render_remove_membership_product(): void {
|
|
|
|
$membership = wu_get_membership(wu_request('id'));
|
|
|
|
if ( ! $membership) {
|
|
return;
|
|
}
|
|
|
|
$gateway_message = false;
|
|
|
|
if ($membership->get_gateway()) {
|
|
$gateway = wu_get_gateway($membership->get_gateway());
|
|
|
|
$gateway_message = $gateway ? $gateway->get_amount_update_message() : '';
|
|
}
|
|
|
|
$fields = [
|
|
'quantity' => [
|
|
'type' => 'number',
|
|
'title' => __('Quantity', 'wp-multisite-waas'),
|
|
'value' => 1,
|
|
'placeholder' => 1,
|
|
'wrapper_classes' => 'wu-w-1/2',
|
|
'html_attr' => [
|
|
'min' => 1,
|
|
'required' => 'required',
|
|
],
|
|
],
|
|
'update_price' => [
|
|
'type' => 'toggle',
|
|
'title' => __('Update Pricing?', 'wp-multisite-waas'),
|
|
'desc' => __('Checking this box will update the membership pricing. Otherwise, the products will be added without changing the membership prices.', 'wp-multisite-waas'),
|
|
'html_attr' => [
|
|
'v-model' => 'update_pricing',
|
|
],
|
|
],
|
|
'transfer_note' => [
|
|
'type' => 'note',
|
|
'desc' => $gateway_message,
|
|
'classes' => 'sm:wu-p-2 wu-bg-red-100 wu-text-red-600 wu-rounded wu-w-full',
|
|
'wrapper_html_attr' => [
|
|
'v-show' => 'update_pricing',
|
|
'v-cloak' => '1',
|
|
],
|
|
],
|
|
'submit_button' => [
|
|
'type' => 'submit',
|
|
'title' => __('Remove Product', 'wp-multisite-waas'),
|
|
'placeholder' => __('Remove Product', 'wp-multisite-waas'),
|
|
'value' => 'save',
|
|
'classes' => 'wu-w-full button button-primary',
|
|
'wrapper_classes' => 'wu-items-end',
|
|
],
|
|
'id' => [
|
|
'type' => 'hidden',
|
|
'value' => $membership->get_id(),
|
|
],
|
|
'product_id' => [
|
|
'type' => 'hidden',
|
|
'value' => wu_request('product_id', 0),
|
|
],
|
|
];
|
|
|
|
if ( ! $gateway_message) {
|
|
unset($fields['transfer_note']);
|
|
}
|
|
|
|
$form = new \WP_Ultimo\UI\Form(
|
|
'edit_membership_product',
|
|
$fields,
|
|
[
|
|
'views' => 'admin-pages/fields',
|
|
'classes' => 'wu-modal-form wu-widget-list wu-striped wu-m-0 wu-mt-0',
|
|
'field_wrapper_classes' => 'wu-w-full wu-box-border wu-items-center wu-flex wu-justify-between wu-p-4 wu-m-0 wu-border-t wu-border-l-0 wu-border-r-0 wu-border-b-0 wu-border-gray-300 wu-border-solid',
|
|
'html_attr' => [
|
|
'data-wu-app' => 'edit_membership_product',
|
|
'data-state' => wu_convert_to_state(
|
|
[
|
|
'update_pricing' => 0,
|
|
]
|
|
),
|
|
],
|
|
]
|
|
);
|
|
|
|
$form->render();
|
|
}
|
|
|
|
/**
|
|
* Handles the deletion of line items.
|
|
*
|
|
* @since 2.0.0
|
|
* @return void
|
|
*/
|
|
public function handle_remove_membership_product(): void {
|
|
|
|
$membership = wu_get_membership(wu_request('id'));
|
|
|
|
if ( ! $membership) {
|
|
$error = new \WP_Error('membership-not-found', __('Membership not found.', 'wp-multisite-waas'));
|
|
|
|
wp_send_json_error($error);
|
|
}
|
|
|
|
$product = wu_get_product(wu_request('product_id'));
|
|
|
|
if ( ! $product) {
|
|
$error = new \WP_Error('product-not-found', __('Product not found.', 'wp-multisite-waas'));
|
|
|
|
wp_send_json_error($error);
|
|
}
|
|
|
|
// Get the existing quantity by filtering the products array.
|
|
$existing_quantity = array_filter($membership->get_addon_products(), fn($item) => $item['product']->get_id() === $product->get_id())[0]['quantity'];
|
|
|
|
$quantity = (int) wu_request('quantity', 1);
|
|
$quantity = $quantity > $existing_quantity ? $existing_quantity : $quantity;
|
|
|
|
$membership->remove_product($product->get_id(), $quantity);
|
|
|
|
// if we are updating the pricing, we need to update the membership price.
|
|
if (wu_request('update_price')) {
|
|
$value_to_remove = wu_get_membership_product_price($membership, $product->get_id(), $quantity);
|
|
|
|
if (is_wp_error($value_to_remove)) {
|
|
wp_send_json_error($value_to_remove);
|
|
}
|
|
|
|
$membership->set_amount($membership->get_amount() - $value_to_remove);
|
|
}
|
|
|
|
$saved = $membership->save();
|
|
|
|
if (is_wp_error($saved)) {
|
|
wp_send_json_error($saved);
|
|
}
|
|
|
|
wp_send_json_success(
|
|
[
|
|
'redirect_url' => add_query_arg('updated', 1, $_SERVER['HTTP_REFERER']),
|
|
]
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Renders the add/edit line items form.
|
|
*
|
|
* @since 2.0.0
|
|
* @return void
|
|
*/
|
|
public function render_change_membership_plan_modal(): void {
|
|
|
|
$membership = wu_get_membership(wu_request('id'));
|
|
|
|
if ( ! $membership) {
|
|
return;
|
|
}
|
|
|
|
$product = wu_get_product(wu_request('product_id'));
|
|
|
|
if ( ! $product) {
|
|
return;
|
|
}
|
|
|
|
$gateway_message = false;
|
|
|
|
if ($membership->get_gateway()) {
|
|
$gateway = wu_get_gateway($membership->get_gateway());
|
|
|
|
$gateway_message = $gateway ? $gateway->get_amount_update_message() : '';
|
|
}
|
|
|
|
$fields = [
|
|
'plan_id' => [
|
|
'type' => 'model',
|
|
'title' => __('Plan', 'wp-multisite-waas'),
|
|
'placeholder' => __('Search new Plan...', 'wp-multisite-waas'),
|
|
'desc' => __('Select a new plan for this membership.', 'wp-multisite-waas'),
|
|
'value' => $product->get_id(),
|
|
'tooltip' => '',
|
|
'html_attr' => [
|
|
'data-model' => 'plan',
|
|
'v-model' => 'plan_id',
|
|
'data-value-field' => 'id',
|
|
'data-label-field' => 'name',
|
|
'data-search-field' => 'name',
|
|
'data-max-items' => 1,
|
|
'data-selected' => wp_json_encode($product->to_search_results()),
|
|
],
|
|
],
|
|
'update_price' => [
|
|
'type' => 'toggle',
|
|
'title' => __('Update Pricing', 'wp-multisite-waas'),
|
|
'desc' => __('Checking this box will update the membership pricing. Otherwise, the products will be added without changing the membership prices.', 'wp-multisite-waas'),
|
|
'html_attr' => [
|
|
'v-model' => 'update_pricing',
|
|
],
|
|
],
|
|
'transfer_note' => [
|
|
'type' => 'note',
|
|
'desc' => $gateway_message,
|
|
'classes' => 'sm:wu-p-2 wu-bg-red-100 wu-text-red-600 wu-rounded wu-w-full',
|
|
'wrapper_html_attr' => [
|
|
'v-show' => 'update_pricing',
|
|
'v-cloak' => '1',
|
|
],
|
|
],
|
|
'submit_button' => [
|
|
'type' => 'submit',
|
|
'title' => __('Change Product', 'wp-multisite-waas'),
|
|
'placeholder' => __('Change Product', 'wp-multisite-waas'),
|
|
'value' => 'save',
|
|
'classes' => 'wu-w-full button button-primary',
|
|
'wrapper_classes' => 'wu-items-end',
|
|
'html_attr' => [
|
|
'v-bind:class' => 'plan_id == original_plan_id ? "button-disabled" : ""',
|
|
'v-bind:disabled' => 'plan_id == original_plan_id',
|
|
],
|
|
],
|
|
'id' => [
|
|
'type' => 'hidden',
|
|
'value' => $membership->get_id(),
|
|
],
|
|
];
|
|
|
|
if ( ! $gateway_message) {
|
|
unset($fields['transfer_note']);
|
|
}
|
|
|
|
$form = new \WP_Ultimo\UI\Form(
|
|
'change_membership_plan',
|
|
$fields,
|
|
[
|
|
'views' => 'admin-pages/fields',
|
|
'classes' => 'wu-modal-form wu-widget-list wu-striped wu-m-0 wu-mt-0',
|
|
'field_wrapper_classes' => 'wu-w-full wu-box-border wu-items-center wu-flex wu-justify-between wu-p-4 wu-m-0 wu-border-t wu-border-l-0 wu-border-r-0 wu-border-b-0 wu-border-gray-300 wu-border-solid',
|
|
'html_attr' => [
|
|
'data-wu-app' => 'change_membership_plan',
|
|
'data-state' => wu_convert_to_state(
|
|
[
|
|
'update_pricing' => 0,
|
|
'original_plan_id' => $product->get_id(),
|
|
'plan_id' => $product->get_id(),
|
|
]
|
|
),
|
|
],
|
|
]
|
|
);
|
|
|
|
$form->render();
|
|
}
|
|
|
|
/**
|
|
* Handles the add/edit of line items.
|
|
*
|
|
* @since 2.0.0
|
|
* @return mixed
|
|
*/
|
|
public function handle_change_membership_plan_modal(): void {
|
|
|
|
$membership = wu_get_membership(wu_request('id'));
|
|
|
|
if ( ! $membership) {
|
|
$error = new \WP_Error('membership-not-found', __('Membership not found.', 'wp-multisite-waas'));
|
|
|
|
wp_send_json_error($error);
|
|
}
|
|
|
|
$plan = wu_get_product(wu_request('plan_id'));
|
|
|
|
if ( ! $plan) {
|
|
$error = new \WP_Error('plan-not-found', __('Plan not found.', 'wp-multisite-waas'));
|
|
|
|
wp_send_json_error($error);
|
|
}
|
|
|
|
$original_plan_id = $membership->get_plan_id();
|
|
|
|
if (absint($original_plan_id) === absint($plan->get_id())) {
|
|
$error = new \WP_Error('same-plan', __('No change performed. The same plan selected.', 'wp-multisite-waas'));
|
|
|
|
wp_send_json_error($error);
|
|
}
|
|
|
|
$membership->set_plan_id($plan->get_id());
|
|
|
|
// if we are updating the pricing, we need to update the membership price.
|
|
if (wu_request('update_price')) {
|
|
$value_to_add = wu_get_membership_product_price($membership, $plan->get_id(), 1);
|
|
|
|
if (is_wp_error($value_to_add)) {
|
|
wp_send_json_error($value_to_add);
|
|
}
|
|
|
|
$value_to_remove = wu_get_membership_product_price($membership, $original_plan_id, 1);
|
|
|
|
if (is_wp_error($value_to_remove)) {
|
|
wp_send_json_error($value_to_remove);
|
|
}
|
|
|
|
$membership->set_amount($membership->get_amount() + $value_to_add - $value_to_remove);
|
|
}
|
|
|
|
$saved = $membership->save();
|
|
|
|
if (is_wp_error($saved)) {
|
|
wp_send_json_error($saved);
|
|
}
|
|
|
|
wp_send_json_success(
|
|
[
|
|
'redirect_url' => add_query_arg('updated', 1, $_SERVER['HTTP_REFERER']),
|
|
]
|
|
);
|
|
}
|
|
}
|