Initial Commit

This commit is contained in:
David Stone
2024-11-30 18:24:12 -07:00
commit e8f7955c1c
5432 changed files with 1397750 additions and 0 deletions

View File

@ -0,0 +1,147 @@
<?php
/**
* WP Ultimo About Admin Page.
*
* @package WP_Ultimo
* @subpackage Admin_Pages
* @since 2.0.0
*/
namespace WP_Ultimo\Admin_Pages;
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* WP Ultimo About Admin Page.
*/
class About_Admin_Page extends Base_Admin_Page {
/**
* Holds the ID for this page, this is also used as the page slug.
*
* @var string
*/
protected $id = 'wp-ultimo-about';
/**
* Is this a top-level menu or a submenu?
*
* @since 1.8.2
* @var string
*/
protected $type = 'submenu';
/**
* 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';
/**
* Should we hide admin notices on this page?
*
* @since 2.0.0
* @var boolean
*/
protected $hide_admin_notices = true;
/**
* Should we force the admin menu into a folded state?
*
* @since 2.0.0
* @var boolean
*/
protected $fold_menu = true;
/**
* 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 = array(
'network_admin_menu' => 'manage_network',
);
/**
* Returns the title of the page.
*
* @since 2.0.0
* @return string Title of the page.
*/
public function get_title() {
return __('About', 'wp-ultimo');
} // end get_title;
/**
* 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 __('WP Ultimo', 'wp-ultimo');
} // end get_menu_title;
/**
* Allows admins to rename the sub-menu (first item) for a top-level page.
*
* @since 2.0.0
* @return string False to use the title menu or string with sub-menu title.
*/
public function get_submenu_title() {
return __('About', 'wp-ultimo');
} // end get_submenu_title;
/**
* Every child class should implement the output method to display the contents of the page.
*
* @since 1.8.2
* @return void
*/
public function output() {
wu_get_template('about');
} // end output;
/**
* Adds the cure bg image here as well.
*
* @since 2.0.0
* @return void
*/
public function register_scripts() {
parent::register_scripts();
wp_add_inline_style('wu-admin', sprintf('
#wpwrap {
background: url("%s") right bottom no-repeat;
background-size: 60%%;
}', wu_get_asset('bg-setup.png', 'img')));
} // end register_scripts;
} // end class About_Admin_Page;

View File

@ -0,0 +1,553 @@
<?php
/**
* WP Ultimo Dashboard Admin Page.
*
* @package WP_Ultimo
* @subpackage Admin_Pages
* @since 2.0.0
*/
namespace WP_Ultimo\Admin_Pages;
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* WP Ultimo Dashboard Admin Page.
*/
class Addons_Admin_Page extends Wizard_Admin_Page {
/**
* Holds the ID for this page, this is also used as the page slug.
*
* @var string
*/
protected $id = 'wp-ultimo-addons';
/**
* Is this a top-level menu or a submenu?
*
* @since 1.8.2
* @var string
*/
protected $type = 'submenu';
/**
* Menu position. This is only used for top-level menus
*
* @since 1.8.2
* @var integer
*/
protected $position = 999;
/**
* Is this a top-level menu or a submenu?
*
* @since 1.8.2
* @var string
*/
protected $parent = 'wp-ultimo';
/**
* 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;
/**
* 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 = array(
'network_admin_menu' => 'wu_read_settings',
);
/**
* Should we hide admin notices on this page?
*
* @since 2.0.0
* @var boolean
*/
protected $hide_admin_notices = false;
/**
* Should we force the admin menu into a folded state?
*
* @since 2.0.0
* @var boolean
*/
protected $fold_menu = false;
/**
* Holds the section slug for the URLs.
*
* @since 2.0.0
* @var string
*/
protected $section_slug = 'tab';
/**
* Defines if the step links on the side are clickable or not.
*
* @since 2.0.0
* @var boolean
*/
protected $clickable_navigation = true;
/**
* Caches the list of add-ons.
*
* @since 2.0.0
* @var null|array
*/
protected $addons;
/**
* Allow child classes to add hooks to be run once the page is loaded.
*
* @see https://codex.wordpress.org/Plugin_API/Action_Reference/load-(page)
* @since 1.8.2
* @return void
*/
public function init() {
parent::init();
add_action('wp_ajax_serve_addons_list', array($this, 'serve_addons_list'));
} // end init;
/**
* Register forms
*
* @since 2.0.0
* @return void
*/
public function register_forms() {
wu_register_form('addon_more_info', array(
'render' => array($this, 'display_more_info'),
'handler' => array($this, 'install_addon'),
));
} // end register_forms;
/**
* Displays the more info tab.
*
* @since 2.0.0
* @return void
*/
public function display_more_info() {
$addon_slug = wu_request('addon');
$addon = wu_get_isset($this->get_addons_list(), $addon_slug);
$upgrade_url = wu_network_admin_url('wp-ultimo-pricing', array(
'checkout' => 'true',
'plan_id' => '4675',
'plan_name' => 'wpultimo',
'billing_cycle' => 'annual',
'pricing_id' => '3849',
'currency' => 'usd',
));
wu_get_template('base/addons/details', array(
'upgrade_url' => $upgrade_url,
'addon' => (object) $addon,
'addon_slug' => $addon_slug,
'license' => \WP_Ultimo\License::get_instance(),
));
do_action('wu_form_scripts', false);
} // end display_more_info;
/**
* Installs a given add-on.
*
* @since 2.0.0
* @return void
*/
public function install_addon() {
if (!current_user_can('manage_network_plugins')) {
$error = new \WP_Error('error', __('You do not have enough permissions to perform this task.', 'wp-ultimo'));
wp_send_json_error($error);
} // end if;
$addon_slug = wu_request('addon');
$addon = wu_get_isset($this->get_addons_list(), $addon_slug);
$download_url = add_query_arg(array(
'action' => 'download',
'slug' => $addon_slug,
'beta_program' => 2,
'license_key' => rawurlencode((string) \WP_Ultimo\License::get_instance()->get_license_key()),
), 'https://versions.nextpress.co/updates/');
/**
* We check if the URL is one of our websites
*/
$allowed_sites = array(
'http://nextpress.co', 'https://nextpress.co', // New Domain
'http://versions.nextpress.co', 'https://versions.nextpress.co', // New Domain
'http://weare732.com', 'https://weare732.com' // Old Updates Domain
);
if (defined('WP_DEBUG') && WP_DEBUG) {
$allowed_sites[] = 'http://localhost';
$allowed_sites[] = 'http://wp-ultimo.local';
} // end if;
$allowed = false;
foreach ($allowed_sites as $allowed_site) {
if (strncmp($download_url, $allowed_site, strlen($allowed_site)) === 0) {
$allowed = true;
break;
} // end if;
} // end foreach;
if ($allowed) {
// includes necessary for Plugin_Upgrader and Plugin_Installer_Skin
include_once(ABSPATH . 'wp-admin/includes/file.php');
include_once(ABSPATH . 'wp-admin/includes/misc.php');
include_once(ABSPATH . 'wp-admin/includes/class-wp-upgrader.php');
$skin = new \Automatic_Upgrader_Skin(array());
$upgrader = new \Plugin_Upgrader($skin);
add_filter('https_ssl_verify', '__return_false', 2000);
$results = $upgrader->install($download_url);
remove_filter('https_ssl_verify', '__return_false', 2000);
if (is_wp_error($results)) {
wp_send_json_error($results);
} // end if;
$messages = $upgrader->skin->get_upgrade_messages();
if (!in_array($upgrader->strings['process_success'], $messages, true)) {
$error = new \WP_Error('error', array_pop($messages));
wp_send_json_error($error);
} // end if;
wp_send_json_success(array(
'redirect_url' => add_query_arg(array(
's' => urlencode((string) $addon['name']),
), network_admin_url('plugins.php')),
));
} else {
$error = new \WP_Error('insecure-url', __('You are trying to download an add-on from an insecure URL', 'wp-ultimo'));
wp_send_json_error($error);
} // end if;
} // end install_addon;
/**
* Enqueue the necessary scripts.
*
* @since 2.0.0
* @return void
*/
public function register_scripts() {
wp_enqueue_style('theme');
wp_register_script('wu-addons', wu_get_asset('addons.js', 'js'), array('jquery', 'wu-vue', 'underscore'), wu_get_version(), true);
wp_localize_script('wu-addons', 'wu_addons', array(
'search' => wu_request('s', ''),
'category' => wu_request('tab', 'all'),
'i18n' => array(
'all' => __('All Add-ons', 'wp-ultimo'),
),
));
wp_enqueue_script('wu-addons');
} // end register_scripts;
/**
* Fetches the list of add-ons available.
*
* @since 2.0.0
* @return array
*/
protected function get_addons_list() {
/*
* Checks if we have a cached version.
*/
if (is_array($this->addons)) {
return $this->addons;
} // end if;
/*
* Check for local cache.
*/
if (!wu_is_debug()) {
$addons_list = get_site_transient('wu-addons-list');
if (is_array($addons_list) && !empty($addons_list)) {
$this->addons = $addons_list;
return $this->addons;
} // end if;
} // end if;
$base_url = 'https://versions.nextpress.co/updates/';
$remote_url = add_query_arg(array(
'slug' => 'wp-ultimo',
'action' => 'addons',
'installed_version' => wu_get_version(),
), $base_url);
if (defined('WP_ULTIMO_DEVELOPER_KEY') && WP_ULTIMO_DEVELOPER_KEY) {
$remote_url = add_query_arg('developer_key', WP_ULTIMO_DEVELOPER_KEY, $remote_url);
} // end if;
$response = wp_remote_get($remote_url, array(
'sslverify' => false,
));
if (is_wp_error($response)) {
return array();
} // end if;
$data = wp_remote_retrieve_body($response);
$data = json_decode($data, true);
if (!is_array($data)) {
return array();
} // end if;
/*
* Adds missing keys
*/
foreach ($data as $slug => $item) {
/*
* Checks if this is a free add-on.
*/
$item['free'] = wu_get_isset($item, 'free', false);
/*
* Checks if the plugin is installed.
*/
$item['installed'] = $this->is_plugin_installed($slug);
$this->addons[$slug] = $item;
} // end foreach;
set_transient('wu-addons-list', $this->addons, 2 * DAY_IN_SECONDS);
return $this->addons;
} // end get_addons_list;
/**
* Checks if a given plugin is installed.
*
* @since 2.0.0
* @param string $plugin_slug The plugin slug to check.
* @return boolean
*/
public function is_plugin_installed($plugin_slug) {
$plugin_keys = array_keys(get_plugins());
$installed_plugins = implode(' - ', $plugin_keys);
return stristr($installed_plugins, $plugin_slug) !== false;
} // end is_plugin_installed;
/**
* Gets the list of addons from the remote server.
*
* @since 2.0.0
* @return void
*/
public function serve_addons_list() {
$addons_list = $this->get_addons_list();
wp_send_json_success($addons_list);
} // end serve_addons_list;
/**
* Returns the title of the page.
*
* @since 2.0.0
* @return string Title of the page.
*/
public function get_title() {
return __('Add-ons', 'wp-ultimo');
} // end get_title;
/**
* 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 __('Add-ons', 'wp-ultimo');
} // end get_menu_title;
/**
* Every child class should implement the output method to display the contents of the page.
*
* @since 1.8.2
* @return void
*/
public function output() {
$more_info_url = wu_get_form_url('addon_more_info', array(
'width' => 768,
'addon' => 'ADDON_SLUG',
));
wu_get_template('base/addons', array(
'screen' => get_current_screen(),
'page' => $this,
'classes' => '',
'sections' => $this->get_sections(),
'current_section' => $this->get_current_section(),
'clickable_navigation' => $this->clickable_navigation,
'more_info_url' => $more_info_url,
'license' => \WP_Ultimo\License::get_instance(),
));
} // end output;
/**
* Returns the list of settings sections.
*
* @since 2.0.0
* @return array
*/
public function get_sections() {
return array(
'all' => array(
'title' => __('All Add-ons', 'wp-ultimo'),
'icon' => 'dashicons-wu-grid',
),
'premium' => array(
'title' => __('Premium', 'wp-ultimo'),
'icon' => 'dashicons-wu-rocket',
),
'free' => array(
'title' => __('Free', 'wp-ultimo'),
'icon' => 'dashicons-wu-pin',
),
'gateways' => array(
'title' => __('Gateways', 'wp-ultimo'),
'icon' => 'dashicons-wu-credit-card',
),
'growth' => array(
'title' => __('Growth & Scaling', 'wp-ultimo'),
'icon' => 'dashicons-wu-line-graph',
),
'integrations' => array(
'title' => __('Integrations', 'wp-ultimo'),
'icon' => 'dashicons-wu-power-plug',
),
'customization' => array(
'title' => __('Customization', 'wp-ultimo'),
'icon' => 'dashicons-wu-edit',
),
'admin theme' => array(
'title' => __('Admin Themes', 'wp-ultimo'),
'icon' => 'dashicons-wu-palette',
),
'monetization' => array(
'title' => __('Monetization', 'wp-ultimo'),
'icon' => 'dashicons-wu-credit',
),
'migrators' => array(
'title' => __('Migrators', 'wp-ultimo'),
'icon' => 'dashicons-wu-publish',
),
'separator' => array(
'separator' => true,
),
'marketplace' => array(
'title' => __('Marketplace', 'wp-ultimo'),
'icon' => 'dashicons-wu-shop',
),
);
} // end get_sections;
/**
* Default handler for step submission. Simply redirects to the next step.
*
* @since 2.0.0
* @return void
*/
public function default_handler() {
WP_Ultimo()->settings->save_settings($_POST);
wp_redirect(add_query_arg('updated', 1, wu_get_current_url()));
exit;
} // end default_handler;
} // end class Addons_Admin_Page;

View File

@ -0,0 +1,783 @@
<?php
/**
* Base admin page class.
*
* Abstract class that makes it easy to create new admin pages.
*
* Most of WP Ultimo pages are implemented using this class, which means that the filters and hooks
* listed below can be used to append content to all of our pages at once.
*
* @package WP_Ultimo
* @subpackage Admin_Pages
* @since 2.0.0
*/
namespace WP_Ultimo\Admin_Pages;
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Abstract class that makes it easy to create new admin pages.
*/
abstract class Base_Admin_Page {
/**
* @var bool
*/
protected $edit;
/**
* Holds the ID for this page, this is also used as the page slug.
*
* @var string
*/
protected $id;
/**
* Is this a top-level menu or a submenu?
*
* @since 1.8.2
* @var string
*/
protected $type = 'menu';
/**
* If this is a submenu, we need a parent menu to attach this to
*
* @since 1.8.2
* @var string
*/
protected $parent = 'wp-ultimo';
/**
* Holds the list of action links.
* These are the ones displayed next to the title of the page. e.g. Add New.
*
* @since 1.8.2
* @var array
*/
public $action_links = array();
/**
* Holds the page title
*
* @since 1.8.2
* @var string
*/
protected $title;
/**
* Holds the menu label of the page, this is what we effectively use on the menu item
*
* @since 1.8.2
* @var string
*/
protected $menu_title;
/**
* After we create the menu item using WordPress functions, we need to store the generated hook.
*
* @since 1.8.2
* @var string
*/
protected $page_hook;
/**
* Menu position. This is only used for top-level menus
*
* @since 1.8.2
* @var integer
*/
protected $position;
/**
* Dashicon to be used on the menu item. This is only used on top-level menus
*
* @since 1.8.2
* @var string
*/
protected $menu_icon;
/**
* 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;
/**
* If this is a top-level menu, we can need the option to rewrite the sub-menu
*
* @since 1.8.2
* @var boolean|string
*/
protected $submenu_title = false;
/**
* Allows us to highlight another menu page, if this page has no parent page at all.
*
* @since 2.0.0
* @var bool|string
*/
protected $highlight_menu_slug = false;
/**
* Should we hide admin notices on this page?
*
* @since 2.0.0
* @var boolean
*/
protected $hide_admin_notices = false;
/**
* Should we force the admin menu into a folded state?
*
* @since 2.0.0
* @var boolean
*/
protected $fold_menu = false;
/**
* Should we remove the default WordPress frame?
*
* When set to true, this will remove the admin top-bar and the admin menu.
*
* @since 2.0.0
* @var boolean
*/
protected $remove_frame = 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 = array(
'network_admin_menu' => 'manage_network',
);
/**
* Creates the page with the necessary hooks.
*
* @since 1.8.2
*/
public function __construct() {
/*
* Adds the page to all the necessary admin panels.
*/
foreach ($this->supported_panels as $panel => $capability) {
add_action($panel, array($this, 'add_menu_page'));
add_action($panel, array($this, 'fix_subdomain_name'), 100);
} // end foreach;
/*
* Delegates further initializations to the child class.
*/
$this->init();
/*
* Add forms
*/
add_action('plugins_loaded', array($this, 'register_forms'));
/**
* Allow plugin developers to run additional things when pages are registered.
*
* Unlike the wu_page_load, which only runs when a specific page
* is being seen, this hook runs at registration for every admin page
* being added using WP Ultimo code.
*
* @since 2.0.0
* @param string $page_id The ID of this page.
* @return void
*/
do_action('wu_page_added', $this->id, $this->page_hook);
} // end __construct;
/**
* Returns the ID of the admin page.
*
* @since 2.0.0
* @return string
*/
public function get_id() {
return $this->id;
} // end get_id;
/**
* Returns the appropriate capability for a this page, depending on the context.
*
* @since 2.0.0
* @return string
*/
public function get_capability() {
if (is_user_admin()) {
return $this->supported_panels['user_admin_menu'];
} elseif (is_network_admin()) {
return $this->supported_panels['network_admin_menu'];
} // end if;
return $this->supported_panels['admin_menu'];
} // end get_capability;
/**
* Fix the subdomain name if an option (submenu title) is passed.
*
* @since 1.8.2
* @return void
*/
public function fix_subdomain_name() {
global $submenu;
if ($this->get_submenu_title() && $this->type === 'menu' && isset($submenu[$this->id]) && $submenu[$this->id][0][3] === $this->get_title()) {
$submenu[$this->id][0][0] = $this->get_submenu_title();
} // end if;
} // end fix_subdomain_name;
/**
* Fix the highlight Menu.
*
* @since 2.0.0
* @param string $file Fix the menu highlight for menus without parent.
* @return string
*/
public function fix_menu_highlight($file) {
global $plugin_page;
if ($this->highlight_menu_slug && isset($_GET['page']) && $_GET['page'] === $this->get_id()) {
$plugin_page = $this->highlight_menu_slug;
$file = $this->highlight_menu_slug;
} // end if;
return $file;
} // end fix_menu_highlight;
/**
* Install the base hooks for developers
*
* @since 1.8.2
* @return void
*/
public function install_hooks() {
/**
* Get the action links
*/
$this->action_links = $this->action_links();
/**
* Allow plugin developers to add additional hooks to our pages.
*
* @since 1.8.2
* @since 2.0.4 Added third parameter: the page instance.
*
* @param string $id The ID of this page.
* @param string $page_hook The page hook of this page.
* @param self $admin_page TThe page instance.
*
* @return void
*/
do_action('wu_page_load', $this->id, $this->page_hook, $this);
/**
* Allow plugin developers to add additional hooks to our pages.
*
* @since 1.8.2
* @since 2.0.4 Added third parameter: the page instance.
*
* @param string $id The ID of this page.
* @param string $page_hook The page hook of this page.
* @param self $admin_page TThe page instance.
*
* @return void
*/
do_action("wu_page_{$this->id}_load", $this->id, $this->page_hook, $this);
/**
* Fixes menu highlights when necessary.
*/
add_filter('parent_file', array($this, 'fix_menu_highlight'), 99);
add_filter('submenu_file', array($this, 'fix_menu_highlight'), 99);
} // end install_hooks;
/**
* Get the badge value, to append to the menu item title.
*
* @since 1.8.2
* @return string
*/
public function get_badge() {
$markup = '&nbsp;<span class="update-plugins count-%s">
<span class="update-count">%s</span>
</span>';
return $this->badge_count >= 1 ? sprintf($markup, $this->badge_count, $this->badge_count) : '';
} // end get_badge;
/**
* Displays the page content.
*
* @since 1.8.2
* @return void
*/
final public function display() {
/**
* 'Hack-y' solution for the customer facing title problem... but good enough for now.
*
* @todo review when possible.
*/
add_filter('wp_ultimo_render_vars', function($vars) {
$vars['page_title'] = $this->get_title();
return $vars;
});
/**
* Allow plugin developers to add additional content before we print the page.
*
* @since 1.8.2
* @param string $this->id The id of this page.
* @return void
*/
do_action('wu_page_before_render', $this->id, $this);
/**
* Allow plugin developers to add additional content before we print the page.
*
* @since 1.8.2
* @param string $this->id The id of this page.
* @return void
*/
do_action("wu_page_{$this->id}_before_render", $this->id, $this);
/*
* Calls the output function.
*/
$this->output();
/**
* Allow plugin developers to add additional content after we print the page
*
* @since 1.8.2
* @param string $this->id The id of this page
* @return void
*/
do_action('wu_page_after_render', $this->id, $this);
/**
* Allow plugin developers to add additional content after we print the page
*
* @since 1.8.2
* @param string $this->id The id of this page
* @return void
*/
do_action("wu_page_{$this->id}_after_render", $this->id, $this);
} // end display;
/**
* Get the menu item, with the badge if necessary.
*
* @since 1.8.2
* @return string
*/
public function get_menu_label() {
return $this->get_menu_title() . $this->get_badge();
} // end get_menu_label;
/**
* Adds the menu items using default WordPress functions and handles the side-effects
*
* @since 1.8.2
* @return void
*/
public function add_menu_page() {
/**
* Create the admin page or sub-page
*/
$this->page_hook = $this->type === 'menu' ? $this->add_toplevel_menu_page() : $this->add_submenu_page();
/**
* Add the default hooks
*/
$this->enqueue_default_hooks();
} // end add_menu_page;
/**
* Adds top-level admin page.
*
* @since 1.8.2
* @return string Page hook generated by WordPress.
*/
public function add_toplevel_menu_page() {
if (wu_request('id')) {
$this->edit = true;
} // end if;
return add_menu_page(
$this->get_title(),
$this->get_menu_label(),
$this->get_capability(),
$this->id,
array($this, 'display'),
$this->menu_icon,
$this->position
);
} // end add_toplevel_menu_page;
/**
* Adds sub-pages.
*
* @since 1.8.2
* @return string Page hook generated by WordPress.
*/
public function add_submenu_page() {
if (wu_request('id')) {
$this->edit = true;
} // end if;
return add_submenu_page(
$this->parent,
$this->get_title(),
$this->get_menu_label(),
$this->get_capability(),
$this->id,
array($this, 'display')
);
} // end add_submenu_page;
/**
* Adds WP Ultimo branding to this page, if that's the case.
*
* @since 2.0.0
* @return void
*/
public function add_branding() {
if (apply_filters('wp_ultimo_remove_branding', false) === false) {
add_action('in_admin_header', array($this, 'brand_header'));
add_action('wu_header_right', array($this, 'add_container_toggle'));
add_action('in_admin_footer', array($this, 'brand_footer'));
add_filter('admin_footer_text', '__return_empty_string', 1000);
add_filter('update_footer', '__return_empty_string', 1000);
} // end if;
} // end add_branding;
/**
* Adds the Jumper trigger to the admin top pages.
*
* @since 2.0.0
* @return void
*/
public function add_container_toggle() {
wu_get_template('ui/container-toggle', array(
'page' => $this,
));
} // end add_container_toggle;
/**
* Adds the WP Ultimo branding header.
*
* @since 2.0.0
* @return void
*/
public function brand_header() {
wu_get_template('ui/branding/header', array(
'page' => $this,
));
} // end brand_header;
/**
* Adds the WP Ultimo branding footer.
*
* @since 2.0.0
* @return void
*/
public function brand_footer() {
wu_get_template('ui/branding/footer', array(
'page' => $this,
));
} // end brand_footer;
/**
* Injects our admin classes to the admin body classes.
*
* @since 2.0.0
* @return void
*/
public function add_admin_body_classes() {
add_action('admin_body_class', function($classes) {
if ($this->hide_admin_notices) {
$classes .= ' wu-hide-admin-notices';
} // end if;
if ($this->fold_menu) {
$classes .= ' folded';
} // end if;
if ($this->remove_frame) {
$classes .= ' wu-remove-frame folded';
} // end if;
if (is_network_admin()) {
$classes .= ' wu-network-admin';
} // end if;
return "$classes wu-page-{$this->id} wu-styling hover:wu-styling first:wu-styling odd:wu-styling";
});
} // end add_admin_body_classes;
/**
* Register the default hooks.
*
* @todo: this does not need to run on every page.
*
* @since 1.8.2
* @return void
*/
final public function enqueue_default_hooks() {
if ($this->page_hook) {
add_action("load-$this->page_hook", array($this, 'install_hooks'));
add_action("load-$this->page_hook", array($this, 'page_loaded'));
add_action("load-$this->page_hook", array($this, 'hooks'));
add_action("load-$this->page_hook", array($this, 'register_scripts'), 10);
add_action("load-$this->page_hook", array($this, 'screen_options'), 10);
add_action("load-$this->page_hook", array($this, 'register_widgets'), 20);
add_action("load-$this->page_hook", array($this, 'add_admin_body_classes'), 20);
/*
* Add the page to WP Ultimo branding (aka top-bar and footer)
*/
if (is_network_admin()) {
add_action("load-$this->page_hook", array($this, 'add_branding'));
} // end if;
/**
* Allow plugin developers to add additional hooks
*
* @since 1.8.2
* @param string
*/
do_action('wu_enqueue_extra_hooks', $this->page_hook);
} // end if;
} // end enqueue_default_hooks;
/**
* Returns an array with the title links.
*
* @since 2.0.0
* @return array
*/
public function get_title_links() {
if (wu_get_documentation_url($this->get_id(), false)) {
$this->action_links[] = array(
'url' => wu_get_documentation_url($this->get_id()),
'label' => __('Documentation'),
'icon' => 'wu-open-book',
);
} // end if;
/**
* Allow plugin developers, and ourselves, to add action links to our edit pages
*
* @since 1.8.2
* @param WU_Page_Edit $this This instance
* @return array
*/
return apply_filters('wu_page_get_title_links', $this->action_links, $this);
} // end get_title_links;
/**
* Allows child classes to register their own title links.
*
* @since 2.0.0
* @return array
*/
public function action_links() {
return array();
} // end action_links;
/**
* Allow child classes to add further initializations.
*
* @since 1.8.2
* @return void
*/
public function init() {} // end init;
/**
* Allow child classes to add further initializations, but only after the page is loaded.
*
* @since 1.8.2
* @return void
*/
public function page_loaded() {} // end page_loaded;
/**
* Allow child classes to add hooks to be run once the page is loaded.
*
* @see https://codex.wordpress.org/Plugin_API/Action_Reference/load-(page)
* @since 1.8.2
* @return void
*/
public function hooks() {} // end hooks;
/**
* Allow child classes to add screen options; Useful for pages that have list tables.
*
* @since 1.8.2
* @return void
*/
public function screen_options() {} // end screen_options;
/**
* Allow child classes to register scripts and styles that can be loaded on the output function, for example.
*
* @since 1.8.2
* @return void
*/
public function register_scripts() {} // end register_scripts;
/**
* Allow child classes to register widgets, if they need them.
*
* @since 1.8.2
* @return void
*/
public function register_widgets() {} // end register_widgets;
/**
* Allow child classes to register forms, if they need them.
*
* @since 2.0.0
* @return void
*/
public function register_forms() {} // end register_forms;
/**
* Returns the title of the page. Must be declared on the child classes.
*
* @since 2.0.0
* @return string Title of the page.
*/
abstract public function get_title();
/**
* Returns the title of menu for this page. Must be declared on the child classes.
*
* @since 2.0.0
* @return string Menu label of the page.
*/
abstract public function get_menu_title();
/**
* Allows admins to rename the sub-menu (first item) for a top-level page.
*
* @since 2.0.0
* @return string False to use the title menu or string with sub-menu title.
*/
public function get_submenu_title() {
return false;
} // end get_submenu_title;
/**
* Every child class should implement the output method to display the contents of the page.
*
* @since 1.8.2
* @return void
*/
abstract public function output(); // end output;
} // end class Base_Admin_Page;

View File

@ -0,0 +1,478 @@
<?php
/**
* Base customer facing admin page class.
*
* @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\Admin_Pages\Base_Admin_Page;
/**
* Abstract class that adds customizability to customer facing pages.
*/
abstract class Base_Customer_Facing_Admin_Page extends Base_Admin_Page {
/**
* @var bool
*/
protected $edit;
/**
* The capability required to be able to activate the customize mode.
*
* @since 2.0.0
* @var string
*/
protected $edit_capability = 'manage_network';
/**
* The current editing status of this page.
*
* @since 2.0.0
* @var boolean
*/
protected $editing = false;
/**
* Holds the original parameters before we change them.
*
* @since 2.0.0
* @var array
*/
protected $original_parameters = array();
/**
* If this customer facing page has menu settings.
*
* @since 2.0.9
* @var boolean
*/
protected $menu_settings = true;
/**
* Allow child classes to add further initializations.
*
* @since 1.8.2
* @return void
*/
public function init() {
$this->change_parameters();
parent::init();
$this->editing = wu_request('customize');
add_action('wu_enqueue_extra_hooks', array($this, 'additional_hooks'));
add_action('updated_user_meta', array($this, 'save_settings'), 10, 4);
wu_register_form("edit_admin_page_$this->id", array(
'render' => array($this, 'render_edit_page'),
'handler' => array($this, 'handle_edit_page'),
'capability' => 'exist',
));
$this->register_page_settings();
} // end init;
/**
* Saves the original parameters and change them with the settings saved.
*
* @since 2.0.0
* @return void
*/
public function change_parameters() {
$this->original_parameters = array(
'title' => $this->get_title(),
'position' => $this->position,
'menu_icon' => $this->menu_icon,
);
$new_parameters = $this->get_page_settings();
$this->title = wu_get_isset($new_parameters, 'title', $this->original_parameters['title']);
$this->menu_title = wu_get_isset($new_parameters, 'title', $this->original_parameters['title']);
$this->position = wu_get_isset($new_parameters, 'position', $this->original_parameters['position']);
$this->menu_icon = str_replace('dashicons-before', '', (string) wu_get_isset($new_parameters, 'menu_icon', $this->original_parameters['menu_icon'] ?? ''));
} // end change_parameters;
/**
* Renders the edit page form.
*
* @since 2.0.0
* @return void
*/
public function render_edit_page() {
$settings = $this->get_page_settings();
$fields = array();
$fields['title'] = array(
'type' => 'text',
'title' => __('Page & Menu Title', 'wp-ultimo'),
'value' => wu_get_isset($settings, 'title', ''),
'tooltip' => '',
);
if ($this->menu_settings) {
$fields['position'] = array(
'type' => 'number',
'title' => __('Menu', 'wp-ultimo'),
'value' => wu_get_isset($settings, 'position', ''),
'tooltip' => '',
);
$fields['menu_icon'] = array(
'type' => 'dashicon',
'title' => __('Menu Icon', 'wp-ultimo'),
'value' => wu_get_isset($settings, 'menu_icon', ''),
'tooltip' => '',
);
} // end if;
$fields['save_line'] = array(
'type' => 'group',
'classes' => 'wu-justify-between',
'wrapper_classes' => 'wu-bg-gray-100',
'fields' => array(
'reset' => array(
'type' => 'submit',
'title' => __('Reset Settings', 'wp-ultimo'),
'value' => 'edit',
'classes' => 'button',
'wrapper_classes' => 'wu-mb-0',
),
'submit' => array(
'type' => 'submit',
'title' => __('Save Changes', 'wp-ultimo'),
'value' => 'edit',
'classes' => 'button button-primary',
'wrapper_classes' => 'wu-mb-0',
),
),
);
$fields = apply_filters("wu_customer_facing_page_{$this->id}_fields", $fields);
$form = new \WP_Ultimo\UI\Form('edit_page', $fields, array(
'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' => array(
'data-wu-app' => "{$this->id}_page_customize",
'data-state' => wu_convert_to_state(),
),
));
echo '<div class="wu-styling">';
$form->render();
echo '</div>';
} // end render_edit_page;
/**
* Handles the edit page form and saved changes.
*
* @since 2.0.0
* @return void
*/
public function handle_edit_page() {
$settings_to_save = wu_request('submit') !== 'restore' ? $_POST : array(); // don't worry, this gets cleaned later on.
$this->save_page_settings($settings_to_save);
wp_send_json_success(array(
'redirect_url' => add_query_arg('updated', 1, $_SERVER['HTTP_REFERER']),
));
} // end handle_edit_page;
/**
* Generates a unique id for each page based on the class name.
*
* @since 2.0.0
* @return string
*/
public function get_page_unique_id() {
$class_name_array = explode('\\', static::class);
$class_name = array_pop($class_name_array);
return wu_replace_dashes(strtolower($class_name));
} // end get_page_unique_id;
/**
* Grabs the original page parameters.
*
* @since 2.0.0
* @return array
*/
public function get_defaults() {
return $this->original_parameters;
} // end get_defaults;
/**
* Register the default setting on the core section.
*
* @since 2.0.0
* @return void
*/
public function register_page_settings() {
wu_register_settings_field('core', $this->get_page_unique_id() . '_settings', array(
'raw' => true,
));
} // end register_page_settings;
/**
* Get the page settings saved.
*
* @since 2.0.0
* @return array
*/
public function get_page_settings() {
$atts = wu_get_setting($this->get_page_unique_id() . '_settings', array());
return wp_parse_args($atts, $this->get_defaults());
} // end get_page_settings;
/**
* Saves the page settings.
*
* @since 2.0.0
*
* @param array $settings List of page settings.
* @return boolean
*/
public function save_page_settings($settings) {
$atts = shortcode_atts($this->get_defaults(), $settings); // Use shortcode atts to remove unauthorized params.
return wu_save_setting($this->get_page_unique_id() . '_settings', $atts);
} // end save_page_settings;
/**
* Adds additional hooks using the right hook on the page lifecycle.
*
* @since 2.0.0
* @return void
*/
public function additional_hooks() {
add_action("load-$this->page_hook", array($this, 'register_additional_scripts'));
add_action("load-$this->page_hook", array($this, 'add_additional_body_classes'));
add_action("load-$this->page_hook", array($this, 'additional_on_page_load'));
} // end additional_hooks;
/**
* Registers additional hooks for the page load.
*
* @since 2.0.0
* @return void
*/
public function additional_on_page_load() {
add_filter('wu_element_display_super_admin_notice', array($this, 'is_edit_mode'));
add_action("get_user_option_meta-box-order_{$this->page_hook}", array($this, 'get_settings'), 10, 3);
add_action("get_user_option_screen_layout_{$this->page_hook}", array($this, 'get_settings'), 10, 3);
/**
* 'Hack-y' solution for the customer facing title problem... but good enough for now.
*
* @todo review when possible.
*/
add_filter('wp_ultimo_render_vars', function($vars) {
$vars['page_title'] = $this->title;
return $vars;
}, 15);
} // end additional_on_page_load;
/**
* Adds additional body classes for styling control purposes.
*
* @since 2.0.0
* @return void
*/
public function add_additional_body_classes() {
add_action('admin_body_class', function($classes) {
$classes .= $this->is_edit_mode() ? ' wu-customize-admin-screen' : '';
return $classes;
});
} // end add_additional_body_classes;
/**
* Registers and enqueues additional scripts and styles required.
*
* @since 2.0.0
* @return void
*/
public function register_additional_scripts() {
\WP_Ultimo\Scripts::get_instance()->register_style('wu-admin-screen', wu_get_asset('admin-screen.css', 'css'));
wp_enqueue_style('wu-admin-screen');
if ($this->is_edit_mode()) {
wp_enqueue_script('dashboard');
} // end if;
if (current_user_can($this->edit_capability)) {
\WP_Ultimo\Scripts::get_instance()->register_script('wu-admin-screen', wu_get_asset('admin-screen.js', 'js'), array('jquery', 'wu-fonticonpicker'));
wp_localize_script('wu-admin-screen', 'wu_admin_screen', array(
'page_customize_link' => wu_get_form_url("edit_admin_page_$this->id"),
'customize_link' => add_query_arg('customize', 1),
'close_link' => remove_query_arg('customize'),
'i18n' => array(
'page_customize_label' => __('Customize Page', 'wp-ultimo'),
'customize_label' => __('Customize Elements', 'wp-ultimo'),
'close_label' => __('Exit Customize Mode', 'wp-ultimo'),
),
));
wp_enqueue_script('wu-admin-screen');
} // end if;
} // end register_additional_scripts;
/**
* Filters the order and columns of the widgets to return a globally saved value.
*
* @since 2.0.0
*
* @param array $result Original value of the settings being changed.
* @param string $option The name of the option/setting being fetched.
* @param int $user The user ID.
* @return array
*/
public function get_settings($result, $option, $user) {
$option = wu_replace_dashes($option);
$saved = wu_get_setting($option);
return empty($saved) ? $result : $saved;
} // end get_settings;
/**
* Save the settings globally for columns and order of the widgets.
*
* @since 2.0.0
*
* @param int $meta_id The id of the user meta being saved.
* @param int $user_id The user id.
* @param string $meta_key The name of the option/setting being saved.
* @param mixed $_meta_value The original saved value.
* @return void
*/
public function save_settings($meta_id, $user_id, $meta_key, $_meta_value) {
if (wu_request('action') !== 'meta-box-order') {
return;
} // end if;
$is_this_page = strpos((string) wu_request('page'), $this->id) !== false;
if (!$is_this_page) {
return;
} // end if;
if (!user_can($user_id, $this->edit_capability)) {
return;
} // end if;
$meta_key = wu_replace_dashes($meta_key);
wu_save_setting($meta_key, $_meta_value);
} // end save_settings;
/**
* Get the value of editing.
*
* @since 2.0.0
* @return boolean
*/
public function is_edit_mode() {
return $this->editing && current_user_can($this->edit_capability);
} // end is_edit_mode;
/**
* Adds top-level admin page.
*
* @since 1.8.2
* @return string Page hook generated by WordPress.
*/
public function add_toplevel_menu_page() {
if (wu_request('id')) {
$this->edit = true;
} // end if;
return add_menu_page(
$this->title,
$this->title . '&nbsp;' . $this->get_badge(),
$this->get_capability(),
$this->id,
array($this, 'display'),
$this->menu_icon,
$this->position
);
} // end add_toplevel_menu_page;
} // end class Base_Customer_Facing_Admin_Page;

View File

@ -0,0 +1,509 @@
<?php
/**
* WP Ultimo Broadcast 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\Models\Broadcast;
/**
* WP Ultimo Broadcast Edit/Add New Admin Page.
*/
class Broadcast_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-broadcast';
/**
* 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 = 'broadcast';
/**
* 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-broadcasts';
/**
* 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;
/**
* 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 = array(
'network_admin_menu' => 'wu_edit_broadcasts',
);
/**
* Allow child classes to register widgets, if they need them.
*
* @since 1.8.2
* @return void
*/
public function register_widgets() {
parent::register_widgets();
$this->add_list_table_widget('events', array(
'title' => __('Events', 'wp-ultimo'),
'table' => new \WP_Ultimo\List_Tables\Inside_Events_List_Table(),
'query_filter' => array($this, 'events_query_filter'),
));
$this->add_save_widget('save', array(
'html_attr' => array(
'data-wu-app' => 'save_broadcast',
'data-state' => wu_convert_to_state(array(
'type' => $this->get_object()->get_type(),
)),
),
'fields' => array(
'type' => array(
'type' => 'select',
'title' => __('Broadcast Type', 'wp-ultimo'),
'placeholder' => __('Type', 'wp-ultimo'),
'desc' => __('Broadcast type cannot be edited.', 'wp-ultimo'),
'options' => array(
'broadcast_email' => __('Email', 'wp-ultimo'),
'broadcast_notice' => __('Admin Notice', 'wp-ultimo'),
),
'value' => $this->get_object()->get_type(),
'tooltip' => '',
'html_attr' => array(
'disabled' => 'disabled',
'name' => ''
)
),
'notice_type' => array(
'type' => 'select',
'title' => __('Broadcast Status', 'wp-ultimo'),
'placeholder' => __('Status', 'wp-ultimo'),
'desc' => __('This option determines the color of the admin notice.', 'wp-ultimo'),
'options' => array(
'info' => __('Info (blue)', 'wp-ultimo'),
'success' => __('Success (green)', 'wp-ultimo'),
'warning' => __('Warning (yellow)', 'wp-ultimo'),
'error' => __('Error (red)', 'wp-ultimo'),
),
'value' => $this->get_object()->get_notice_type(),
'tooltip' => '',
'wrapper_html_attr' => array(
'v-if' => 'type === "broadcast_notice"',
'v-cloak' => 1,
)
),
),
));
add_meta_box('wp-ultimo-broadcast-customer-targets', __('Customer Targets', 'wp-ultimo'), array($this, 'output_default_widget_customer_targets'), get_current_screen()->id, 'side');
add_meta_box('wp-ultimo-broadcast-product-targets', __('Product Targets', 'wp-ultimo'), array($this, 'output_default_widget_product_targets'), get_current_screen()->id, 'side');
} // end register_widgets;
/**
* Outputs the markup for the customer targets widget.
*
* @since 2.0.0
* @return void
*/
public function output_default_widget_customer_targets() {
$object = $this->get_object();
$all_targets = $object->get_message_targets();
$targets = array();
$customer_targets = wu_get_isset($all_targets, 'customers', '');
if ($customer_targets) {
if (is_array($all_targets['customers'])) {
$all_targets['customers'] = $all_targets['customers'][0];
} // end if;
$targets = explode(',', (string) $all_targets['customers']);
} // end if;
$targets_count = count($targets);
$html = '<div class="wu-bg-gray-100 wu--mt-3 wu--mb-6 wu--mx-3">
<ul class="wu-widget-list">
<li class="wu-p-2 wu-m-0 wu-border-t wu-border-l-0 wu-border-r-0 wu-border-b-0 wu-border-gray-200 wu-border-solid">
<div class="wu-p-2 wu-mr-1 wu-flex wu-rounded wu-items-center wu-border wu-border-solid wu-border-gray-300 wu-bg-white wu-relative wu-overflow-hidden">';
switch ($targets) {
case $targets_count < 0:
$not_found = __('No customer found', 'wp-ultimo');
$html .= "<span class='dashicons dashicons-wu-block wu-text-gray-600 wu-px-1 wu-pr-3'>&nbsp;</span>
<div class=''>
<span class='wu-block wu-py-3 wu-text-gray-600 wu-text-2xs wu-font-bold wu-uppercase'>{$not_found}</span>
</div>";
break;
case $targets_count === 1:
$customer = wu_get_customer($targets[0]);
$url_atts = array(
'id' => $customer->get_id(),
);
$customer_link = wu_network_admin_url('wp-ultimo-edit-customer', $url_atts);
$avatar = get_avatar($customer->get_user_id(), 32, 'identicon', '', array(
'force_display' => true,
'class' => 'wu-rounded-full wu-border-solid wu-border-1 wu-border-white hover:wu-border-gray-400',
));
$display_name = $customer->get_display_name();
$id = $customer->get_id();
$email = $customer->get_email_address();
$html .= "<a href='{$customer_link}' class='wu-p-1 wu-flex wu-flex-grow wu-rounded wu-items-center wu-no-underline'>
{$avatar}
<div class='wu-pl-2'>
<strong class='wu-block'>{$display_name} <small class='wu-font-normal'>(#{$id})</small></strong>
<small>{$email}</small>
</div>
</a>";
break;
case $targets_count > 1:
foreach ($targets as $key => $target) {
$customer = wu_get_customer($target);
$tooltip_name = $customer->get_display_name();
$email = $customer->get_email_address();
$avatar = get_avatar($email, 32, 'identicon', '', array(
'class' => 'wu-rounded-full wu-border-solid wu-border-1 wu-border-white hover:wu-border-gray-400',
));
$url_atts = array(
'id' => $customer->get_id(),
);
$customer_link = wu_network_admin_url('wp-ultimo-edit-customer', $url_atts);
$html .= "<div class='wu-flex wu--mr-4'><a role='tooltip' aria-label='{$tooltip_name}' href='{$customer_link}'>{$avatar}</a></div>";
} // end foreach;
if ($targets_count < 7) {
$modal_atts = array(
'action' => 'wu_modal_targets_display',
'object_id' => $object->get_id(),
'width' => '400',
'height' => '360',
'target_type' => 'customers',
);
$html .= sprintf('<div class="wu-inline-block wu--mr-4">
<a href="%s" title="%s" class="wubox wu-no-underline"><span class="wu-ml-6 wu-uppercase wu-text-xs wu-text-gray-600 wu-font-bold"> %s %s</span></a>
</div>', wu_get_form_url('view_broadcast_targets', $modal_atts), __('Targets', 'wp-ultimo'), $targets_count, __('Targets', 'wp-ultimo'));
} else {
$count = $targets_count - 6;
$modal_atts = array(
'action' => 'wu_modal_targets_display',
'object_id' => $object->get_id(),
'width' => '400',
'height' => '360',
'target_type' => 'customers',
);
$html .= sprintf('<div class="wu-inline-block wu-ml-4">
<a href="%s" title="%s" class="wubox wu-no-underline"><span class="wu-pl-2 wu-uppercase wu-text-xs wu-font-bold"> %s %s</span></a>
</div>', wu_get_form_url('view_broadcast_targets', $modal_atts), __('Targets', 'wp-ultimo'), $targets_count, __('Targets', 'wp-ultimo'));
} // end if;
break;
} // end switch;
$html .= '</div></li></ul></div>';
echo $html;
} // end output_default_widget_customer_targets;
/**
* Outputs the markup for the products targets widget.
*
* @since 2.0.0
* @return void
*/
public function output_default_widget_product_targets() {
$object = $this->get_object();
$targets = wu_get_broadcast_targets($object->get_id(), 'products');
$product_targets = array();
if ($targets) {
foreach ($targets as $key => $value) {
$product = wu_get_product($value);
if ($product) {
$modal_atts = array(
'action' => 'wu_modal_product_targets_display',
'product_id' => $product->get_id(),
'width' => '400',
'height' => '360',
);
$link = wu_get_form_url('view_broadcast_targets', $modal_atts);
$image = $product->get_featured_image('thumbnail');
$image = $image ? sprintf('<img class="wu-w-8 wu-h-8 wu-rounded-full" src="%s">', esc_attr($image)) : '<span class="dashicons-wu-image"></span>';
$plan_customers = wu_get_membership_customers($product->get_id());
$customer_count = (int) 0;
if ($plan_customers) {
$customer_count = count($plan_customers);
} // end if;
// translators: %s is the number of customers.
$description = sprintf(__('%s customer(s) targeted.', 'wp-ultimo'), $customer_count);
$product_targets[$key] = array(
'link' => $link,
'avatar' => $image,
'display_name' => $product->get_name(),
'id' => $product->get_id(),
'description' => $description
);
} // end if;
} // end foreach;
} // end if;
$args = array(
'targets' => $product_targets,
'loading_text' => __('Loading...', 'wp-ultimo'),
'wrapper_class' => 'wu-bg-gray-100 wu--mt-3 wu--mb-6 wu--mx-3',
'modal_class' => 'wubox',
);
wu_get_template('broadcast/widget-targets', $args);
} // end output_default_widget_product_targets;
/**
* Returns the title of the page.
*
* @since 2.0.0
* @return string Title of the page.
*/
public function get_title() {
return $this->edit ? __('Edit Broadcast', 'wp-ultimo') : __('Add new Broadcast', 'wp-ultimo');
} // end get_title;
/**
* 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 Broadcast', 'wp-ultimo');
} // end get_menu_title;
/**
* Returns the action links for that page.
*
* @since 1.8.2
* @return array
*/
public function action_links() {
return array();
} // end action_links;
/**
* Returns the labels to be used on the admin page.
*
* @since 2.0.0
* @return array
*/
public function get_labels() {
return array(
'edit_label' => __('Edit Broadcast', 'wp-ultimo'),
'add_new_label' => __('Add new Broadcast', 'wp-ultimo'),
'updated_message' => __('Broadcast updated with success!', 'wp-ultimo'),
'title_placeholder' => __('Enter Broadcast Title', 'wp-ultimo'),
'title_description' => __('This title is used on the message itself, and in the case of a broadcast email, it will be used as the subject.', 'wp-ultimo'),
'save_button_label' => __('Save Broadcast', 'wp-ultimo'),
'save_description' => '',
'delete_button_label' => __('Delete Broadcast', 'wp-ultimo'),
'delete_description' => __('Be careful. This action is irreversible.', 'wp-ultimo'),
);
} // end get_labels;
/**
* 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 query_filter($args) {
$extra_args = array(
'object_type' => 'broadcast',
'object_id' => absint($this->get_object()->get_id()),
);
return array_merge($args, $extra_args);
} // end query_filter;
/**
* Returns the object being edit at the moment.
*
* @since 2.0.0
* @return \WP_Ultimo\Models\Broadcast
*/
public function get_object() {
if (isset($_GET['id'])) {
$query = new \WP_Ultimo\Database\Broadcasts\Broadcast_Query;
$item = $query->get_item_by('id', $_GET['id']);
if (!$item) {
wp_redirect(wu_network_admin_url('wp-ultimo-broadcasts'));
exit;
} // end if;
return $item;
} // end if;
return new Broadcast;
} // end get_object;
/**
* Broadcasts have titles.
*
* @since 2.0.0
*/
public function has_title(): bool {
return true;
} // end has_title;
/**
* Wether or not this pages should have an editor field.
*
* @since 2.0.0
*/
public function has_editor(): bool {
return true;
} // end has_editor;
/**
* 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 = array(
'object_type' => 'broadcast',
'object_id' => absint($this->get_object()->get_id()),
);
return array_merge($args, $extra_args);
} // end events_query_filter;
} // end class Broadcast_Edit_Admin_Page;

View File

@ -0,0 +1,570 @@
<?php
/**
* WP Ultimo Broadcast 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\Managers\Broadcast_Manager;
/**
* WP Ultimo Broadcast Admin Page.
*/
class Broadcast_List_Admin_Page extends List_Admin_Page {
/**
* Holds the ID for this page, this is also used as the page slug.
*
* @var string
*/
protected $id = 'wp-ultimo-broadcasts';
/**
* Is this a top-level menu or a submenu?
*
* @since 1.8.2
* @var string
*/
protected $type = 'submenu';
/**
* 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;
/**
* 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 = array(
'network_admin_menu' => 'wu_read_broadcasts',
);
/**
* Register ajax forms that we use for send broadcasts.
*
* @since 2.0.0
* @return void
*/
public function register_forms() {
/*
* Add new broadcast notice.
*/
wu_register_form('add_new_broadcast_message', array(
'render' => array($this, 'render_add_new_broadcast_modal'),
'handler' => array($this, 'handle_add_new_broadcast_modal'),
'capability' => 'wu_add_broadcasts',
));
/**
* Ajax to render the broadcast targets modal.
*/
add_action('wu_ajax_wu_modal_targets_display', array($this, 'display_targets_modal'));
/**
* Ajax to render the targets modal with customers from a specific membership.
*/
add_action('wu_ajax_wu_modal_product_targets_display', array($this, 'display_product_targets_modal'));
} // end register_forms;
/**
* Enqueue the necessary scripts.
*
* @since 2.0.0
* @return void
*/
public function register_scripts() {
parent::register_scripts();
wp_enqueue_editor();
} // end register_scripts;
/**
* Renders the broadcast targets modal, when requested.
*
* @since 2.0.0
* @return void
*/
public function display_targets_modal() {
$broadcast_id = wu_request('object_id');
$object = \WP_Ultimo\Models\Broadcast::get_by_id($broadcast_id);
$target_type = wu_request('target_type');
$targets = wu_get_broadcast_targets($object->get_id(), $target_type);
$display_targets = array();
if ($targets) {
if ($target_type === 'customers') {
foreach ($targets as $key => $value) {
$customer = wu_get_customer($value);
$url_atts = array(
'id' => $customer->get_id(),
);
$link = wu_network_admin_url('wp-ultimo-edit-customer', $url_atts);
$avatar = get_avatar($customer->get_user_id(), 48, 'identicon', '', array(
'force_display' => true,
'class' => 'wu-rounded-full',
));
$display_targets[$key] = array(
'link' => $link,
'avatar' => $avatar,
'display_name' => $customer->get_display_name(),
'id' => $customer->get_id(),
'description' => $customer->get_email_address(),
);
} // end foreach;
} // end if;
if ($target_type === 'products') {
foreach ($targets as $key => $value) {
$product = wu_get_product($value);
$url_atts = array(
'id' => $product->get_id(),
);
$link = wu_network_admin_url('wp-ultimo-edit-product', $url_atts);
$avatar = $product->get_featured_image('thumbnail');
if ($avatar) {
$avatar = sprintf('<img class="wu-w-8 wu-h-8 wu-bg-gray-200 wu-rounded-full wu-text-gray-600 wu-flex wu-items-center wu-justify-center" src="%s">', esc_attr($avatar));
} else {
$avatar = '<span class="dashicons-wu-image wu-p-1 wu-rounded-full"></span>';
} // end if;
$plan_customers = wu_get_membership_customers($product->get_id());
$customer_count = (int) 0;
if ($plan_customers) {
$customer_count = count($plan_customers);
} // end if;
// translators: %s is the number of customers.
$description = sprintf(__('%s customer(s) targeted.', 'wp-ultimo'), $customer_count);
$display_targets[$key] = array(
'link' => $link,
'avatar' => $avatar,
'display_name' => $product->get_name(),
'id' => $product->get_id(),
'description' => $description,
);
} // end foreach;
} // end if;
} // end if;
$args = array(
'targets' => $display_targets,
'wrapper_class' => 'wu-bg-gray-100 wu--mt-3 wu--mb-6 wu-max-h-2',
'modal_class' => '',
);
wu_get_template('broadcast/widget-targets', $args);
exit;
} // end display_targets_modal;
/**
* Renders the broadcast targets modal, when requested.
*
* @since 2.0.0
* @return void
*/
public function display_product_targets_modal() {
$product_id = wu_request('product_id');
$customers = wu_get_membership_customers($product_id);
$display_targets = array();
if ($customers) {
foreach ($customers as $key => $value) {
$customer = wu_get_customer($value);
$url_atts = array(
'id' => $customer->get_id(),
);
$link = wu_network_admin_url('wp-ultimo-edit-customer', $url_atts);
$avatar = get_avatar($customer->get_user_id(), 48, 'identicon', '', array(
'force_display' => true,
'class' => 'wu-rounded-full',
));
$display_targets[$key] = array(
'link' => $link,
'avatar' => $avatar,
'display_name' => $customer->get_display_name(),
'id' => $customer->get_id(),
'description' => $customer->get_email_address(),
);
} // end foreach;
} // end if;
$args = array(
'targets' => $display_targets,
'wrapper_class' => 'wu-bg-gray-100 wu--mt-3 wu--mb-6 wu-max-h-2',
'modal_class' => '',
);
wu_get_template('broadcast/widget-targets', $args);
exit;
} // end display_product_targets_modal;
/**
* Renders the add new broadcast message modal.
*
* @since 2.0.0
* @return void
*/
public function render_add_new_broadcast_modal() {
$fields = array(
'type' => array(
'type' => 'select-icon',
'title' => __('Broadcast Type', 'wp-ultimo'),
'desc' => __('Select the type of message you want to send.', 'wp-ultimo'),
'placeholder' => '',
'tooltip' => '',
'value' => '',
'classes' => 'wu-w-1/2',
'html_attr' => array(
'v-model' => 'type',
),
'wrapper_html_attr' => array(
'v-show' => 'step === 1',
),
'options' => array(
'broadcast_notice' => array(
'title' => __('Message', 'wp-ultimo'),
'tooltip' => __('Display a message on your customers\' dashboard.', 'wp-ultimo'),
'icon' => 'dashicons-before dashicons-excerpt-view',
),
'broadcast_email' => array(
'title' => __('Email', 'wp-ultimo'),
'tooltip' => __('Send an email to your customers.', 'wp-ultimo'),
'icon' => 'dashicons-before dashicons-email',
),
),
),
'step_note' => array(
'type' => 'note',
'desc' => sprintf('<a href="#" class="wu-no-underline wu-mt-1 wu-uppercase wu-text-2xs wu-font-semibold wu-text-gray-600" v-show="step === 2" v-on:click.prevent="step = 1">%s</a>', __('&larr; Back to Type Selection', 'wp-ultimo')),
'wrapper_html_attr' => array(
'v-show' => 'step === 2',
),
),
'target_customers' => array(
'type' => 'model',
'title' => __('Target Customers', 'wp-ultimo'),
'desc' => __('This broadcast will be sent to the user or users that are selected here. You can select more than one.', 'wp-ultimo'),
'placeholder' => __('Search a customer...', 'wp-ultimo'),
'min' => 1,
'html_attr' => array(
'v-model' => 'target_customers',
'data-model' => 'customer',
'data-value-field' => 'id',
'data-label-field' => 'display_name',
'data-search-field' => 'display_name',
'data-max-items' => 10000,
),
'wrapper_html_attr' => array(
'v-show' => 'step === 2',
),
),
'target_products' => array(
'type' => 'model',
'title' => __('Target Product', 'wp-ultimo'),
'desc' => __('This broadcast will be sent to the users that have this product. You can select more than one.', 'wp-ultimo'),
'placeholder' => __('Search for a product..', 'wp-ultimo'),
'html_attr' => array(
'v-model' => 'target_products',
'data-model' => 'product',
'data-value-field' => 'id',
'data-label-field' => 'name',
'data-search-field' => 'name',
'data-max-items' => 99,
),
'wrapper_html_attr' => array(
'v-show' => 'step === 2',
),
),
'notice_type' => array(
'title' => __('Message Type', 'wp-ultimo'),
'desc' => __('The color of the notice is based on the type.', 'wp-ultimo'),
'type' => 'select',
'default' => 'success',
'options' => array(
'success' => __('Success (green)', 'wp-ultimo'),
'info' => __('Info (blue)', 'wp-ultimo'),
'warning' => __('Warning (orange)', 'wp-ultimo'),
'error' => __('Error (red)', 'wp-ultimo'),
),
'wrapper_html_attr' => array(
'v-show' => "step === 2 && require('type', 'broadcast_notice')",
'v-cloak' => 1
),
),
'step_note_2' => array(
'type' => 'note',
'desc' => sprintf('<a href="#" class="wu-no-underline wu-mt-1 wu-uppercase wu-text-2xs wu-font-semibold wu-text-gray-600" v-show="step === 3" v-on:click.prevent="step = 2">%s</a>', __('&larr; Back to Target Selection', 'wp-ultimo')),
'wrapper_html_attr' => array(
'v-show' => 'step === 3',
),
),
'subject' => array(
'type' => 'text',
'title' => __('Message Subject', 'wp-ultimo'),
'desc' => __('The title will appear above the main content in the notice or used as subject of the email.', 'wp-ultimo'),
'placeholder' => __('Enter a title for your broadcast.', 'wp-ultimo'),
'html_attr' => array(
'v-model' => 'subject',
),
'wrapper_html_attr' => array(
'v-show' => 'step === 3',
),
),
'content' => array(
'id' => 'content',
'title' => __('Content', 'wp-ultimo'),
'desc' => __('The main content of your broadcast.', 'wp-ultimo'),
'type' => 'wp-editor',
'settings' => array(
'tinymce' => array('toolbar1' => 'bold,italic,strikethrough,link,unlink,undo,redo,pastetext'),
),
'html_attr' => array(
'v-model' => 'content',
),
'wrapper_html_attr' => array(
'v-show' => 'step === 3',
),
),
'submit_button' => array(
'type' => 'submit',
'title' => __('Next Step &rarr;', 'wp-ultimo'),
'value' => 'save',
'classes' => 'button button-primary wu-w-full',
'wrapper_classes' => 'wu-items-end',
'wrapper_html_attr' => array(
'v-show' => 'step === 1',
),
'html_attr' => array(
'v-bind:disabled' => 'type === ""',
'v-on:click.prevent' => 'step = 2'
),
),
'submit_button_2' => array(
'type' => 'submit',
'title' => __('Next Step &rarr;', 'wp-ultimo'),
'value' => 'save',
'classes' => 'button button-primary wu-w-full',
'wrapper_classes' => 'wu-items-end',
'wrapper_html_attr' => array(
'v-show' => 'step === 2',
),
'html_attr' => array(
'v-bind:disabled' => 'target_customers === "" && target_products === ""', // phpcs:ignore
'v-on:click.prevent' => 'step = 3'
),
),
'submit_button_3' => array(
'type' => 'submit',
'title' => __('Send &rarr;', 'wp-ultimo'),
'value' => 'save',
'classes' => 'button button-primary wu-w-full',
'wrapper_classes' => 'wu-items-end',
'html_attr' => array(
'v-bind:disabled' => 'subject === ""',
),
'wrapper_html_attr' => array(
'v-show' => 'step === 3',
),
),
);
$form = new \WP_Ultimo\UI\Form('add_new_broadcast', $fields, array(
'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' => array(
'data-wu-app' => 'add_new_broadcast',
'data-state' => wu_convert_to_state(array(
'type' => 'broadcast_notice',
'content' => '',
'step' => 1,
'confirmed' => false,
'target_customers' => '',
'target_products' => '',
'subject' => '',
)),
),
));
$form->render();
} // end render_add_new_broadcast_modal;
/**
* Handles the add new broadcast modal.
*
* @since 2.0.0
* @return void
*/
public function handle_add_new_broadcast_modal() {
$broadcast = Broadcast_Manager::get_instance();
$broadcast->handle_broadcast();
} // end handle_add_new_broadcast_modal;
/**
* Allow child classes to register widgets, if they need them.
*
* @since 1.8.2
* @return void
*/
public function register_widgets() {} // end register_widgets;
/**
* Returns an array with the labels for the edit page.
*
* @since 1.8.2
* @return array
*/
public function get_labels() {
return array(
'deleted_message' => __('Broadcast removed successfully.', 'wp-ultimo'),
'search_label' => __('Search Broadcast', 'wp-ultimo'),
);
} // end get_labels;
/**
* Returns the title of the page.
*
* @since 2.0.0
* @return string Title of the page.
*/
public function get_title() {
return __('Broadcast', 'wp-ultimo');
} // end get_title;
/**
* 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 __('Broadcasts', 'wp-ultimo');
} // end get_menu_title;
/**
* Allows admins to rename the sub-menu (first item) for a top-level page.
*
* @since 2.0.0
* @return string False to use the title menu or string with sub-menu title.
*/
public function get_submenu_title() {
return __('Broadcasts', 'wp-ultimo');
} // end get_submenu_title;
/**
* Returns the action links for that page.
*
* @since 1.8.2
* @return array
*/
public function action_links() {
return array(
array(
'label' => __('Add Broadcast', 'wp-ultimo'),
'icon' => 'wu-circle-with-plus',
'classes' => 'wubox',
'url' => wu_get_form_url('add_new_broadcast_message'),
),
array(
'url' => wu_network_admin_url('wp-ultimo-emails'),
'label' => __('System Emails'),
'icon' => 'wu-mail',
),
);
} // end action_links;
/**
* Loads the list table for this particular page.
*
* @since 2.0.0
* @return \WP_Ultimo\List_Tables\Base_List_Table
*/
public function table() {
return new \WP_Ultimo\List_Tables\Broadcast_List_Table();
} // end table;
} // end class Broadcast_List_Admin_Page;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,289 @@
<?php
/**
* WP Ultimo Checkout Form 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\Models\Checkout_Form;
/**
* WP Ultimo Checkout Form Admin Page.
*/
class Checkout_Form_List_Admin_Page extends List_Admin_Page {
/**
* Holds the ID for this page, this is also used as the page slug.
*
* @var string
*/
protected $id = 'wp-ultimo-checkout-forms';
/**
* Is this a top-level menu or a submenu?
*
* @since 1.8.2
* @var string
*/
protected $type = 'submenu';
/**
* 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;
/**
* 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 = array(
'network_admin_menu' => 'wu_read_checkout_forms',
);
/**
* Register the list page tour.
*
* @since 2.0.0
* @return void
*/
public function register_widgets() {
\WP_Ultimo\UI\Tours::get_instance()->create_tour('checkout-form-list', array(
array(
'id' => 'checkout-form-list',
'title' => __('Checkout Forms', 'wp-ultimo'),
'text' => array(
__('Checkout Forms are an easy and flexible way to experiment with different approaches when trying to convert new customers.', 'wp-ultimo'),
),
),
array(
'id' => 'default-form',
'title' => __('Experiment!', 'wp-ultimo'),
'text' => array(
__('You can create as many checkout forms as you want, with different fields, products on offer, etc.', 'wp-ultimo'),
__('Planning on running some sort of promotion? Why not create a custom landing page with a tailor-maid checkout form to go with? The possibilities are endless.', 'wp-ultimo'),
),
'attachTo' => array(
'element' => '#wp-ultimo-wrap > h1 > a:first-child',
'on' => 'right',
),
),
));
} // end register_widgets;
/**
* Register ajax forms to handle adding new checkout forms.
*
* @since 2.0.0
* @return void
*/
public function register_forms() {
/*
* Add new Checkout Form
*/
wu_register_form('add_new_checkout_form', array(
'render' => array($this, 'render_add_new_checkout_form_modal'),
'handler' => array($this, 'handle_add_new_checkout_form_modal'),
'capability' => 'wu_edit_checkout_forms',
));
} // end register_forms;
/**
* Renders the add new customer modal.
*
* @since 2.0.0
* @return void
*/
public function render_add_new_checkout_form_modal() {
$fields = array(
'template' => array(
'type' => 'select-icon',
'title' => __('Checkout Form Template', 'wp-ultimo'),
'desc' => __('Select a starting point for a new Checkout Form.', 'wp-ultimo'),
'placeholder' => '',
'tooltip' => '',
'value' => '',
'classes' => 'wu-w-1/3',
'html_attr' => array(
'v-model' => 'template',
),
'options' => array(
'single-step' => array(
'title' => __('Single Step', 'wp-ultimo'),
'icon' => 'dashicons-before dashicons-list-view',
),
'multi-step' => array(
'title' => __('Multi-Step', 'wp-ultimo'),
'icon' => 'dashicons-before dashicons-excerpt-view',
),
'blank' => array(
'title' => __('Blank', 'wp-ultimo'),
'icon' => 'dashicons-before dashicons-admin-page',
),
),
),
'submit_button' => array(
'type' => 'submit',
'title' => __('Go to the Editor &rarr;', 'wp-ultimo'),
'value' => 'save',
'classes' => 'button button-primary wu-w-full',
'wrapper_classes' => 'wu-items-end',
),
);
$form = new \WP_Ultimo\UI\Form('add_new_checkout_form', $fields, array(
'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' => array(
'data-wu-app' => 'add_checkout_form_field',
'data-state' => json_encode(array(
'template' => 'single-step',
)),
),
));
$form->render();
} // end render_add_new_checkout_form_modal;
/**
* Handles creation of a new memberships.
*
* @since 2.0.0
* @return void
*/
public function handle_add_new_checkout_form_modal() {
$template = wu_request('template');
$checkout_form = new \WP_Ultimo\Models\Checkout_Form;
$checkout_form->use_template($template);
$checkout_form->set_name(__('Draft Checkout Form', 'wp-ultimo'));
$checkout_form->set_slug(uniqid());
$checkout_form->set_skip_validation(true);
$status = $checkout_form->save();
if (is_wp_error($status)) {
wp_send_json_error($status);
} else {
wp_send_json_success(array(
'redirect_url' => wu_network_admin_url('wp-ultimo-edit-checkout-form', array(
'id' => $checkout_form->get_id(),
))
));
} // end if;
} // end handle_add_new_checkout_form_modal;
/**
* Returns an array with the labels for the edit page.
*
* @since 1.8.2
* @return array
*/
public function get_labels() {
return array(
'deleted_message' => __('Checkout Form removed successfully.', 'wp-ultimo'),
'search_label' => __('Search Checkout Form', 'wp-ultimo'),
);
} // end get_labels;
/**
* Returns the title of the page.
*
* @since 2.0.0
* @return string Title of the page.
*/
public function get_title() {
return __('Checkout Forms', 'wp-ultimo');
} // end get_title;
/**
* 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 __('Checkout Forms', 'wp-ultimo');
} // end get_menu_title;
/**
* Allows admins to rename the sub-menu (first item) for a top-level page.
*
* @since 2.0.0
* @return string False to use the title menu or string with sub-menu title.
*/
public function get_submenu_title() {
return __('Checkout Forms', 'wp-ultimo');
} // end get_submenu_title;
/**
* Returns the action links for that page.
*
* @since 1.8.2
* @return array
*/
public function action_links() {
return array(
array(
'label' => __('Add Checkout Form'),
'icon' => 'wu-circle-with-plus',
'classes' => 'wubox',
'url' => wu_get_form_url('add_new_checkout_form'),
),
);
} // end action_links;
/**
* Loads the list table for this particular page.
*
* @since 2.0.0
* @return \WP_Ultimo\List_Tables\Base_List_Table
*/
public function table() {
return new \WP_Ultimo\List_Tables\Checkout_Form_List_Table();
} // end table;
} // end class Checkout_Form_List_Admin_Page;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,415 @@
<?php
/**
* WP Ultimo Dashboard Admin Page.
*
* @package WP_Ultimo
* @subpackage Admin_Pages
* @since 2.0.0
*/
namespace WP_Ultimo\Admin_Pages;
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* WP Ultimo Dashboard Admin Page.
*/
class Customer_List_Admin_Page extends List_Admin_Page {
/**
* Holds the ID for this page, this is also used as the page slug.
*
* @var string
*/
protected $id = 'wp-ultimo-customers';
/**
* Is this a top-level menu or a submenu?
*
* @since 1.8.2
* @var string
*/
protected $type = 'submenu';
/**
* 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;
/**
* Initializes the class
*
* @since 2.1
* @return void
*/
public function init() {
parent::init();
add_action('plugins_loaded', array($this, 'export_customers'));
} // end init;
/**
* Export customers in .csv file
*
* @since 2.1
* @return void
*/
public function export_customers() {
if (wu_request('wu_action') !== 'wu_export_customers') {
return;
} // end if;
if (!wp_verify_nonce(wu_request('nonce'), 'wu_export_customers')) {
wp_die(__('You do not have permissions to access this file.', 'wp-ultimo'));
} // end if;
$customer_data = array_map(function($customer) {
$memberships = $customer->get_memberships();
$membership_amount = count($memberships);
$memberships_ids = array_map(fn($membership) => $membership->get_id(), $memberships);
$billing_address = array_map(fn($field) => $field['value'], $customer->get_billing_address()->get_fields());
return array_merge(
array(
$customer->get_id(),
$customer->get_user_id(),
$customer->get_hash(),
$customer->get_email_verification(),
$customer->get_user()->user_email,
$customer->has_trialed(),
$customer->get_last_ip(),
$customer->is_vip(),
$customer->get_signup_form(),
$membership_amount,
implode('|', $memberships_ids),
),
$billing_address,
array(
$customer->get_last_login(),
$customer->get_date_registered(),
)
);
}, wu_get_customers());
$billing_fields = array_keys(\WP_Ultimo\Objects\Billing_Address::fields());
$headers = array_merge(
array(
'id',
'user_id',
'customer_hash',
'email_verification',
'user_email',
'has_trialed',
'customer_last_ip',
'vip',
'signup_form',
'membership_amount',
'membership_ids',
),
$billing_fields,
array(
'last_login',
'date_registered',
)
);
$file_name = sprintf('wp-ultimo-customers-(%s)', gmdate('Y-m-d', wu_get_current_time('timestamp')));
wu_generate_csv($file_name, array_merge(array($headers), $customer_data));
die;
} // end export_customers;
/**
* 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 = array(
'network_admin_menu' => 'wu_read_customers',
);
/**
* Register ajax forms that we use for payments.
*
* @since 2.0.0
* @return void
*/
public function register_forms() {
/*
* Add new Customer
*/
wu_register_form('add_new_customer', array(
'render' => array($this, 'render_add_new_customer_modal'),
'handler' => array($this, 'handle_add_new_customer_modal'),
'capability' => 'wu_invite_customers',
));
} // end register_forms;
/**
* Renders the add new customer modal.
*
* @since 2.0.0
* @return void
*/
public function render_add_new_customer_modal() {
$fields = array(
'type' => array(
'type' => 'tab-select',
'html_attr' => array(
'v-model' => 'type',
),
'options' => array(
'existing' => __('Existing User', 'wp-ultimo'),
'new' => __('Invite New', 'wp-ultimo'),
),
),
'user_id' => array(
'type' => 'model',
'title' => __('Existing User', 'wp-ultimo'),
'placeholder' => __('Search WordPress user...', 'wp-ultimo'),
'tooltip' => '',
'min' => 1,
'wrapper_html_attr' => array(
'v-show' => "require('type', 'existing')",
),
'html_attr' => array(
'data-model' => 'user',
'data-value-field' => 'ID',
'data-label-field' => 'display_name',
'data-search-field' => 'display_name',
'data-max-items' => 1,
),
),
'username' => array(
'type' => 'text',
'title' => __('Username', 'wp-ultimo'),
'placeholder' => __('E.g. johnsmith', 'wp-ultimo'),
'wrapper_html_attr' => array(
'v-show' => "require('type', 'new')",
),
),
'email_address' => array(
'type' => 'email',
'title' => __('Email Address', 'wp-ultimo'),
'placeholder' => __('E.g. customer@wpultimo.dev', 'wp-ultimo'),
'wrapper_html_attr' => array(
'v-show' => "require('type', 'new')",
),
),
'set_password' => array(
'type' => 'toggle',
'title' => __('Set Password', 'wp-ultimo'),
'desc' => __('If not set, the user will be asked to set a password after accepting the invite.', 'wp-ultimo'),
'wrapper_html_attr' => array(
'v-show' => "require('type', 'new')",
),
'html_attr' => array(
'v-model' => 'set_password',
),
),
'password' => array(
'type' => 'password',
'title' => __('Password', 'wp-ultimo'),
'placeholder' => __('E.g. p@$$w0rd', 'wp-ultimo'),
'wrapper_html_attr' => array(
'v-show' => "require('type', 'new') && require('set_password', true)",
),
),
'submit_button' => array(
'type' => 'submit',
'title' => __('Create Customer', 'wp-ultimo'),
'value' => 'save',
'classes' => 'button button-primary wu-w-full',
'wrapper_classes' => 'wu-items-end',
'html_attr' => array(
// 'v-bind:disabled' => '!confirmed',
),
),
);
$form = new \WP_Ultimo\UI\Form('add_new_customer', $fields, array(
'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' => array(
'data-wu-app' => 'add_new_customer',
'data-state' => json_encode(array(
'set_password' => false,
'type' => 'existing',
)),
),
));
$form->render();
} // end render_add_new_customer_modal;
/**
* Handles creation of a new customer.
*
* @since 2.0.0
* @return void
*/
public function handle_add_new_customer_modal() {
if (wu_request('type', 'existing') === 'new') {
$customer_data = array(
'email' => wu_request('email_address'),
'username' => wu_request('username'),
'password' => wu_request('password', false),
'meta' => array(),
);
} else {
$customer_data = array(
'user_id' => wu_request('user_id', 0),
);
} // end if;
/*
* Tries to create the customer
*/
$customer = wu_create_customer($customer_data);
if (is_wp_error($customer)) {
wp_send_json_error($customer);
} // end if;
wp_send_json_success(array(
'redirect_url' => wu_network_admin_url('wp-ultimo-edit-customer', array(
'id' => $customer->get_id(),
))
));
} // end handle_add_new_customer_modal;
/**
* Allow child classes to register widgets, if they need them.
*
* @since 1.8.2
* @return void
*/
public function register_widgets() {} // end register_widgets;
/**
* Returns an array with the labels for the edit page.
*
* @since 1.8.2
* @return array
*/
public function get_labels() {
return array(
'deleted_message' => __('Customer removed successfully.', 'wp-ultimo'),
'search_label' => __('Search Customer', 'wp-ultimo'),
);
} // end get_labels;
/**
* Returns the title of the page.
*
* @since 2.0.0
* @return string Title of the page.
*/
public function get_title() {
return __('Customers', 'wp-ultimo');
} // end get_title;
/**
* 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 __('Customers', 'wp-ultimo');
} // end get_menu_title;
/**
* Allows admins to rename the sub-menu (first item) for a top-level page.
*
* @since 2.0.0
* @return string False to use the title menu or string with sub-menu title.
*/
public function get_submenu_title() {
return __('Customers', 'wp-ultimo');
} // end get_submenu_title;
/**
* Returns the action links for that page.
*
* @since 1.8.2
* @return array
*/
public function action_links() {
return array(
array(
'label' => __('Add Customer', 'wp-ultimo'),
'icon' => 'wu-circle-with-plus',
'classes' => 'wubox',
'url' => wu_get_form_url('add_new_customer'),
),
array(
'label' => __('Export as CSV', 'wp-ultimo'),
'icon' => 'wu-export',
'url' => add_query_arg(array(
'wu_action' => 'wu_export_customers',
'nonce' => wp_create_nonce('wu_export_customers'),
)),
),
);
} // end action_links;
/**
* Loads the list table for this particular page.
*
* @since 2.0.0
* @return \WP_Ultimo\List_Tables\Base_List_Table
*/
public function table() {
return new \WP_Ultimo\List_Tables\Customer_List_Table();
} // end table;
} // end class Customer_List_Admin_Page;

View File

@ -0,0 +1,122 @@
<?php
/**
* WP Ultimo Customize/Add New Template Previewer Page.
*
* @package WP_Ultimo
* @subpackage Admin_Pages
* @since 2.0.0
*/
namespace WP_Ultimo\Admin_Pages;
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* WP Ultimo Template Previewer Customize/Add New Admin Page.
*/
abstract class Customizer_Admin_Page extends Edit_Admin_Page {
/**
* Should we force the admin menu into a folded state?
*
* @since 2.0.0
* @var boolean
*/
protected $fold_menu = true;
/**
* The preview area height.
*
* @since 2.0.0
* @var string
*/
protected $preview_height = '120vh';
/**
* Returns the preview URL. This is then added to the iframe.
*
* @since 2.0.0
* @return string
*/
public function get_preview_url() {
return get_site_url(null);
} // end get_preview_url;
/**
* Adds hooks when the page loads.
*
* @since 2.0.0
* @return void
*/
public function page_loaded() {
/**
* Process save, if necessary
*/
$this->process_save();
$screen = get_current_screen();
add_action("wu_edit_{$screen->id}_after_normal", array($this, 'display_preview_window'));
} // end page_loaded;
/**
* Adds the preview window.
*
* @since 2.0.0
* @return void
*/
public function display_preview_window() {
wu_get_template('base/edit/editor-customizer', array(
'preview_iframe_url' => $this->get_preview_url(),
'preview_height' => $this->preview_height,
));
} // end display_preview_window;
/**
* Registers the necessary scripts and styles for this admin page.
*
* @since 2.0.0
* @return void
*/
public function register_scripts() {
parent::register_scripts();
wp_enqueue_script('wu-customizer', wu_get_asset('customizer.js', 'js'), array('jquery', 'wu-vue', 'wu-block-ui'));
wp_enqueue_style('wp-color-picker');
wp_enqueue_script('wp-color-picker');
wp_enqueue_media();
} // end register_scripts;
/**
* Checkout_Forms have titles.
*
* @since 2.0.0
* @return boolean
*/
public function has_title() {
return false;
} // end has_title;
/**
* Not needed.
*
* @since 2.0.0
* @return void
*/
public function get_object() {} // end get_object;
} // end class Customizer_Admin_Page;

View File

@ -0,0 +1,632 @@
<?php
/**
* WP Ultimo Dashboard 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\Dashboard_Statistics;
/**
* WP Ultimo Dashboard Admin Page.
*/
class Dashboard_Admin_Page extends Base_Admin_Page {
/**
* Holds the ID for this page, this is also used as the page slug.
*
* @var string
*/
protected $id = 'wp-ultimo';
/**
* Menu position. This is only used for top-level menus
*
* @since 1.8.2
* @var integer
*/
protected $position = 10_101_010;
/**
* Dashicon to be used on the menu item. This is only used on top-level menus
*
* @since 1.8.2
* @var string
*/
protected $menu_icon = 'dashicons-wu-wp-ultimo';
/**
* 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;
/**
* 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 = array(
'network_admin_menu' => 'wu_read_dashboard',
);
/**
* The tab being displayed.
*
* @since 2.2.0
* @var string
*/
public $tab;
/**
* The start date for the statistics.
*
* @since 2.2.0
* @var string
*/
public $start_date;
/**
* The end date for the statistics.
*
* @since 2.2.0
* @var string
*/
public $end_date;
/**
* Sets up the global parameters.
*
* @since 2.0.0
* @return void
*/
public function init() {
parent::init();
/*
* Get the content of the tab.
*/
$this->tab = wu_request('tab', 'general');
$this->start_date = date_i18n('Y-m-d', strtotime((string) wu_request('start_date', '-1 month')));
$this->end_date = date_i18n('Y-m-d', strtotime((string) wu_request('end_date', 'tomorrow')));
} // end init;
/**
* Allow child classes to add hooks to be run once the page is loaded.
*
* @see https://codex.wordpress.org/Plugin_API/Action_Reference/load-(page)
* @since 1.8.2
* @return void
*/
public function hooks() {
add_action('wu_dash_after_full_metaboxes', array($this, 'render_filter'));
add_action('wu_dashboard_general_widgets', array($this, 'register_general_tab_widgets'), 10, 2);
} // end hooks;
/**
* Renders the filter.
*
* @since 2.0.0
*
* @param WP_Ultimo\Admin_Pages\Base_Admin_Page $page The page object.
* @return void
*/
public function render_filter($page) {
if (apply_filters('wu_dashboard_display_filter', true) === false) {
return;
} // end if;
if ($page->id === 'wp-ultimo') {
$preset_options = array(
'last_7_days' => array(
'label' => __('Last 7 days', 'wp-ultimo'),
'start_date' => date_i18n('Y-m-d', strtotime('-7 days')),
'end_date' => date_i18n('Y-m-d'),
),
'last_30_days' => array(
'label' => __('Last 30 days', 'wp-ultimo'),
'start_date' => date_i18n('Y-m-d', strtotime('-30 days')),
'end_date' => date_i18n('Y-m-d'),
),
'year_to_date' => array(
'label' => __('Year to date', 'wp-ultimo'),
'start_date' => date_i18n('Y-m-d', strtotime('first day of january this year')),
'end_date' => date_i18n('Y-m-d'),
),
);
$args = array(
'preset_options' => $preset_options,
'filters_el_id' => 'dashboard-filters',
'search_label' => '',
'has_search' => false,
'has_view_switch' => false,
'table' => $this,
'active_tab' => $this->tab,
'views' => $this->get_views(),
);
wu_get_template('dashboard-statistics/filter', $args);
} // end if;
} // end render_filter;
/**
* Returns the views for the filter menu bar.
*
* @since 2.0.0
* @return array
*/
public function get_views() {
$dashboard_filters = array(
'general' => array(
'field' => 'type',
'url' => add_query_arg('tab', 'general'),
'label' => __('General', 'wp-ultimo'),
'count' => 0,
),
);
return apply_filters('wu_dashboard_filter_bar', $dashboard_filters);
} // end get_views;
/**
* Allow child classes to register widgets, if they need them.
*
* @since 1.8.2
* @return void
*/
public function register_widgets() {
$screen = get_current_screen();
if (!$screen) {
return;
} // end if;
/**
* Allow plugin developers to add widgets to Network Dashboard Panel.
*
* @since 2.0.0
*
* @param string $tab The current tab.
* @param \WP_Screen $screen The screen object.
* @param \WP_Ultimo\Admin_Pages\Dashboard_Admin_Page $page WP Ultimo admin page instance.
*/
do_action("wu_dashboard_{$this->tab}_widgets", $this->tab, $screen, $this);
/**
* Allow plugin developers to add widgets to Network Dashboard Panel.
*
* @since 2.0.0
*
* @param string $tab The current tab.
* @param \WP_Screen $screen The screen object.
* @param \WP_Ultimo\Admin_Pages\Dashboard_Admin_Page $page WP Ultimo admin page instance.
*/
do_action('wu_dashboard_widgets', $this->tab, $screen, $this);
if (wu_request('tab', 'general') === 'general') {
\WP_Ultimo\UI\Tours::get_instance()->create_tour('wp-ultimo-dashboard', array(
array(
'id' => 'your-dashboard',
'title' => __('Our dashboard', 'wp-ultimo'),
'text' => array(
__('This is the <strong>WP Ultimo Dashboard</strong>, where you will find most of the important information you will need regarding your business\' performance.', 'wp-ultimo'),
),
),
array(
'id' => 'documentation',
'title' => __('Learning more', 'wp-ultimo'),
'text' => array(
__('Most of the WP Ultimo admin pages will contain a link like this one at the top. These will link directly to the relevant knowledge base page on the WP Ultimo site.', 'wp-ultimo'),
),
'attachTo' => array(
'element' => '#wp-ultimo-wrap > h1 > a:last-child',
'on' => 'left',
),
),
array(
'id' => 'mrr-growth',
'title' => __('It\'s all about growth!', 'wp-ultimo'),
'text' => array(
__('This graph allows you to follow how your monthly recurring revenue is growing this year.', 'wp-ultimo'),
),
'attachTo' => array(
'element' => '#wp-ultimo-mrr-growth',
'on' => 'bottom',
),
),
array(
'id' => 'tailor-made',
'title' => __('Date-range support', 'wp-ultimo'),
'text' => array(
__('Checking statistics and comparing data for different periods is key in maintaining a good grasp on your business.', 'wp-ultimo'),
__('You can use the date-range selectors to have access to just the data you need and nothing more.', 'wp-ultimo'),
),
'attachTo' => array(
'element' => '#dashboard-filters',
'on' => 'bottom',
),
),
));
} // end if;
} // end register_widgets;
/**
* Register the widgets of the default general tab.
*
* @since 2.0.0
*
* @param string $tab Tab slug.
* @param \WP_Screen $screen The screen object.
* @return void
*/
public function register_general_tab_widgets($tab, $screen) {
if (current_user_can('wu_read_financial')) {
add_meta_box('wp-ultimo-mrr-growth', __('Monthly Recurring Revenue Growth', 'wp-ultimo'), array($this, 'output_widget_mrr_growth'), $screen->id, 'full', 'high');
add_meta_box('wp-ultimo-revenue', __('Revenue', 'wp-ultimo'), array($this, 'output_widget_revenues'), $screen->id, 'normal', 'high');
} // end if;
add_meta_box('wp-ultimo-countries', __('Signups by Countries', 'wp-ultimo'), array($this, 'output_widget_countries'), $screen->id, 'side', 'high');
add_meta_box('wp-ultimo-signups', __('Signups by Form', 'wp-ultimo'), array($this, 'output_widget_forms'), $screen->id, 'side', 'high');
add_meta_box('wp-ultimo-most-visited-sites', __('Most Visited Sites', 'wp-ultimo'), array($this, 'output_widget_most_visited_sites'), $screen->id, 'side', 'low');
add_meta_box('wp-ultimo-new-accounts', __('New Memberships', 'wp-ultimo'), array($this, 'output_widget_new_accounts'), $screen->id, 'normal', 'low');
} // end register_general_tab_widgets;
/**
* Output the statistics filter widget
*
* @return void
* @since 2.0.0
*/
public function output_widget_mrr_growth() {
wu_get_template('dashboard-statistics/widget-mrr-growth');
} // end output_widget_mrr_growth;
/**
* Output the statistics filter widget
*
* @return void
* @since 2.0.0
*/
public function output_widget_countries() {
wu_get_template('dashboard-statistics/widget-countries', array(
'countries' => wu_get_countries_of_customers(10, $this->start_date, $this->end_date),
'page' => $this,
));
} // end output_widget_countries;
/**
* Output the statistics filter widget
*
* @return void
* @since 2.0.0
*/
public function output_widget_forms() {
wu_get_template('dashboard-statistics/widget-forms', array(
'forms' => wu_calculate_signups_by_form($this->start_date, $this->end_date),
'page' => $this,
));
} // end output_widget_forms;
/**
* Output the statistics filter widget
*
* @return void
* @since 2.0.0
*/
public function output_widget_most_visited_sites() {
$sites = array();
$site_results = \WP_Ultimo\Objects\Visits::get_sites_by_visit_count($this->start_date, $this->end_date, 10);
foreach ($site_results as $site_result) {
$site = wu_get_site($site_result->site_id);
if (!$site) {
continue;
} // end if;
$sites[] = (object) array(
'site' => $site,
'count' => $site_result->count,
);
} // end foreach;
wu_get_template('dashboard-statistics/widget-most-visited-sites', array(
'sites' => $sites,
'page' => $this,
));
} // end output_widget_most_visited_sites;
/**
* Outputs the total refunds widget content.
*
* @since 2.0.0
*
* @param string $unknown Unknown.
* @param array $metabox With the metabox arguments passed when registered.
* @return void.
*/
public function output_widget_revenues($unknown = null, $metabox = null) {
wu_get_template('dashboard-statistics/widget-revenue', array(
'mrr' => wu_calculate_mrr(),
'gross_revenue' => wu_calculate_revenue($this->start_date, $this->end_date),
'refunds' => wu_calculate_refunds($this->start_date, $this->end_date),
'product_stats' => wu_calculate_financial_data_by_product($this->start_date, $this->end_date),
));
} // end output_widget_revenues;
/**
* Outputs the total refunds widget content.
*
* @since 2.0.0
*
* @param string $unknown Unknown.
* @param array $metabox With the metabox arguments passed when registered.
* @return void.
*/
public function output_widget_new_accounts($unknown = null, $metabox = array()) {
$new_accounts = wu_get_memberships(array(
'fields' => array('plan_id'),
'date_query' => array(
'column' => 'date_created',
'after' => $this->start_date . ' 00:00:00',
'before' => $this->end_date . ' 23:59:59',
'inclusive' => true,
),
));
$products = wu_get_products(array(
'type' => 'plan',
'fields' => array('id', 'name', 'count'),
));
$products_ids = array_column($products, 'id');
$products = array_combine($products_ids, $products);
$products = array_map(function($item) {
$item->count = 0;
return $item;
}, $products);
/**
* Add edge case for no plan.
*/
$products['none'] = (object) array(
'name' => __('No Product', 'wp-ultimo'),
'count' => 0,
);
foreach ($new_accounts as $new_account) {
if (isset($products[$new_account->plan_id])) {
$products[$new_account->plan_id]->count += 1;
} else {
$products['none']->count += 1;
} // end if;
} // end foreach;
wu_get_template('dashboard-statistics/widget-new-accounts', array(
'new_accounts' => count($new_accounts),
'products' => $products,
));
} // end output_widget_new_accounts;
/**
* Enqueue the necessary scripts.
*
* @since 2.0.0
* @return void
*/
public function register_scripts() {
$month_list = array();
$start = date_i18n('Y-m-d 00:00:00', strtotime('first day of january this year'));
for ($i = 0; $i < 12; $i++) {
$start_date = wu_date($start);
$month_list[] = date_i18n('M y', $start_date->addMonths($i)->format('U'));
} // end for;
$statistics = new Dashboard_Statistics(array(
'start_date' => $this->start_date,
'end_date' => $this->end_date,
'types' => array(
'mrr_growth' => 'mrr_growth',
),
));
$data = $statistics->statistics_data();
wp_register_script('wu-apex-charts', wu_get_asset('apexcharts.js', 'js/lib'), array(), wu_get_version(), true);
wp_register_script('wu-vue-apex-charts', wu_get_asset('vue-apexcharts.js', 'js/lib'), array(), wu_get_version(), true);
wp_register_script('wu-dashboard-stats', wu_get_asset('dashboard-statistics.js', 'js'), array('jquery', 'wu-functions', 'wu-ajax-list-table', 'moment', 'wu-block-ui', 'dashboard', 'wu-apex-charts', 'wu-vue-apex-charts'), wu_get_version(), true);
wp_localize_script('wu-dashboard-stats', 'wu_dashboard_statistics_vars', array(
'mrr_array' => $data['mrr_growth'],
'start_date' => date_i18n('Y-m-d', strtotime((string) wu_request('start_date', '-1 month'))),
'end_date' => date_i18n('Y-m-d', strtotime((string) wu_request('end_date', 'tomorrow'))),
'today' => date_i18n('Y-m-d', strtotime('tomorrow')),
'month_list' => $month_list,
'i18n' => array(
'new_mrr' => __('New MRR', 'wp-ultimo'),
'cancellations' => __('Cancellations', 'wp-ultimo'),
),
));
wp_enqueue_script('wu-dashboard-stats');
wp_enqueue_style('wu-apex-charts', wu_get_asset('apexcharts.css', 'css'), array(), wu_get_version());
wp_enqueue_style('wu-flags');
} // end register_scripts;
/**
* Returns the title of the page.
*
* @since 2.0.0
* @return string Title of the page.
*/
public function get_title() {
return __('Dashboard', 'wp-ultimo');
} // end get_title;
/**
* 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 __('WP Ultimo', 'wp-ultimo');
} // end get_menu_title;
/**
* Allows admins to rename the sub-menu (first item) for a top-level page.
*
* @since 2.0.0
* @return string False to use the title menu or string with sub-menu title.
*/
public function get_submenu_title() {
return __('Dashboard', 'wp-ultimo');
} // end get_submenu_title;
/**
* Every child class should implement the output method to display the contents of the page.
*
* @since 1.8.2
* @return void
*/
public function output() {
/*
* Renders the base edit page layout, with the columns and everything else =)
*/
wu_get_template('base/dash', array(
'screen' => get_current_screen(),
'page' => $this,
'has_full_position' => true,
));
} // end output;
/**
* Render an export CSV button.
*
* @since 2.0.0
*
* @param array $args Data array to convert to CSV.
* @return void
*/
public function render_csv_button($args) {
$args = wp_parse_args($args, array(
'slug' => 'csv',
'headers' => array(),
'data' => array(),
'action' => apply_filters('wu_export_data_table_action', 'wu_generate_csv'),
));
$slug = $args['slug'];
$header_strings = json_encode($args['headers']);
$data_strings = json_encode($args['data']);
$html = "<div class='wu-bg-gray-100 wu-p-2 wu-text-right wu-border-0 wu-border-b wu-border-solid wu-border-gray-400'>
<a href='#' attr-slug-csv='{$slug}' class='wu-export-button wu-no-underline wu-text-gray-800 wu-text-xs'>
<span class='dashicons-wu-download wu-mr-1'></span> %s
</a>
<input type='hidden' id='csv_headers_{$slug}' value='{$header_strings}' />
<input type='hidden' id='csv_data_{$slug}' value='{$data_strings}' />
<input type='hidden' id='csv_action_{$slug}' value='{$args['action']}' />
</div>";
$html = apply_filters('wu_export_html_render', $html, $html);
echo sprintf($html, apply_filters('wu_export_data_table_label', __('CSV', 'wp-ultimo')));
} // end render_csv_button;
} // end class Dashboard_Admin_Page;

View File

@ -0,0 +1,695 @@
<?php
/**
* WP Ultimo Discount_Code 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\Models\Discount_Code;
use \WP_Ultimo\Managers\Discount_Code_Manager;
/**
* WP Ultimo Discount_Code Edit/Add New Admin Page.
*/
class Discount_Code_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-discount-code';
/**
* 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 = 'discount_code';
/**
* 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-discount-codes';
/**
* 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;
/**
* 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 = array(
'network_admin_menu' => 'wu_edit_discount_codes',
);
/**
* Allow child classes to register widgets, if they need them.
*
* @since 1.8.2
* @return void
*/
public function register_widgets() {
parent::register_widgets();
$this->add_fields_widget('description', array(
'title' => __('Description', 'wp-ultimo'),
'position' => 'normal',
'fields' => array(
'description' => array(
'type' => 'textarea',
'title' => __('Description', 'wp-ultimo'),
'placeholder' => __('Tell your customers what this product is about.', 'wp-ultimo'),
'value' => $this->get_object()->get_description(),
'html_attr' => array(
'rows' => 3,
),
),
),
));
$tz_note = sprintf('The site timezone is <code>%s</code>. The current time is <code>%s</code>', date_i18n('e'), date_i18n('r'));
$options = array(
'general' => array(
'title' => __('Limit Uses', 'wp-ultimo'),
'icon' => 'dashicons-wu-lock',
'desc' => __('Rules and limitations to the applicability of this discount code.', 'wp-ultimo'),
'fields' => array(
'uses' => array(
'title' => __('Uses', 'wp-ultimo'),
'type' => 'text-display',
// translators: %d is the number of times the coupon was used.
'display_value' => sprintf(__('This discount code was used %d times.', 'wp-ultimo'), $this->get_object()->get_uses()),
'tooltip' => __('The number of times that this discount code was used so far.', 'wp-ultimo'),
),
'max_uses' => array(
'title' => __('Max Uses', 'wp-ultimo'),
'desc' => __('Use this option to set a limit on how many times this discount code can be used. Leave blank or 0 for unlimited uses.', 'wp-ultimo'),
'type' => 'number',
'min' => 0,
'placeholder' => 0,
'value' => $this->get_object()->has_max_uses() ? $this->get_object()->get_max_uses() : __('Unlimited', 'wp-ultimo'),
),
),
),
'time' => array(
'title' => __('Start & Expiration Dates', 'wp-ultimo'),
'desc' => __('Define a start and end date for this discount code. Useful when running campaigns for a pre-determined period.', 'wp-ultimo'),
'icon' => 'dashicons-wu-calendar',
'state' => array(
'enable_date_start' => $this->get_object()->get_date_start(),
'enable_date_expiration' => $this->get_object()->get_date_expiration(),
),
'fields' => array(
'enable_date_start' => array(
'type' => 'toggle',
'title' => __('Enable Start Date', 'wp-ultimo'),
'desc' => __('Allows you to set a start date for this coupon code.', 'wp-ultimo'),
'value' => 1,
'html_attr' => array(
'v-model' => 'enable_date_start',
),
),
'date_start' => array(
'title' => __('Start Date', 'wp-ultimo'),
'desc' => __('The discount code will only be good to be used after this date.', 'wp-ultimo') . ' ' . $tz_note,
'type' => 'text',
'date' => true,
'value' => $this->edit ? $this->get_object()->get_date_start() : __('No date', 'wp-ultimo'),
'placeholder' => 'E.g. 2020-04-04 12:00:00',
'wrapper_html_attr' => array(
'v-cloak' => 1,
'v-show' => 'enable_date_start',
),
'html_attr' => array(
'v-bind:name' => 'enable_date_start ? "date_start" : ""',
'wu-datepicker' => 'true',
'data-format' => 'Y-m-d H:i:S',
'data-allow-time' => 'true',
),
),
'enable_date_expiration' => array(
'type' => 'toggle',
'title' => __('Enable Expiration Date', 'wp-ultimo'),
'desc' => __('Allows you to set an expiration date for this coupon code.', 'wp-ultimo'),
'value' => 1,
'html_attr' => array(
'v-model' => 'enable_date_expiration',
),
),
'date_expiration' => array(
'title' => __('Expiration Date', 'wp-ultimo'),
'desc' => __('The discount code will expire after this date.', 'wp-ultimo') . ' ' . $tz_note,
'type' => 'text',
'date' => true,
'value' => $this->edit ? $this->get_object()->get_date_expiration() : __('Never Expires', 'wp-ultimo'),
'placeholder' => 'E.g. 2020-04-04 12:00:00',
'wrapper_html_attr' => array(
'v-cloak' => 1,
'v-show' => 'enable_date_expiration',
),
'html_attr' => array(
'v-bind:name' => 'enable_date_expiration ? "date_expiration" : ""',
'wu-datepicker' => 'true',
'data-format' => 'Y-m-d H:i:S',
'data-allow-time' => 'true',
),
),
),
),
'products' => array(
'title' => __('Limit Products', 'wp-ultimo'),
'desc' => __('Determine if you want this discount code to apply to all discountable products or not.', 'wp-ultimo'),
'icon' => 'dashicons-wu-price-tag',
'state' => array(
'limit_products' => $this->get_object()->get_limit_products(),
),
'fields' => array_merge(
array(
'limit_products' => array(
'type' => 'toggle',
'title' => __('Select Products', 'wp-ultimo'),
'desc' => __('Manually select to which products this discount code should be applicable.', 'wp-ultimo'),
'value' => 1,
'html_attr' => array(
'v-model' => 'limit_products',
),
),
), $this->get_product_field_list()
),
),
);
$this->add_tabs_widget('options', array(
'title' => __('Advanced Options', 'wp-ultimo'),
'position' => 'normal',
'sections' => apply_filters('wu_discount_code_options_sections', $options, $this->get_object()),
));
/*
* Handle legacy options for back-compat.
*/
$this->handle_legacy_options();
$this->add_list_table_widget('events', array(
'title' => __('Events', 'wp-ultimo'),
'table' => new \WP_Ultimo\List_Tables\Inside_Events_List_Table(),
'query_filter' => array($this, 'query_filter'),
));
$this->add_save_widget('save', array(
'html_attr' => array(
'data-wu-app' => 'save_discount_code',
'data-state' => wu_convert_to_state(array(
'apply_to_setup_fee' => $this->get_object()->get_setup_fee_value() > 0,
'code' => $this->get_object()->get_code(),
'type' => $this->get_object()->get_type(),
'value' => $this->get_object()->get_value(),
'setup_fee_type' => $this->get_object()->get_setup_fee_type(),
'setup_fee_value' => $this->get_object()->get_setup_fee_value(),
)),
),
'fields' => array(
'code' => array(
'title' => __('Coupon Code', 'wp-ultimo'),
'type' => 'text',
'placeholder' => __('E.g. XMAS10OFF', 'wp-ultimo'),
'desc' => __('The actual code your customers will enter during checkout.', 'wp-ultimo'),
'value' => $this->get_object()->get_code(),
'tooltip' => '',
'wrapper_html_attr' => array(
'v-cloak' => '1',
),
'html_attr' => array(
'v-on:input' => 'code = $event.target.value.toUpperCase().replace(/[^A-Z0-9-_]+/g, "")',
'v-bind:value' => 'code',
),
),
'value_group' => array(
'type' => 'group',
'title' => __('Discount', 'wp-ultimo'),
'wrapper_html_attr' => array(
'v-cloak' => '1',
),
'fields' => array(
'type' => array(
'type' => 'select',
'value' => $this->get_object()->get_type(),
'placeholder' => '',
'wrapper_classes' => 'wu-w-2/3',
'options' => array(
'percentage' => __('Percentage (%)', 'wp-ultimo'),
// translators: %s is the currency symbol. e.g. $
'absolute' => sprintf(__('Absolute (%s)', 'wp-ultimo'), wu_get_currency_symbol()),
),
'html_attr' => array(
'v-model' => 'type',
),
),
'value' => array(
'type' => 'number',
'value' => $this->get_object()->get_value(),
'placeholder' => '',
'wrapper_classes' => 'wu-ml-2 wu-w-1/3',
'html_attr' => array(
'min' => 0,
'v-bind:max' => "type === 'percentage' ? 100 : 999999999",
'step' => 'any'
),
),
),
),
'apply_to_renewals' => array(
'type' => 'toggle',
'title' => __('Apply to Renewals', 'wp-ultimo'),
'desc' => __('By default, discounts are only applied to the first payment.', 'wp-ultimo'),
'value' => $this->get_object()->should_apply_to_renewals(),
'wrapper_html_attr' => array(
'v-cloak' => '1',
),
),
'apply_to_setup_fee' => array(
'type' => 'toggle',
'title' => __('Setup Fee Discount', 'wp-ultimo'),
'desc' => __('Also set a discount for setup fee?', 'wp-ultimo'),
'value' => $this->get_object()->get_setup_fee_value() > 0,
'html_attr' => array(
'v-model' => 'apply_to_setup_fee',
),
'wrapper_html_attr' => array(
'v-cloak' => '1',
),
),
'setup_fee_value_group' => array(
'type' => 'group',
'title' => __('Setup Fee Discount', 'wp-ultimo'),
'wrapper_html_attr' => array(
'v-show' => 'apply_to_setup_fee',
'v-cloak' => '1',
),
'fields' => array(
'setup_fee_type' => array(
'type' => 'select',
'value' => $this->get_object()->get_setup_fee_type(),
'placeholder' => '',
'wrapper_classes' => 'wu-w-2/3',
'options' => array(
'percentage' => __('Percentage (%)', 'wp-ultimo'),
// translators: %s is the currency symbol. e.g $
'absolute' => sprintf(__('Absolute (%s)', 'wp-ultimo'), wu_get_currency_symbol()),
),
'html_attr' => array(
'v-model' => 'setup_fee_type',
),
),
'setup_fee_value' => array(
'type' => 'number',
'value' => $this->get_object()->get_setup_fee_value(),
'placeholder' => '',
'wrapper_classes' => 'wu-ml-2 wu-w-1/3',
'html_attr' => array(
'min' => 0,
'v-bind:max' => "setup_fee_type === 'percentage' ? 100 : 999999999",
),
),
),
),
),
));
$this->add_fields_widget('active', array(
'title' => __('Active', 'wp-ultimo'),
'fields' => array(
'active' => array(
'type' => 'toggle',
'title' => __('Active', 'wp-ultimo'),
'desc' => __('Use this option to manually enable or disable this discount code for new sign-ups.', 'wp-ultimo'),
'value' => $this->get_object()->is_active(),
),
),
));
} // end register_widgets;
/**
* List of products to apply this coupon to.
*
* @since 2.0.0
* @return array
*/
protected function get_product_field_list() {
$fields = array();
foreach (wu_get_products() as $product) {
$product_id = $product->get_id();
$fields["allowed_products_{$product_id}"] = array(
'type' => 'toggle',
'title' => $product->get_name(),
'desc' => __('Make applicable to this product.', 'wp-ultimo'),
'tooltip' => '',
'wrapper_classes' => '',
'html_attr' => array(
':name' => "'allowed_products[]'",
':checked' => json_encode(!$this->get_object()->get_limit_products() || in_array($product_id, $this->get_object()->get_allowed_products())), // phpcs:ignore
':value' => $product_id,
),
'wrapper_html_attr' => array(
'v-cloak' => 1,
'v-show' => 'limit_products',
),
);
// TODO: this is a hack-y fix. Needs to be re-implemented.
$fields['allowed_products_none'] = array(
'type' => 'hidden',
'value' => '__none',
'html_attr' => array(
':name' => "'allowed_products[]'",
),
);
} // end foreach;
if (empty($fields)) {
$fields['allowed_products_no_products'] = array(
'type' => 'note',
'title' => '',
'desc' => __('You do not have any products at this moment.', 'wp-ultimo'),
'wrapper_html_attr' => array(
'v-cloak' => 1,
'v-show' => 'limit_products',
),
);
} // end if;
return $fields;
} // end get_product_field_list;
/**
* Handles legacy advanced options for coupons.
*
* @since 2.0.0
* @return void
*/
public function handle_legacy_options() {
global $wp_filter;
$tabs = array(__('Legacy Add-ons', 'wp-ultimo'));
if (!isset($wp_filter['wp_ultimo_coupon_advanced_options'])) {
return;
} // end if;
wp_enqueue_style('wu-legacy-admin-tabs', wu_get_asset('legacy-admin-tabs.css', 'css'), false, wu_get_version());
$priorities = $wp_filter['wp_ultimo_coupon_advanced_options']->callbacks;
$fields = array(
'heading' => array(
'type' => 'header',
'title' => __('Legacy Options', 'wp-ultimo'),
// translators: %s is the comma-separated list of legacy add-ons.
'desc' => sprintf(__('Options for %s, and others.', 'wp-ultimo'), implode(', ', $tabs)),
),
);
foreach ($priorities as $priority => $callbacks) {
foreach ($callbacks as $id => $callable) {
$fields[$id] = array(
'type' => 'html',
'classes' => 'wu--mt-2',
'content' => function() use ($callable) {
call_user_func($callable['function'], $this->get_object());
},
);
} // end foreach;
} // end foreach;
$this->add_fields_widget('legacy-options', array(
'title' => __('Legacy Options', 'wp-ultimo'),
'position' => 'normal',
'fields' => $fields,
'classes' => 'wu-legacy-options-panel',
'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' => array(
'style' => 'margin-top: -5px;',
),
));
} // end handle_legacy_options;
/**
* Register ajax forms that we use for discount code.
*
* @since 2.0.0
* @return void
*/
public function register_forms() {
/*
* Delete Discount code - Confirmation modal
*/
add_filter('wu_data_json_success_delete_discount_code_modal', fn($data_json) => array(
'redirect_url' => wu_network_admin_url('wp-ultimo-discount-codes', array('deleted' => 1))
));
} // end register_forms;
/**
* 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 query_filter($args) {
$extra_args = array(
'object_type' => 'discount_code',
'object_id' => absint($this->get_object()->get_id()),
);
return array_merge($args, $extra_args);
} // end query_filter;
/**
* Returns the title of the page.
*
* @since 2.0.0
* @return string Title of the page.
*/
public function get_title() {
return $this->edit ? __('Edit Discount Code', 'wp-ultimo') : __('Add new Discount Code', 'wp-ultimo');
} // end get_title;
/**
* 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 Discount Code', 'wp-ultimo');
} // end get_menu_title;
/**
* Returns the action links for that page.
*
* @since 1.8.2
* @return array
*/
public function action_links() {
return array();
} // end action_links;
/**
* Returns the labels to be used on the admin page.
*
* @since 2.0.0
* @return array
*/
public function get_labels() {
return array(
'edit_label' => __('Edit Discount Code', 'wp-ultimo'),
'add_new_label' => __('Add new Discount Code', 'wp-ultimo'),
'updated_message' => __('Discount Code updated successfully!', 'wp-ultimo'),
'title_placeholder' => __('Enter Discount Code', 'wp-ultimo'),
'title_description' => '',
'save_button_label' => __('Save Discount Code', 'wp-ultimo'),
'save_description' => '',
'delete_button_label' => __('Delete Discount Code', 'wp-ultimo'),
'delete_description' => __('Be careful. This action is irreversible.', 'wp-ultimo'),
);
} // end get_labels;
/**
* Returns the object being edit at the moment.
*
* @since 2.0.0
* @return \WP_Ultimo\Models\Discount_Code
*/
public function get_object() {
if ($this->object !== null) {
return $this->object;
} // end if;
if (isset($_GET['id'])) {
$item_id = wu_request('id', 0);
$item = wu_get_discount_code($item_id);
if (!$item) {
wp_redirect(wu_network_admin_url('wp-ultimo-discount_codes'));
exit;
} // end if;
$this->object = $item;
return $this->object;
} // end if;
$this->object = new Discount_Code;
return $this->object;
} // end get_object;
/**
* Discount_Codes have titles.
*
* @since 2.0.0
*/
public function has_title(): bool {
return true;
} // end has_title;
/**
* Should implement the processes necessary to save the changes made to the object.
*
* @since 2.0.0
* @return void
*/
public function handle_save() {
/*
* Set the recurring value to zero if the toggle is disabled.
*/
if (!wu_request('apply_to_renewals')) {
$_POST['apply_to_renewals'] = false;
} // end if;
/*
* Set the limit products value.
*/
if (!wu_request('limit_products')) {
$_POST['limit_products'] = false;
} // end if;
/*
* Set the setup fee value to zero if the toggle is disabled.
*/
if (!wu_request('apply_to_setup_fee')) {
$_POST['setup_fee_value'] = 0;
} // end if;
/**
* Unset dates to prevent invalid dates
*/
if (!wu_request('enable_date_start') || !wu_validate_date(wu_request('date_start'))) {
$_POST['date_start'] = null;
} // end if;
if (!wu_request('enable_date_expiration') || !wu_validate_date(wu_request('date_expiration'))) {
$_POST['date_expiration'] = null;
} // end if;
$_POST['code'] = trim((string) wu_request('code'));
parent::handle_save();
} // end handle_save;
} // end class Discount_Code_Edit_Admin_Page;

View File

@ -0,0 +1,146 @@
<?php
/**
* WP Ultimo Discount Code Admin Page.
*
* @package WP_Ultimo
* @subpackage Admin_Pages
* @since 2.0.0
*/
namespace WP_Ultimo\Admin_Pages;
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* WP Ultimo Discount Code Admin Page.
*/
class Discount_Code_List_Admin_Page extends List_Admin_Page {
/**
* Holds the ID for this page, this is also used as the page slug.
*
* @var string
*/
protected $id = 'wp-ultimo-discount-codes';
/**
* Is this a top-level menu or a submenu?
*
* @since 1.8.2
* @var string
*/
protected $type = 'submenu';
/**
* 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;
/**
* 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 = array(
'network_admin_menu' => 'wu_read_discount_codes',
);
/**
* Allow child classes to register widgets, if they need them.
*
* @since 1.8.2
* @return void
*/
public function register_widgets() {} // end register_widgets;
/**
* Returns an array with the labels for the edit page.
*
* @since 1.8.2
* @return array
*/
public function get_labels() {
return array(
'deleted_message' => __('Discount Code removed successfully.', 'wp-ultimo'),
'search_label' => __('Search Discount Code', 'wp-ultimo'),
);
} // end get_labels;
/**
* Returns the title of the page.
*
* @since 2.0.0
* @return string Title of the page.
*/
public function get_title() {
return __('Discount Codes', 'wp-ultimo');
} // end get_title;
/**
* 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 __('Discount Codes', 'wp-ultimo');
} // end get_menu_title;
/**
* Allows admins to rename the sub-menu (first item) for a top-level page.
*
* @since 2.0.0
* @return string False to use the title menu or string with sub-menu title.
*/
public function get_submenu_title() {
return __('Discount Codes', 'wp-ultimo');
} // end get_submenu_title;
/**
* Returns the action links for that page.
*
* @since 1.8.2
* @return array
*/
public function action_links() {
return array(
array(
'url' => wu_network_admin_url('wp-ultimo-edit-discount-code'),
'label' => __('Add Discount Code'),
'icon' => 'wu-circle-with-plus',
),
);
} // end action_links;
/**
* Loads the list table for this particular page.
*
* @since 2.0.0
* @return \WP_Ultimo\List_Tables\Base_List_Table
*/
public function table() {
return new \WP_Ultimo\List_Tables\Discount_Code_List_Table();
} // end table;
} // end class Discount_Code_List_Admin_Page;

View File

@ -0,0 +1,549 @@
<?php
/**
* WP Ultimo Domain 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\Domains\Domain_Stage;
/**
* WP Ultimo Domain Edit/Add New Admin Page.
*/
class Domain_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-domain';
/**
* 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 = 'domain';
/**
* 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-domains';
/**
* 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;
/**
* 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 = array(
'network_admin_menu' => 'wu_edit_domains',
);
/**
* Register ajax forms.
*
* @since 2.0.0
* @return void
*/
public function register_forms() {
/*
* Adds the hooks to handle deletion.
*/
add_filter('wu_form_fields_delete_domain_modal', array($this, 'domain_extra_delete_fields'), 10, 2);
add_action('wu_after_delete_domain_modal', array($this, 'domain_after_delete_actions'));
} // end register_forms;
/**
* Adds the extra delete fields to the delete form.
*
* @since 2.0.0
*
* @param array $fields The original fields.
* @param object $domain The domain object.
* @return array
*/
public function domain_extra_delete_fields($fields, $domain) {
$is_primary_domain = $domain->is_primary_domain();
$has_other_domains = false;
if ($is_primary_domain) {
$other_domains = \WP_Ultimo\Models\Domain::get_by_site($domain->get_blog_id());
$has_other_domains = is_countable($other_domains) ? count($other_domains) - 1 : false;
} // end if;
$custom_fields = array(
'set_domain_as_primary' => array(
'type' => 'model',
'title' => __('Set another domain as primary', 'wp-ultimo'),
'html_attr' => array(
'data-model' => 'domain',
'data-value-field' => 'id',
'data-label-field' => 'domain',
'data-search-field' => 'domain',
'data-max-items' => 1,
'data-exclude' => json_encode(array($domain->get_id())),
'data-include' => json_encode($domain->get_blog_id()),
),
'wrapper_html_attr' => array(
'v-if' => $is_primary_domain && $has_other_domains ? 'true' : 'false',
),
),
'confirm' => array(
'type' => 'toggle',
'title' => __('Confirm Deletion', 'wp-ultimo'),
'desc' => __('This action can not be undone.', 'wp-ultimo'),
'html_attr' => array(
'v-model' => 'confirmed',
),
),
'submit_button' => array(
'type' => 'submit',
'title' => __('Delete', 'wp-ultimo'),
'placeholder' => __('Delete', 'wp-ultimo'),
'value' => 'save',
'classes' => 'button button-primary wu-w-full',
'wrapper_classes' => 'wu-items-end',
'html_attr' => array(
'v-bind:disabled' => '!confirmed',
),
),
'id' => array(
'type' => 'hidden',
'value' => $domain->get_id(),
),
);
return array_merge($custom_fields, $fields);
} // end domain_extra_delete_fields;
/**
* Adds the primary domain handling to the domain deletion.
*
* @since 2.0.0
*
* @param object $domain The domain object.
* @return void
*/
public function domain_after_delete_actions($domain) {
$new_primary_domain_name = wu_request('set_domain_as_primary');
$new_primary_domain = wu_get_domain($new_primary_domain_name);
if ($new_primary_domain) {
$new_primary_domain->set_primary_domain(true);
$new_primary_domain->save();
} // end if;
} // end domain_after_delete_actions;
/**
* Allow child classes to register widgets, if they need them.
*
* @since 1.8.2
* @return void
*/
public function register_widgets() {
parent::register_widgets();
$this->add_fields_widget('domain-url', array(
'title' => __('Domain URL', 'wp-ultimo'),
'position' => 'normal',
'after' => array($this, 'render_dns_widget'),
'fields' => array(
'domain' => array(
'type' => 'text-display',
'title' => __('Domain', 'wp-ultimo'),
'tooltip' => __('Editing an existing domain is not possible. If you want to make changes to this domain, first delete it, and then re-add the right domain.', 'wp-ultimo'),
'display_value' => '<span class="wu-text-sm wu-uppercase wu-font-mono">' . $this->get_object()->get_domain() . '</span> <a target="_blank" class="wu-no-underline" href="' . esc_url($this->get_object()->get_url()) . '"><span class="dashicons-wu-link1 "></span></a>',
),
),
));
$this->add_tabs_widget('options', array(
'title' => __('Domain Options', 'wp-ultimo'),
'position' => 'normal',
'sections' => array(
'general' => array(
'title' => __('General', 'wp-ultimo'),
'desc' => __('General options for the domain.', 'wp-ultimo'),
'icon' => 'dashicons-wu-globe',
'state' => array(
'primary_domain' => $this->get_object()->is_primary_domain(),
),
'fields' => array(
'primary_domain' => array(
'type' => 'toggle',
'title' => __('Is Primary Domain?', 'wp-ultimo'),
'desc' => __('Set as the primary domain.', 'wp-ultimo'),
'tooltip' => __('Setting this as the primary domain will remove any other domain mapping marked as the primary domain for this site.', 'wp-ultimo'),
'value' => $this->get_object()->is_primary_domain(),
'html_attr' => array(
'v-model' => 'primary_domain',
),
),
'primary_note' => array(
'type' => 'note',
'desc' => __('By making this the primary domain, we will convert the previous primary domain for this site, if one exists, into an alias domain.', 'wp-ultimo'),
'wrapper_html_attr' => array(
'v-if' => "require('primary_domain', true)",
),
),
'secure' => array(
'type' => 'toggle',
'title' => __('Is Secure?', 'wp-ultimo'),
'desc' => __('Force the load using HTTPS.', 'wp-ultimo'),
'value' => $this->get_object()->is_secure(),
),
),
),
),
));
$this->add_list_table_widget('sites', array(
'title' => __('Linked Site', 'wp-ultimo'),
'table' => new \WP_Ultimo\List_Tables\Memberships_Site_List_Table(),
'query_filter' => array($this, 'sites_query_filter'),
));
add_meta_box('wp-ultimo-domain-log', __('Domain Test Log', 'wp-ultimo'), array($this, 'render_log_widget'), get_current_screen()->id, 'normal', null);
$this->add_list_table_widget('events', array(
'title' => __('Events', 'wp-ultimo'),
'table' => new \WP_Ultimo\List_Tables\Inside_Events_List_Table(),
'query_filter' => array($this, 'query_filter'),
));
$this->add_save_widget('save', array(
'html_attr' => array(
'data-wu-app' => 'save',
'data-state' => wu_convert_to_state( array(
'stage' => $this->get_object()->get_stage(),
)),
),
'fields' => array(
'stage' => array(
'type' => 'select',
'title' => __('Stage', 'wp-ultimo'),
'placeholder' => __('Select Stage', 'wp-ultimo'),
'desc' => __('The stage in the checking lifecycle of this domain.', 'wp-ultimo'),
'options' => Domain_Stage::to_array(),
'value' => $this->get_object()->get_stage(),
'wrapper_html_attr' => array(
'v-cloak' => '1',
),
'html_attr' => array(
'@change' => 'window.wu_basic.stage = $event.target.value',
'v-model' => 'stage',
),
),
'blog_id' => array(
'type' => 'model',
'title' => __('Site', 'wp-ultimo'),
'placeholder' => __('Search Site...', 'wp-ultimo'),
'desc' => __('The target site of this domain.', 'wp-ultimo'),
'value' => $this->get_object()->get_blog_id(),
'tooltip' => '',
'html_attr' => array(
'data-model' => 'site',
'data-value-field' => 'blog_id',
'data-label-field' => 'title',
'data-search-field' => 'title',
'data-max-items' => 1,
'data-selected' => $this->get_object()->get_site() ? json_encode($this->get_object()->get_site()->to_search_results()) : '',
),
'wrapper_html_attr' => array(
'v-cloak' => '1',
),
),
),
));
$check_for_active_string = sprintf('%s.includes(stage)', json_encode(\WP_Ultimo\Models\Domain::INACTIVE_STAGES));
$this->add_fields_widget('basic', array(
'title' => __('Active', 'wp-ultimo'),
'html_attr' => array(
'data-wu-app' => 'basic',
'data-state' => wu_convert_to_state( array(
'stage' => $this->get_object()->get_stage(),
)),
),
'fields' => array(
'active' => array(
'type' => 'toggle',
'title' => __('Active', 'wp-ultimo'),
'desc' => __('Use this option to manually enable or disable this domain.', 'wp-ultimo'),
'value' => $this->get_object()->is_active(),
'html_attr' => array(
'v-cloak' => '1',
'v-bind:disabled' => $check_for_active_string,
),
'wrapper_html_attr' => array(
'v-bind:class' => "$check_for_active_string ? 'wu-cursor-not-allowed wu-opacity-75' : ''",
),
),
'note' => array(
'type' => 'note',
'desc' => __('This domain has a domain stage that forces it to be inactive. Change the status to Ready or Ready (without SSL) to be able to control the active status directly.', 'wp-ultimo'),
'classes' => 'wu-p-2 wu-bg-red-100 wu-text-red-600 wu-rounded wu-w-full',
'wrapper_html_attr' => array(
'v-show' => $check_for_active_string,
'v-cloak' => '1',
),
),
),
));
} // end register_widgets;
/**
* Renders the DNS widget
*
* @since 2.0.0
* @return void
*/
public function render_dns_widget() {
wu_get_template('domain/dns-table', array(
'domain' => $this->get_object(),
));
} // end render_dns_widget;
/**
* Renders the DNS widget
*
* @since 2.0.0
* @return void
*/
public function render_log_widget() {
wu_get_template('domain/log', array(
'domain' => $this->get_object(),
'log_path' => \WP_Ultimo\Logger::get_logs_folder(),
));
} // end render_log_widget;
/**
* Returns the title of the page.
*
* @since 2.0.0
* @return string Title of the page.
*/
public function get_title() {
return $this->edit ? __('Edit Domain', 'wp-ultimo') : __('Add new Domain', 'wp-ultimo');
} // end get_title;
/**
* 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 Domain', 'wp-ultimo');
} // end get_menu_title;
/**
* Returns the action links for that page.
*
* @since 1.8.2
* @return array
*/
public function action_links() {
return array();
} // end action_links;
/**
* Returns the labels to be used on the admin page.
*
* @since 2.0.0
* @return array
*/
public function get_labels() {
return array(
'edit_label' => __('Edit Domain', 'wp-ultimo'),
'add_new_label' => __('Add new Domain', 'wp-ultimo'),
'updated_message' => __('Domain updated with success!', 'wp-ultimo'),
'title_placeholder' => __('Enter Domain', 'wp-ultimo'),
'title_description' => '',
'save_button_label' => __('Save Domain', 'wp-ultimo'),
'save_description' => '',
'delete_button_label' => __('Delete Domain', 'wp-ultimo'),
'delete_description' => __('Be careful. This action is irreversible.', 'wp-ultimo'),
);
} // end get_labels;
/**
* 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 query_filter($args) {
$extra_args = array(
'object_type' => 'domain',
'object_id' => absint($this->get_object()->get_id()),
);
return array_merge($args, $extra_args);
} // end query_filter;
/**
* 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['blog_id'] = $this->get_object()->get_site_id();
return $args;
} // end sites_query_filter;
/**
* Returns the object being edit at the moment.
*
* @since 2.0.0
* @return \WP_Ultimo\Models\Domain
*/
public function get_object() {
if ($this->object !== null) {
return $this->object;
} // end if;
$item_id = wu_request('id', 0);
$item = wu_get_domain($item_id);
if (!$item) {
wp_redirect(wu_network_admin_url('wp-ultimo-domains'));
exit;
} // end if;
$this->object = $item;
return $this->object;
} // end get_object;
/**
* Domains have titles.
*
* @since 2.0.0
*/
public function has_title(): bool {
return false;
} // end has_title;
/**
* Should implement the processes necessary to save the changes made to the object.
*
* @since 2.0.0
* @return void
*/
public function handle_save() {
if (!wu_request('primary_domain')) {
$_POST['primary_domain'] = false;
} // end if;
if (!wu_request('active')) {
$_POST['active'] = false;
} // end if;
if (!wu_request('secure')) {
$_POST['secure'] = false;
} // end if;
wu_enqueue_async_action('wu_async_process_domain_stage', array('domain_id' => $this->get_object()->get_id()), 'domain');
parent::handle_save();
} // end handle_save;
} // end class Domain_Edit_Admin_Page;

View File

@ -0,0 +1,344 @@
<?php
/**
* WP Ultimo Dashboard 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\Models\Domain;
use \WP_Ultimo\Database\Domains\Domain_Stage;
/**
* WP Ultimo Dashboard Admin Page.
*/
class Domain_List_Admin_Page extends List_Admin_Page {
/**
* Holds the ID for this page, this is also used as the page slug.
*
* @var string
*/
protected $id = 'wp-ultimo-domains';
/**
* Is this a top-level menu or a submenu?
*
* @since 1.8.2
* @var string
*/
protected $type = 'submenu';
/**
* 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;
/**
* 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 = array(
'network_admin_menu' => 'wu_read_domains',
);
/**
* Register ajax forms that we use for payments.
*
* @since 2.0.0
* @return void
*/
public function register_forms() {
/*
* Add new Domain
*/
wu_register_form('add_new_domain', array(
'render' => array($this, 'render_add_new_domain_modal'),
'handler' => array($this, 'handle_add_new_domain_modal'),
'capability' => 'wu_edit_domains',
));
} // end register_forms;
/**
* Renders the add new customer modal.
*
* @since 2.0.0
* @return void
*/
public function render_add_new_domain_modal() {
$addon_url = wu_network_admin_url('wp-ultimo-addons', array(
's' => 'Domain Seller'
));
// translators: %s is the URL to the add-on.
$note_desc = sprintf(__('To activate this feature you need to install the <a href="%s" target="_blank" class="wu-no-underline">WP Ultimo: Domain Seller</a> add-on.', 'wp-ultimo'), $addon_url);
$fields = array(
'type' => array(
'type' => 'tab-select',
'options' => array(
'add' => __('Add Existing Domain', 'wp-ultimo'),
'register' => __('Register New', 'wp-ultimo'),
),
'html_attr' => array(
'v-model' => 'type',
),
),
'domain' => array(
'type' => 'text',
'title' => __('Domain', 'wp-ultimo'),
'placeholder' => __('E.g. mydomain.com', 'wp-ultimo'),
'desc' => __('Be sure the domain has the right DNS setup in place before adding it.', 'wp-ultimo'),
'wrapper_html_attr' => array(
'v-show' => "require('type', 'add')",
),
),
'blog_id' => array(
'type' => 'model',
'title' => __('Apply to Site', 'wp-ultimo'),
'placeholder' => __('Search Sites...', 'wp-ultimo'),
'desc' => __('The target site of the domain being added.', 'wp-ultimo'),
'html_attr' => array(
'data-model' => 'site',
'data-value-field' => 'blog_id',
'data-label-field' => 'title',
'data-search-field' => 'title',
'data-max-items' => 1,
),
'wrapper_html_attr' => array(
'v-show' => "require('type', 'add')",
),
),
'stage' => array(
'type' => 'select',
'title' => __('Stage', 'wp-ultimo'),
'placeholder' => __('Select Stage', 'wp-ultimo'),
'desc' => __('The stage in the domain check lifecycle. Leave "Checking DNS" to have the domain go through WP Ultimo\'s automated tests.', 'wp-ultimo'),
'options' => Domain_Stage::to_array(),
'value' => Domain_Stage::CHECKING_DNS,
),
'primary_domain' => array(
'type' => 'toggle',
'title' => __('Primary Domain', 'wp-ultimo'),
'desc' => __('Check to set this domain as the primary', 'wp-ultimo'),
'html_attr' => array(
'v-model' => 'primary_domain',
),
),
'primary_note' => array(
'type' => 'note',
'desc' => __('By making this the primary domain, we will convert the previous primary domain for this site, if one exists, into an alias domain.', 'wp-ultimo'),
'wrapper_html_attr' => array(
'v-show' => "require('primary_domain', true)",
),
),
'submit_button_new' => array(
'type' => 'submit',
'title' => __('Add Existing Domain', 'wp-ultimo'),
'value' => 'save',
'classes' => 'button button-primary wu-w-full',
'wrapper_classes' => 'wu-items-end',
'wrapper_html_attr' => array(
'v-show' => "require('type', 'add')",
),
),
'addon_note' => array(
'type' => 'note',
'desc' => $note_desc,
'classes' => 'wu-p-2 wu-bg-blue-100 wu-text-gray-600 wu-rounded wu-w-full',
'wrapper_html_attr' => array(
'v-show' => "require('type', 'register')",
),
),
'submit_button_register' => array(
'type' => 'submit',
'title' => __('Register and Add Domain (soon)', 'wp-ultimo'),
'value' => 'save',
'classes' => 'button button-primary wu-w-full',
'wrapper_classes' => 'wu-items-end',
'wrapper_html_attr' => array(
'v-show' => "require('type', 'register')",
),
'html_attr' => array(
'disabled' => 'disabled',
),
),
);
$form = new \WP_Ultimo\UI\Form('add_new_domain', $fields, array(
'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' => array(
'data-wu-app' => 'add_new_domain',
'data-state' => json_encode(array(
'type' => 'add',
'primary_domain' => false,
)),
),
));
$form->render();
} // end render_add_new_domain_modal;
/**
* Handles creation of a new customer.
*
* @since 2.0.0
* @return void
*/
public function handle_add_new_domain_modal() {
/**
* Fires before handle the add new domain modal request.
*
* @since 2.0.0
*/
do_action('wu_handle_add_new_domain_modal');
if (wu_request('type', 'add') === 'add') {
/*
* Tries to create the domain
*/
$domain = wu_create_domain(array(
'domain' => wu_request('domain'),
'stage' => wu_request('stage'),
'blog_id' => (int) wu_request('blog_id'),
'primary_domain' => (bool) wu_request('primary_domain'),
));
if (is_wp_error($domain)) {
wp_send_json_error($domain);
} // end if;
if (wu_request('primary_domain')) {
$old_primary_domains = wu_get_domains(array(
'primary_domain' => true,
'blog_id' => wu_request('blog_id'),
'id__not_in' => array($domain->get_id()),
'fields' => 'ids',
));
/*
* Trigger async action to update the old primary domains.
*/
do_action('wu_async_remove_old_primary_domains', array($old_primary_domains));
} // end if;
wu_enqueue_async_action('wu_async_process_domain_stage', array('domain_id' => $domain->get_id()), 'domain');
wp_send_json_success(array(
'redirect_url' => wu_network_admin_url('wp-ultimo-edit-domain', array(
'id' => $domain->get_id(),
))
));
} // end if;
} // end handle_add_new_domain_modal;
/**
* Returns an array with the labels for the edit page.
*
* @since 1.8.2
* @return array
*/
public function get_labels() {
return array(
'deleted_message' => __('Domains removed successfully.', 'wp-ultimo'),
'search_label' => __('Search Domains', 'wp-ultimo'),
);
} // end get_labels;
/**
* Returns the title of the page.
*
* @since 2.0.0
* @return string Title of the page.
*/
public function get_title() {
return __('Domains', 'wp-ultimo');
} // end get_title;
/**
* 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 __('Domains', 'wp-ultimo');
} // end get_menu_title;
/**
* Allows admins to rename the sub-menu (first item) for a top-level page.
*
* @since 2.0.0
* @return string False to use the title menu or string with sub-menu title.
*/
public function get_submenu_title() {
return __('Domains', 'wp-ultimo');
} // end get_submenu_title;
/**
* Returns the action links for that page.
*
* @since 1.8.2
* @return array
*/
public function action_links() {
return array(
array(
'label' => __('Add Domain'),
'icon' => 'wu-circle-with-plus',
'classes' => 'wubox',
'url' => wu_get_form_url('add_new_domain'),
),
);
} // end action_links;
/**
* Loads the list table for this particular page.
*
* @since 2.0.0
* @return \WP_Ultimo\List_Tables\Base_List_Table
*/
public function table() {
return new \WP_Ultimo\List_Tables\Domain_List_Table();
} // end table;
} // end class Domain_List_Admin_Page;

View File

@ -0,0 +1,897 @@
<?php
/**
* Base admin page class.
*
* Abstract class that makes it easy to create new admin pages.
*
* Most of WP Ultimo pages are implemented using this class, which means that the filters and hooks
* listed below can be used to append content to all of our pages at once.
*
* @package WP_Ultimo
* @subpackage Admin_Pages
* @since 2.0.0
*/
namespace WP_Ultimo\Admin_Pages;
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Abstract class that makes it easy to create new admin pages.
*/
abstract class Edit_Admin_Page extends Base_Admin_Page {
/**
* Checks if we are adding a new object or if we are editing one
*
* @since 1.8.2
* @var boolean
*/
public $edit = false;
/**
* The id/name/slug of the object being edited/created. e.g: plan
*
* @since 1.8.2
* @var string
*/
public $object_id;
/**
* The object being edited.
*
* @since 1.8.2
* @var object
*/
public $object;
/**
* Holds validations errors on edition.
*
* @since 2.0.0
* @var null|\WP_Error
*/
protected $errors;
/**
* Returns the errors, if any.
*
* @since 2.0.0
* @return \WP_Error
*/
public function get_errors() {
if ($this->errors === null) {
$this->errors = new \WP_Error;
} // end if;
return $this->errors;
} // end get_errors;
/**
* Register additional hooks to page load such as the action links and the save processing.
*
* @since 2.0.0
* @return void
*/
public function page_loaded() {
/**
* Setups the object
*/
$this->object = $this->get_object();
$this->edit = $this->object->exists();
/**
* Deals with lock statuses.
*/
$this->add_lock_notices();
if (wu_request('submit_button') === 'delete') {
$this->process_delete();
} elseif (wu_request('remove-lock')) {
$this->remove_lock();
} else {
/*
* Process save, if necessary
*/
$this->process_save();
} // end if;
} // end page_loaded;
/**
* Add some other necessary hooks.
*
* @return void
*/
public function hooks() {
parent::hooks();
add_filter('removable_query_args', array($this, 'removable_query_args'));
} // end hooks;
/**
* Adds the wu-new-model to the list of removable query args of WordPress.
*
* @since 2.0.0
*
* @param array $removable_query_args Existing list of removable query args.
* @return array
*/
public function removable_query_args($removable_query_args) {
$removable_query_args[] = 'wu-new-model';
return $removable_query_args;
} // end removable_query_args;
/**
* Displays lock notices, if necessary.
*
* @since 2.0.0
* @return void
*/
protected function add_lock_notices() {
$locked = $this->get_object()->is_locked();
if ($locked && $this->edit) {
// translators: %s is the date, using the site format options
$message = sprintf(__('This item is locked from editions.<br />This is probably due to a background action being performed (like a transfer between different accounts, for example). You can manually unlock it, but be careful. The lock should be released automatically in %s seconds.', 'wp-ultimo'), wu_get_next_queue_run() + 10);
$actions = array(
'preview' => array(
'title' => __('Unlock', 'wp-ultimo'),
'url' => add_query_arg(array(
'remove-lock' => 1,
'unlock_wpultimo_nonce' => wp_create_nonce(sprintf('unlocking_%s', $this->object_id)),
)),
),
);
WP_Ultimo()->notices->add($message, 'warning', 'network-admin', false, $actions);
} // end if;
} // end add_lock_notices;
/**
* Remove the lock from the object.
*
* @since 2.0.0
* @return void
*/
public function remove_lock() {
$unlock_tag = "unlocking_{$this->object_id}";
if (isset($_REQUEST['remove-lock'])) {
check_admin_referer($unlock_tag, 'unlock_wpultimo_nonce');
/**
* Allow plugin developers to add actions to the unlocking process.
*
* @since 1.8.2
*/
do_action("wu_unlock_{$this->object_id}");
/**
* Unlocks and redirects.
*/
$this->get_object()->unlock();
wp_redirect(remove_query_arg(array(
'remove-lock',
'unlock_wpultimo_nonce',
)));
exit;
} // end if;
} // end remove_lock;
/**
* Handles saves, after verifying nonces and such. Should not be rewritten by child classes.
*
* @since 2.0.0
* @return void
*/
final public function process_save() {
$saving_tag = "saving_{$this->object_id}";
if (isset($_REQUEST[$saving_tag])) {
check_admin_referer($saving_tag, '_wpultimo_nonce');
/**
* Allow plugin developers to add actions to the saving process
*
* @since 1.8.2
*/
do_action("wu_save_{$this->object_id}", $this);
/**
* Calls the saving function
*/
$status = $this->handle_save();
if ($status) {
exit;
} // end if;
} // end if;
} // end process_save;
/**
* Handles delete, after verifying nonces and such. Should not be rewritten by child classes.
*
* @since 2.0.0
* @return void
*/
final public function process_delete() {
$deleting_tag = "deleting_{$this->object_id}";
if (isset($_REQUEST[$deleting_tag])) {
check_admin_referer($deleting_tag, 'delete_wpultimo_nonce');
/**
* Allow plugin developers to add actions to the deleting process
*
* @since 1.8.2
*/
do_action("wu_delete_{$this->object_id}");
/**
* Calls the deleting function
*/
$this->handle_delete();
} // end if;
} // end process_delete;
/**
* Returns the labels to be used on the admin page.
*
* @since 2.0.0
* @return array
*/
public function get_labels() {
$default_labels = array(
'edit_label' => __('Edit Object', 'wp-ultimo'),
'add_new_label' => __('Add New Object', 'wp-ultimo'),
'updated_message' => __('Object updated with success!', 'wp-ultimo'),
'title_placeholder' => __('Enter Object Name', 'wp-ultimo'),
'title_description' => '',
'save_button_label' => __('Save', 'wp-ultimo'),
'save_description' => '',
'delete_button_label' => __('Delete', 'wp-ultimo'),
'delete_description' => __('Be careful. This action is irreversible.', 'wp-ultimo'),
);
return apply_filters('wu_edit_admin_page_labels', $default_labels);
} // end get_labels;
/**
* Allow child classes to register scripts and styles that can be loaded on the output function, for example.
*
* @since 1.8.2
* @return void
*/
public function register_scripts() {
parent::register_scripts();
/*
* Enqueue the base Dashboard Scripts
*/
wp_enqueue_script('dashboard');
/*
* Adds Vue.
*/
wp_enqueue_script('wu-vue-apps');
wp_enqueue_script('wu-fields');
wp_enqueue_style('wp-color-picker');
wp_enqueue_script('wu-selectizer');
} // end register_scripts;
/**
* Registers widgets to the edit page.
*
* This implementation register the default save widget.
* Child classes that wish to inherit that widget while registering other,
* can do such by adding a parent::register_widgets() to their own register_widgets() method.
*
* @since 2.0.0
* @return void
*/
public function register_widgets() {
$screen = get_current_screen();
$this->add_info_widget('info', array(
'title' => __('Timestamps', 'wp-ultimo'),
'position' => 'side-bottom',
));
if ($this->edit) {
$this->add_delete_widget('delete', array());
} // end if;
} // end register_widgets;
/**
* Adds a basic widget with info (and fields) to be shown.
*
* @since 2.0.0
*
* @param string $id Unique ID for the widget, since we can have more than one per page.
* @param array $atts Array containing the attributes to be passed to the widget.
* @return void
*/
protected function add_info_widget($id, $atts = array()) {
$created_key = 'date_created';
if (method_exists($this->get_object(), 'get_date_registered')) {
$created_key = 'date_registered';
} // end if;
$created_value = call_user_func(array($this->get_object(), "get_$created_key"));
$atts['fields'][$created_key] = array(
'title' => __('Created at', 'wp-ultimo'),
'type' => 'text-display',
'date' => true,
'display_value' => $this->edit ? $created_value : false,
'value' => $created_value,
'placeholder' => '2020-04-04 12:00:00',
'html_attr' => array(
'wu-datepicker' => 'true',
'data-format' => 'Y-m-d H:i:S',
'data-allow-time' => 'true',
),
);
$show_modified = wu_get_isset($atts, 'modified', true);
if ($this->edit && $show_modified === true) {
$atts['fields']['date_modified'] = array(
'title' => __('Last Modified at', 'wp-ultimo'),
'type' => 'text-display',
'date' => true,
'display_value' => $this->edit ? $this->get_object()->get_date_modified() : __('No date', 'wp-ultimo'),
'value' => $this->get_object()->get_date_modified(),
'placeholder' => '2020-04-04 12:00:00',
'html_attr' => array(
'wu-datepicker' => 'true',
'data-format' => 'Y-m-d H:i:S',
'data-allow-time' => 'true',
),
);
} // end if;
$this->add_fields_widget($id, $atts);
} // end add_info_widget;
/**
* Adds a basic widget to display list tables.
*
* @since 2.0.0
*
* @param string $id Unique ID for the widget, since we can have more than one per page.
* @param array $atts Array containing the attributes to be passed to the widget.
* @return void
*/
protected function add_list_table_widget($id, $atts = array()) {
$atts = wp_parse_args($atts, array(
'widget_id' => $id,
'before' => '',
'after' => '',
'title' => __('List Table', 'wp-ultimo'),
'position' => 'advanced',
'screen' => get_current_screen(),
'page' => $this,
'labels' => $this->get_labels(),
'object' => $this->get_object(),
'edit' => true,
'table' => false,
'query_filter' => false,
));
$atts['table']->set_context('widget');
$table_name = $atts['table']->get_table_id();
if (is_callable($atts['query_filter'])) {
add_filter("wu_{$table_name}_get_items", $atts['query_filter']);
} // end if;
add_filter('wu_events_list_table_get_columns', function($columns) {
unset($columns['object_type']);
unset($columns['code']);
return $columns;
});
add_meta_box("wp-ultimo-list-table-{$id}", $atts['title'], function() use ($atts) {
wp_enqueue_script('wu-ajax-list-table');
wu_get_template('base/edit/widget-list-table', $atts);
}, $atts['screen']->id, $atts['position'], 'default');
} // end add_list_table_widget;
/**
* Adds field widgets to edit pages with the same Form/Field APIs used elsewhere.
*
* @see Take a look at /inc/ui/form and inc/ui/field for reference.
* @since 2.0.0
*
* @param string $id ID of the widget.
* @param array $atts Array of attributes to pass to the form.
* @return void
*/
protected function add_fields_widget($id, $atts = array()) {
$atts = wp_parse_args($atts, array(
'widget_id' => $id,
'before' => '',
'after' => '',
'title' => __('Fields', 'wp-ultimo'),
'position' => 'side',
'screen' => get_current_screen(),
'fields' => array(),
'html_attr' => array(),
'classes' => '',
'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',
));
add_meta_box("wp-ultimo-{$id}-widget", $atts['title'], function() use ($atts) {
if (wu_get_isset($atts['html_attr'], 'data-wu-app')) {
$atts['fields']['loading'] = array(
'type' => 'note',
'desc' => sprintf('<div class="wu-block wu-text-center wu-blinking-animation wu-text-gray-600 wu-my-1 wu-text-2xs wu-uppercase wu-font-semibold">%s</div>', __('Loading...', 'wp-ultimo')),
'wrapper_html_attr' => array(
'v-if' => 0,
),
);
} // end if;
/**
* Instantiate the form for the order details.
*
* @since 2.0.0
*/
$form = new \WP_Ultimo\UI\Form($atts['widget_id'], $atts['fields'], array(
'views' => 'admin-pages/fields',
'classes' => 'wu-widget-list wu-striped wu-m-0 wu--mt-2 wu--mb-3 wu--mx-3 ' . $atts['classes'],
'field_wrapper_classes' => $atts['field_wrapper_classes'],
'html_attr' => $atts['html_attr'],
'before' => $atts['before'],
'after' => $atts['after'],
));
$form->render();
}, $atts['screen']->id, $atts['position'], 'default');
} // end add_fields_widget;
/**
* Adds field widgets to edit pages with the same Form/Field APIs used elsewhere.
*
* @see Take a look at /inc/ui/form and inc/ui/field for reference.
* @since 2.0.0
*
* @param string $id ID of the widget.
* @param array $atts Array of attributes to pass to the form.
* @return void
*/
protected function add_tabs_widget($id, $atts = array()) {
$atts = wp_parse_args($atts, array(
'widget_id' => $id,
'before' => '',
'after' => '',
'title' => __('Tabs', 'wp-ultimo'),
'position' => 'advanced',
'screen' => get_current_screen(),
'sections' => array(),
'html_attr' => array(),
));
$current_section = wu_request($id, current(array_keys($atts['sections'])));
$atts['html_attr']['data-wu-app'] = $id;
$atts['html_attr']['data-state'] = array(
'section' => $current_section,
'display_all' => false,
);
add_meta_box("wp-ultimo-{$id}-widget", $atts['title'], function() use ($atts) {
foreach ($atts['sections'] as $section_id => &$section) {
$section = wp_parse_args($section, array(
'form' => '',
'before' => '',
'after' => '',
'v-show' => '1',
'fields' => array(),
'html_attr' => array(),
'state' => array(),
'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',
));
/**
* Move state ont step up
*/
$atts['html_attr']['data-state'] = array_merge($atts['html_attr']['data-state'], $section['state']);
$section['html_attr'] = array(
'v-cloak' => 1,
'v-show' => "(section == '{$section_id}' || display_all) && " . $section['v-show'],
);
/**
* Adds a header field
*/
$section['fields'] = array_merge(array(
$section_id => array(
'title' => $section['title'],
'desc' => $section['desc'],
'type' => 'header',
'wrapper_html_attr' => array(
'v-show' => 'display_all',
),
)
), $section['fields']);
/**
* Instantiate the form for the order details.
*
* @since 2.0.0
*/
$section['form'] = new \WP_Ultimo\UI\Form($section_id, $section['fields'], array(
'views' => 'admin-pages/fields',
'classes' => 'wu-widget-list wu-striped wu-m-0 wu-border-solid wu-border-gray-300 wu-border-0 wu-border-b',
'field_wrapper_classes' => $section['field_wrapper_classes'],
'html_attr' => $section['html_attr'],
'before' => $section['before'],
'after' => $section['after'],
));
} // end foreach;
wu_get_template('base/edit/widget-tabs', array(
'sections' => $atts['sections'],
'html_attr' => $atts['html_attr'],
'before' => $atts['before'],
'after' => $atts['after'],
));
}, $atts['screen']->id, $atts['position'], 'default');
} // end add_tabs_widget;
/**
* Adds a generic widget to the admin page.
*
* @since 2.0.0
*
* @param string $id ID of the widget.
* @param array $atts Widget parameters.
* @return void
*/
protected function add_widget($id, $atts = array()) {
$atts = wp_parse_args($atts, array(
'widget_id' => $id,
'before' => '',
'after' => '',
'title' => __('Fields', 'wp-ultimo'),
'screen' => get_current_screen(),
'position' => 'side',
'display' => '__return_empty_string',
));
add_meta_box("wp-ultimo-{$id}-widget", $atts['title'], $atts['display'], $atts['screen']->id, $atts['position'], 'default');
} // end add_widget;
/**
* Adds a basic save widget.
*
* @since 2.0.0
*
* @param string $id Unique ID for the widget, since we can have more than one per page.
* @param array $atts Array containing the attributes to be passed to the widget.
* @return void
*/
protected function add_save_widget($id, $atts = array()) {
$labels = $this->get_labels();
$atts['title'] = __('Save', 'wp-ultimo');
/**
* Adds Submit Button
*/
$atts['fields']['submit_save'] = array(
'type' => 'submit',
'title' => $labels['save_button_label'],
'placeholder' => $labels['save_button_label'],
'value' => 'save',
'classes' => 'button button-primary wu-w-full',
'html_attr' => array(),
'wrapper_html_attr' => array(),
);
if (isset($atts['html_attr']['data-wu-app'])) {
$atts['fields']['submit_save']['wrapper_html_attr']['v-cloak'] = 1;
} // end if;
if ($this->get_object() && $this->edit && $this->get_object()->is_locked()) {
$atts['fields']['submit_save']['title'] = __('Locked', 'wp-ultimo');
$atts['fields']['submit_save']['value'] = 'none';
$atts['fields']['submit_save']['html_attr']['disabled'] = 'disabled';
} // end if;
$this->add_fields_widget('save', $atts);
} // end add_save_widget;
/**
* Adds a basic delete widget.
*
* @since 2.0.0
*
* @param string $id Unique ID for the widget, since we can have more than one per page.
* @param array $atts Array containing the attributes to be passed to the widget.
* @return void
*/
protected function add_delete_widget($id, $atts = array()) {
$labels = $this->get_labels();
$atts_default = array(
'title' => __('Delete', 'wp-ultimo'),
'position' => 'side-bottom',
);
$atts = array_merge($atts_default, $atts);
/**
* Adds Note
*/
$atts['fields']['note'] = array(
'type' => 'note',
'desc' => $labels['delete_description'],
);
/**
* Adds Submit Button
*/
$default_delete_field_settings = array(
'type' => 'link',
'title' => '',
'display_value' => $labels['delete_button_label'] ?? '',
'placeholder' => $labels['delete_button_label'] ?? '',
'value' => 'delete',
'classes' => 'button wubox wu-w-full wu-text-center',
'wrapper_classes' => 'wu-bg-gray-100',
'html_attr' => array(
'title' => $labels['delete_button_label'],
'href' => wu_get_form_url(
'delete_modal',
array(
'id' => $this->get_object()->get_id(),
'model' => $this->get_object()->model
)
),
),
);
$custom_delete_field_settings = wu_get_isset($atts['fields'], 'delete', array());
$atts['fields']['delete'] = array_merge($default_delete_field_settings, $custom_delete_field_settings);
$this->add_fields_widget('delete', $atts);
} // end add_delete_widget;
/**
* Displays the contents of the edit page.
*
* @since 2.0.0
* @return void
*/
public function output() {
/*
* Renders the base edit page layout, with the columns and everything else =)
*/
wu_get_template('base/edit', array(
'screen' => get_current_screen(),
'page' => $this,
'labels' => $this->get_labels(),
'object' => $this->get_object(),
));
} // end output;
/**
* Wether or not this pages should have a title field.
*
* @since 2.0.0
* @return boolean
*/
public function has_title() {
return false;
} // end has_title;
/**
* Wether or not this pages should have an editor field.
*
* @since 2.0.0
* @return boolean
*/
public function has_editor() {
return false;
} // end has_editor;
/**
* Should return the object being edited, or false.
*
* Child classes need to implement this method, returning an object to be edited,
* such as a WP_Ultimo\Model, or false, in case this is a 'Add New' page.
*
* @since 2.0.0
* @return \WP_Ultimo\Models\Base_Model
*/
abstract public function get_object(); // end get_object;
/**
* Should implement the processes necessary to save the changes made to the object.
*
* @since 2.0.0
* @return boolean
*/
public function handle_save() {
$object = $this->get_object();
/*
* Active fix
*/
$_POST['active'] = (bool) wu_request('active', false);
$object->attributes($_POST);
if (method_exists($object, 'handle_limitations')) {
$object->handle_limitations($_POST); // @phpstan-ignore-line
} // end if;
$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;
} else {
$array_params = array(
'updated' => 1,
);
if ($this->edit === false) {
$array_params['id'] = $object->get_id();
$array_params['wu-new-model'] = true;
} // end if;
$url = add_query_arg($array_params);
wp_redirect($url);
return true;
} // end if;
} // end handle_save;
/**
* Should implement the processes necessary to delete the object.
*
* @since 2.0.0
* @return void
*/
public function handle_delete() {
$object = $this->get_object();
$saved = $object->delete();
if (is_wp_error($saved)) {
$errors = implode('<br>', $saved->get_error_messages());
WP_Ultimo()->notices->add($errors, 'error', 'network-admin');
return;
} // end if;
$url = str_replace('_', '-', (string) $object->model);
$url = wu_network_admin_url("wp-ultimo-{$url}s");
wp_redirect($url);
exit;
} // end handle_delete;
} // end class Edit_Admin_Page;

View File

@ -0,0 +1,584 @@
<?php
/**
* WP Ultimo Email 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\Models\Email;
use \WP_Ultimo\Managers\Email_Manager;
/**
* WP Ultimo Email Edit/Add New Admin Page.
*/
class Email_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-email';
/**
* 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 = 'system_email';
/**
* 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-broadcasts';
/**
* 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;
/**
* 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 = array(
'network_admin_menu' => 'wu_edit_emails',
);
/**
* Initializes the class
*
* @since 1.8.2
* @return void
*/
public function init() {
/**
* Runs the parent init functions
*/
parent::init();
add_action('wu_page_edit_redirect_handlers', array($this, 'handle_page_redirect'), 10);
} // end init;
/**
* Registers the necessary scripts.
*
* @since 2.0.0
* @return void
*/
public function register_scripts() {
parent::register_scripts();
wp_enqueue_script('wu-email-edit-page', wu_get_asset('email-edit-page.js', 'js'), array('jquery', 'clipboard'));
} // end register_scripts;
/**
* Allow child classes to register widgets, if they need them.
*
* @since 1.8.2
* @return void
*/
public function register_widgets() {
parent::register_widgets();
$object = $this->get_object();
// translators: %s is replaced with the number of days.
$days_text = sprintf(__('Send %s day(s) after the event.', 'wp-ultimo'), '{{ days }}');
// translators: %1$s is replaced with the number of hours, %2$s is replaced with the number of minutes.
$hour_text = sprintf(__('Send %1$s hour(s) and %2$s minute(s) after the event.', 'wp-ultimo'), '{{ hours.split(":").shift() }}', '{{ hours.split(":").pop() }}');
$desc = sprintf('
<span v-show="schedule && schedule_type == \'days\'">%s</span>
<span v-show="schedule && schedule_type == \'hours\'">%s</span>
', $days_text, $hour_text);
$this->add_save_widget('save', array(
'html_attr' => array(
'data-wu-app' => 'email_edit_save',
'data-state' => wu_convert_to_state(array(
'slug' => $this->edit ? $object->get_slug() : '',
'target' => $this->edit ? $object->get_target() : 'admin',
'schedule' => $this->edit ? $object->has_schedule() : false,
'schedule_type' => $this->edit ? $object->get_schedule_type() : 'days',
'days' => $this->edit ? $object->get_send_days() : 1,
'hours' => $this->edit ? $object->get_send_hours() : '12:00',
)),
),
'fields' => array(
'slug' => array(
'type' => 'text',
'title' => __('Slug', 'wp-ultimo'),
'desc' => __('An unique identifier for this system email.', 'wp-ultimo'),
'value' => $this->edit ? $object->get_slug() : '',
'html_attr' => array(
'required' => 'required',
'v-on:input' => 'slug = $event.target.value.toLowerCase().replace(/[^a-z0-9-_]+/g, "")',
'v-bind:value' => 'slug',
),
),
'event' => array(
'type' => 'select',
'title' => __('Event', 'wp-ultimo'),
'desc' => __('The event that will trigger the sending of this email.', 'wp-ultimo'),
'placeholder' => __('Event', 'wp-ultimo'),
'options' => 'wu_get_event_types_as_options',
'value' => $this->edit ? $object->get_event() : 0,
'html_attr' => array(
'name' => ''
),
),
'target' => array(
'type' => 'select',
'title' => __('Target', 'wp-ultimo'),
'desc' => __('To whom this email should be sent.', 'wp-ultimo'),
'placeholder' => __('Network Administrators', 'wp-ultimo'),
'value' => $this->edit ? $object->get_target() : 'admin',
'options' => array(
'admin' => __('Network Administrators', 'wp-ultimo'),
'customer' => __('Customer', 'wp-ultimo'),
),
'html_attr' => array(
'v-model' => 'target',
),
),
'send_copy_to_admin' => array(
'type' => 'toggle',
'title' => __('Send Copy to Admins?', 'wp-ultimo'),
'desc' => __('Checking this options will add the network admins as bcc every time this email is sent to a customer.', 'wp-ultimo'),
'value' => $this->edit ? $object->get_send_copy_to_admin() : false,
'wrapper_html_attr' => array(
'v-show' => 'target == "customer"',
'v-cloak' => 1,
),
),
'schedule' => array(
'type' => 'toggle',
'title' => __('Schedule?', 'wp-ultimo'),
'desc' => __('You can define when the email is sent after the event triggers.', 'wp-ultimo'),
'value' => $this->edit ? $this->get_object()->has_schedule() : 0,
'html_attr' => array(
'v-model' => 'schedule',
),
),
'send_date' => array(
'type' => 'group',
'title' => __('Scheduling Options', 'wp-ultimo'),
'tooltip' => __('When this email will be sent after the event?', 'wp-ultimo'),
'desc' => $desc,
'desc_id' => 'send_date_desc',
'wrapper_html_attr' => array(
'v-show' => 'schedule',
'v-cloak' => 1,
),
'fields' => array(
'schedule_type' => array(
'type' => 'select',
'default' => 'days',
'wrapper_classes' => 'wu-w-2/3',
'value' => $this->edit ? $object->get_schedule_type() : 'days',
'options' => array(
'hours' => __('Delay for hours', 'wp-ultimo'),
'days' => __('Delay for days', 'wp-ultimo'),
),
'html_attr' => array(
'v-model' => 'schedule_type',
),
),
'send_days' => array(
'type' => 'number',
'value' => $this->edit && $object->get_send_days() ? $object->get_send_days() : 1,
'placeholder' => 1,
'min' => 0,
'wrapper_classes' => 'wu-ml-2 wu-w-1/3',
'wrapper_html_attr' => array(
'v-show' => "schedule_type == 'days'",
'v-cloak' => '1',
),
'html_attr' => array(
'v-model' => 'days',
),
),
'send_hours' => array(
'type' => 'text',
'date' => true,
'placeholder' => $this->edit ? $object->get_send_hours() : '12:00',
'value' => $this->edit ? $object->get_send_hours() : '',
'wrapper_classes' => 'wu-ml-2 wu-w-1/3',
'html_attr' => array(
'data-no-calendar' => 'true',
'wu-datepicker' => 'true',
'data-format' => 'H:i',
'data-allow-time' => 'true',
'v-model' => 'hours',
),
'wrapper_html_attr' => array(
'v-show' => "schedule_type == 'hours'",
'v-cloak' => '1',
),
),
),
),
),
));
add_meta_box('wp-ultimo-placeholders', __('Placeholders', 'wp-ultimo'), array($this, 'output_default_widget_placeholders'), get_current_screen()->id, 'normal', null, array());
$this->add_fields_widget('active', array(
'title' => __('Active', 'wp-ultimo'),
'fields' => array(
'active' => array(
'type' => 'toggle',
'title' => __('Active', 'wp-ultimo'),
'desc' => __('Use this option to manually enable or disable this email.', 'wp-ultimo'),
'value' => $this->get_object()->is_active(),
),
),
));
$this->add_tabs_widget('email_edit_options', array(
'title' => __('Advanced Options', 'wp-ultimo'),
'position' => 'normal',
'sections' => array(
'general' => array(
'title' => __('General', 'wp-ultimo'),
'icon' => 'dashicons-wu-lock',
'desc' => __('Rules and limitations to the applicability of this discount code.', 'wp-ultimo'),
'state' => array(
'sender' => $this->edit ? $object->get_custom_sender() : 0,
),
'fields' => array(
'style' => array(
'type' => 'select',
'title' => __('Email Style', 'wp-ultimo'),
'desc' => __('Choose if email body will be sent using the HTML template or in plain text.', 'wp-ultimo'),
'placeholder' => __('Style', 'wp-ultimo'),
'options' => array(
'default' => __('Use Default', 'wp-ultimo'),
'html' => __('HTML Emails', 'wp-ultimo'),
'plain' => __('Plain Emails', 'wp-ultimo'),
),
'value' => $this->edit ? $object->get_style() : 'html',
),
),
),
'sender' => array(
'title' => __('Custom Sender', 'wp-ultimo'),
'icon' => 'dashicons-wu-mail',
'desc' => __('You can define an email and a name that will only be used when this email is sent.', 'wp-ultimo'),
'fields' => array(
'custom_sender' => array(
'type' => 'toggle',
'title' => __('Use a custom sender?', 'wp-ultimo'),
'desc' => __('You can define an email and a name that will only be used when this email is sent.', 'wp-ultimo'),
'value' => $this->edit ? $object->get_custom_sender() : 0,
'html_attr' => array(
'v-model' => 'sender',
),
),
'custom_sender_name' => array(
'type' => 'text',
'title' => __('From "Name"', 'wp-ultimo'),
'desc' => __('Override the global from name for this particular email.', 'wp-ultimo'),
'wrapper_classes' => 'wu-full',
'value' => $this->edit ? $object->get_custom_sender_name() : '',
'wrapper_html_attr' => array(
'v-show' => 'sender',
'v-cloak' => 1,
),
),
'custom_sender_email' => array(
'type' => 'email',
'title' => __('From "Email"', 'wp-ultimo'),
'desc' => __('Override the global from email for this particular email.', 'wp-ultimo'),
'wrapper_classes' => 'wu-full',
'value' => $this->edit ? $object->get_custom_sender_email() : '',
'wrapper_html_attr' => array(
'v-show' => 'sender',
'v-cloak' => 1,
),
),
),
)
)
));
} // end register_widgets;
/**
* Outputs the block that shows the event payload placeholders.
*
* @since 2.0.0
*
* @param mixed $unused Not sure.
* @param array $data Arguments passed by add_meta_box.
* @return void
*/
public function output_default_widget_placeholders($unused, $data) {
wu_get_template('email/widget-placeholders', array(
'title' => __('Event Payload', 'wp-ultimo'),
'loading_text' => __('Loading Payload', 'wp-ultimo'),
));
} // end output_default_widget_placeholders;
/**
* Returns the title of the page.
*
* @since 2.0.0
* @return string Title of the page.
*/
public function get_title() {
return $this->edit ? __('Edit Email', 'wp-ultimo') : __('Add new Email', 'wp-ultimo');
} // end get_title;
/**
* 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 Email', 'wp-ultimo');
} // end get_menu_title;
/**
* Returns the action links for that page.
*
* @since 1.8.2
* @return array
*/
public function action_links() {
$url_atts = array(
'id' => $this->get_object()->get_id(),
'model' => 'email',
'page' => 'edit'
);
$send_test_link = wu_get_form_url('send_new_test', $url_atts);
return array(
array(
'url' => wu_network_admin_url('wp-ultimo-emails'),
'label' => __('Go Back', 'wp-ultimo'),
'icon' => 'wu-reply',
),
array(
'url' => $send_test_link,
'label' => __('Send Test Email', 'wp-ultimo'),
'icon' => 'wu-mail',
'classes' => 'wubox'
),
);
} // end action_links;
/**
* Returns the labels to be used on the admin page.
*
* @since 2.0.0
* @return array
*/
public function get_labels() {
return array(
'edit_label' => __('Edit Email', 'wp-ultimo'),
'add_new_label' => __('Add new Email', 'wp-ultimo'),
'updated_message' => __('Email updated with success!', 'wp-ultimo'),
'title_placeholder' => __('Enter Email Subject', 'wp-ultimo'),
'title_description' => __('This will be used as the email subject line.', 'wp-ultimo'),
'save_button_label' => __('Save Email', 'wp-ultimo'),
'save_description' => '',
'delete_button_label' => __('Delete Email', 'wp-ultimo'),
'delete_description' => __('Be careful. This action is irreversible.', 'wp-ultimo'),
);
} // end get_labels;
/**
* 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 query_filter($args) {
$extra_args = array(
'object_type' => 'system_email',
'object_id' => absint($this->get_object()->get_id()),
);
return array_merge($args, $extra_args);
} // end query_filter;
/**
* Handles the toggles.
*
* @since 2.0.0
* @return void
*/
public function handle_save() {
$_POST['schedule'] = wu_request('schedule');
$_POST['send_copy_to_admin'] = wu_request('send_copy_to_admin');
$_POST['custom_sender'] = wu_request('custom_sender');
parent::handle_save();
} // end handle_save;
/**
* Handles the redirect notice from sent new test modal.
*
* @param WP_Ultimo\Admin_Pages\Base_Admin_Page $page The page object.
* @return void
*/
public function handle_page_redirect($page) {
if ($page->get_id() === 'wp-ultimo-edit-email') {
if (wu_request('test_notice')) {
$test_notice = wu_request('test_notice');
?>
<div id="message" class="updated notice notice-success is-dismissible below-h2">
<p><?php echo esc_html($test_notice); ?></p>
</div>
<?php
} // end if;
} // end if;
} // end handle_page_redirect;
/**
* Returns the object being edit at the moment.
*
* @since 2.0.0
* @return \WP_Ultimo\Models\Email
*/
public function get_object() {
if (isset($_GET['id'])) {
$query = new \WP_Ultimo\Database\Emails\Email_Query;
$item = $query->get_item_by('id', $_GET['id']);
if (!$item) {
wp_redirect(wu_network_admin_url('wp-ultimo-emails'));
exit;
} // end if;
return $item;
} // end if;
return new Email;
} // end get_object;
/**
* Emails have titles.
*
* @since 2.0.0
*/
public function has_title(): bool {
return true;
} // end has_title;
/**
* Wether or not this pages should have an editor field.
*
* @since 2.0.0
*/
public function has_editor(): bool {
return true;
} // end has_editor;
/**
* 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 = array(
'object_type' => 'email',
'object_id' => absint($this->get_object()->get_id()),
);
return array_merge($args, $extra_args);
} // end events_query_filter;
} // end class Email_Edit_Admin_Page;

View File

@ -0,0 +1,690 @@
<?php
/**
* WP Ultimo Broadcast Admin Page.
*
* @package WP_Ultimo
* @subpackage Admin_Pages
* @since 2.0.0
*/
namespace WP_Ultimo\Admin_Pages;
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* WP Ultimo Broadcast Admin Page.
*/
class Email_List_Admin_Page extends List_Admin_Page {
/**
* Holds the ID for this page, this is also used as the page slug.
*
* @var string
*/
protected $id = 'wp-ultimo-emails';
/**
* Is this a top-level menu or a submenu?
*
* @since 1.8.2
* @var string
*/
protected $type = 'submenu';
/**
* 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-broadcasts';
/**
* 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;
/**
* 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 = array(
'network_admin_menu' => 'wu_read_emails',
);
/**
* Initializes the class
*
* @since 1.8.2
* @return void
*/
public function init() {
/**
* Runs the parent init functions
*/
parent::init();
add_action('wu_page_list_redirect_handlers', array($this, 'handle_page_redirect'), 10);
} // end init;
/**
* Allow child classes to register widgets, if they need them.
*
* @since 1.8.2
* @return void
*/
public function register_widgets() {} // end register_widgets;
/**
* Returns the title of the page.
*
* @since 2.0.0
* @return string Title of the page.
*/
public function get_title() {
return __('System Emails', 'wp-ultimo');
} // end get_title;
/**
* 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 __('System Emails', 'wp-ultimo');
} // end get_menu_title;
/**
* Allows admins to rename the sub-menu (first item) for a top-level page.
*
* @since 2.0.0
* @return string False to use the title menu or string with sub-menu title.
*/
public function get_submenu_title() {
return __('System Emails', 'wp-ultimo');
} // end get_submenu_title;
/**
* Register ajax form that we use for system emails.
*
* @since 2.0.0
* @return void
*/
public function register_forms() {
/*
* Send a email test
*/
wu_register_form('send_new_test', array(
'render' => array($this, 'render_send_new_test_modal'),
'handler' => array($this, 'handle_send_new_test_modal'),
'capability' => 'wu_add_broadcast',
));
/*
* Reset or Import modal.
*/
wu_register_form('reset_import', array(
'render' => array($this, 'render_reset_import_modal'),
'handler' => array($this, 'handle_reset_import_modal'),
'capability' => 'wu_add_broadcasts',
));
/*
* Reset Confirmation modal.
*/
wu_register_form('reset_confirmation', array(
'render' => array($this, 'render_reset_confirmation_modal'),
'handler' => array($this, 'handle_reset_confirmation_modal'),
'capability' => 'wu_add_broadcasts',
));
} // end register_forms;
/**
* Renders the modal to send tests with system emails.
*
* @since 2.0.0
* @return void
*/
public function render_send_new_test_modal() {
$fields = array(
'send_to' => array(
'type' => 'email',
'title' => __('Send To', 'wp-ultimo'),
'placeholder' => __('E.g. network@email.com', 'wp-ultimo'),
'desc' => __('The test email will be sent to the above email address.', 'wp-ultimo'),
'value' => get_network_option(null, 'admin_email'),
'html_attr' => array(
'required' => 'required',
)
),
'email_id' => array(
'type' => 'hidden',
'value' => wu_request('id'),
),
'page' => array(
'type' => 'hidden',
'value' => wu_request('page'),
),
'submit_button' => array(
'type' => 'submit',
'title' => __('Send Test Email', 'wp-ultimo'),
'value' => 'save',
'classes' => 'button button-primary wu-w-full',
'wrapper_classes' => 'wu-items-end wu-text-right',
),
);
$form = new \WP_Ultimo\UI\Form('send_new_test', $fields, array(
'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' => array(
'data-wu-app' => 'send_new_test',
),
));
$form->render();
} // end render_send_new_test_modal;
/**
* Handles the modal to send tests with system emails.
*
* @since 2.0.0
* @return mixed
*/
public function handle_send_new_test_modal() {
$email_id = wu_request('email_id');
$send_to = wu_request('send_to');
if (!$email_id || !$send_to) {
$error = new \WP_Error('error', __('Something wrong happened.', 'wp-ultimo'));
return wp_send_json_error($error);
} // end if;
$from = array(
'name' => wu_get_setting('from_name'),
'email' => wu_get_setting('from_email'),
);
$to = array(
array(
'name' => wu_get_setting('from_name'),
'email' => $send_to,
)
);
$email = wu_get_email($email_id);
$event_slug = $email->get_event();
$event_type = wu_get_event_type($event_slug);
$payload = array();
if ($event_type) {
$payload = wu_maybe_lazy_load_payload($event_type['payload']);
} // end if;
$args = array(
'style' => $email->get_style(),
'content' => $email->get_content(),
'subject' => get_network_option(null, 'site_name') . ' - ' . $email->get_title(),
'payload' => $payload,
);
$send_mail = wu_send_mail($from, $to, $args);
if (!$send_mail) {
$error = new \WP_Error('error', __('Something wrong happened with your test.', 'wp-ultimo'));
return wp_send_json_error($error);
} // end if;
$page = wu_request('page', 'list');
if ($page === 'edit') {
wp_send_json_success(array(
'redirect_url' => wu_network_admin_url('wp-ultimo-edit-email', array(
'id' => $email_id,
'test_notice' => __('Test sent successfully', 'wp-ultimo')
))
));
die();
} // end if;
wp_send_json_success(array(
'redirect_url' => wu_network_admin_url('wp-ultimo-emails', array(
'notice' => __('Test sent successfully', 'wp-ultimo'),
))
));
} // end handle_send_new_test_modal;
/**
* Renders the modal to reset or import system emails.
*
* @since 2.0.0
*
* @return void
*/
public function render_reset_import_modal() {
$default_system_emails = wu_get_default_system_emails();
$created_emails = wu_get_all_system_emails();
$fields = array(
'reset_emails' => array(
'type' => 'toggle',
'title' => __('Reset System Emails ', 'wp-ultimo'),
'desc' => __('Restore the system emails to their original content.'),
'tooltip' => '',
'value' => 0,
'html_attr' => array(
'v-model' => 'reset_emails',
),
)
);
$fields['reset_note'] = array(
'type' => 'note',
'title' => '',
'desc' => __('No emails to reset.', 'wp-ultimo'),
'tooltip' => '',
'value' => 0,
'wrapper_html_attr' => array(
'v-show' => 'reset_emails',
'v-cloak' => 1,
),
);
foreach ($created_emails as $system_email_key => $system_email_value) {
$system_email_slug = $system_email_value->get_slug();
if (isset($default_system_emails[$system_email_slug])) {
$field_name = 'reset_' . $system_email_value->get_slug();
$system_email_target = $system_email_value->get_target();
$field_title = '<div><strong class="wu-inline-block wu-pr-1">' . $system_email_value->get_title() . '</strong></div>';
$fields[$field_name] = array(
'type' => 'toggle',
'title' => $field_title,
'desc' => $system_email_value->get_event() . ' <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">' . $system_email_target . '</span>',
'tooltip' => '',
'value' => 0,
'wrapper_classes' => 'wu-bg-gray-100',
'wrapper_html_attr' => array(
'v-show' => 'reset_emails',
'v-cloak' => 1,
),
);
if (isset($fields['reset_note'])) {
unset($fields['reset_note']);
} // end if;
} // end if;
} // end foreach;
$fields['import_emails'] = array(
'type' => 'toggle',
'title' => __('Import System Emails', 'wp-ultimo'),
'desc' => __('Add new system emails based on WP Ultimo presets.'),
'tooltip' => '',
'value' => 0,
'html_attr' => array(
'v-model' => 'import_emails',
),
);
$fields['import_note'] = array(
'type' => 'note',
'title' => '',
'desc' => __('All emails are already present.', 'wp-ultimo'),
'tooltip' => '',
'value' => 0,
'wrapper_html_attr' => array(
'v-show' => 'import_emails',
'v-cloak' => 1,
),
);
foreach ($default_system_emails as $default_email_key => $default_email_value) {
$maybe_is_created = wu_get_email_by('slug', $default_email_key);
if (!$maybe_is_created) {
$field_name = 'import_' . $default_email_key;
$field_title = '<div><strong class="wu-inline-block wu-pr-1">' . $default_email_value['title'] . '</strong> </div>';
$fields[$field_name] = array(
'type' => 'toggle',
'title' => $field_title,
'desc' => $default_email_value['event'] . ' <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">' . $default_email_value['target'] . '</span>',
'tooltip' => '',
'value' => 0,
'wrapper_classes' => 'wu-bg-gray-100',
'wrapper_html_attr' => array(
'v-show' => 'import_emails',
'v-cloak' => 1,
),
);
if (isset($fields['import_note'])) {
unset($fields['import_note']);
} // end if;
} // end if;
} // end foreach;
$fields['submit_button'] = array(
'type' => 'submit',
'title' => __('Reset and/or Import', 'wp-ultimo'),
'value' => 'save',
'classes' => 'button button-primary wu-w-full',
'wrapper_classes' => 'wu-items-end wu-text-right',
);
$form = new \WP_Ultimo\UI\Form('reset_import', $fields, array(
'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' => array(
'data-wu-app' => 'reset_import',
'data-state' => json_encode(array(
'reset_emails' => false,
'import_emails' => false
)),
),
));
$form->render();
} // end render_reset_import_modal;
/**
* Handles the modal to reset or import system emails.
*
* @since 2.0.0
*
* @return mixed
*/
public function handle_reset_import_modal() {
$reset = wu_request('reset_emails');
$import = wu_request('import_emails');
$default_system_emails = wu_get_default_system_emails();
$created_emails = wu_get_all_system_emails();
if ($reset) {
foreach ($created_emails as $created_email) {
$slug = $created_email->get_slug();
$maybe_reset = wu_request('reset_' . $slug, '');
if ($maybe_reset) {
$created_email->delete();
wu_create_default_system_email($slug);
} // end if;
} // end foreach;
} // end if;
if ($import) {
foreach ($default_system_emails as $default_system_emails_key => $default_system_emails_value) {
$slug = $default_system_emails_value['slug'];
$maybe_import = wu_request('import_' . $slug, '');
if ($maybe_import) {
wu_create_default_system_email($slug);
} // end if;
} // end foreach;
} // end if;
wp_send_json_success(array(
'redirect_url' => wu_network_admin_url('wp-ultimo-emails')
));
} // end handle_reset_import_modal;
/**
* Handles the redirect notice from sent new test modal.
*
* @param WP_Ultimo\Admin_Pages\Base_Admin_Page $page The page object.
* @return void
*/
public function handle_page_redirect($page) {
if ($page->get_id() === 'wp-ultimo-emails') {
if (wu_request('notice')) {
$notice = wu_request('notice');
?>
<div id="message" class="updated notice notice-success is-dismissible below-h2">
<p><?php echo esc_html($notice); ?></p>
</div>
<?php
} // end if;
} // end if;
} // end handle_page_redirect;
/**
* Renders the reset confirmation modal.
*
* @since 2.0.0
* @return void
*/
public function render_reset_confirmation_modal() {
$fields = array(
'single_reset' => array(
'type' => 'toggle',
'title' => __('Confirm Reset', 'wp-ultimo'),
'desc' => __('This action can not be undone.', 'wp-ultimo'),
'default' => 0,
'html_attr' => array(
'required' => 'required',
)
),
'email_id' => array(
'type' => 'hidden',
'value' => wu_request('id'),
),
'submit_button' => array(
'type' => 'submit',
'title' => __('Reset Email', 'wp-ultimo'),
'value' => 'reset',
'classes' => 'button button-primary wu-w-full',
'wrapper_classes' => 'wu-items-end wu-text-right',
),
);
$form = new \WP_Ultimo\UI\Form('reset_confirmation', $fields, array(
'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' => array(
'data-wu-app' => 'reset_confirmation',
),
));
$form->render();
} // end render_reset_confirmation_modal;
/**
* Handles the reset confirmation modal.
*
* @since 2.0.0
*
* @return mixed
*/
public function handle_reset_confirmation_modal() {
$single_reset = wu_request('single_reset');
$email_id = wu_request('email_id');
if (!$single_reset || !$email_id) {
$error = new \WP_Error('error', __('Something wrong happened.', 'wp-ultimo'));
return wp_send_json_error($error);
} // end if;
$email = wu_get_email($email_id);
$slug = $email->get_slug();
$default_system_emails = wu_get_default_system_emails();
if (isset($default_system_emails[$slug])) {
$email->delete();
wu_create_default_system_email($slug);
$new_email = wu_get_email_by('slug', $slug);
if (!$new_email) {
$error = new \WP_Error('error', __('Something wrong happened.', 'wp-ultimo'));
return wp_send_json_error($error);
} // end if;
wp_send_json_success(array(
'redirect_url' => wu_network_admin_url('wp-ultimo-edit-email', array(
'id' => $new_email->get_id(),
))
));
} // end if;
} // end handle_reset_confirmation_modal;
/**
* Returns the action links for that page.
*
* @since 1.8.2
* @return array
*/
public function action_links() {
$email_template_default = get_network_option(null, 'wu_default_email_template');
return array(
array(
'url' => wu_network_admin_url('wp-ultimo-edit-email'),
'label' => __('Add System Email'),
'icon' => 'wu-circle-with-plus',
),
array(
'url' => wu_network_admin_url('wp-ultimo-customize-email-template&id=' . $email_template_default),
'label' => __('Email Template'),
'icon' => 'wu-mail',
),
array(
'url' => wu_get_form_url('reset_import'),
'classes' => 'wubox',
'label' => __('Reset or Import'),
'icon' => 'wu-cycle',
),
);
} // end action_links;
/**
* Loads the list table for this particular page.
*
* @since 2.0.0
* @return \WP_Ultimo\List_Tables\Base_List_Table
*/
public function table() {
return new \WP_Ultimo\List_Tables\Email_List_Table();
} // end table;
} // end class Email_List_Admin_Page;

View File

@ -0,0 +1,694 @@
<?php
/**
* WP Ultimo Customize/Add New Email Template Page.
*
* @package WP_Ultimo
* @subpackage Admin_Pages
* @since 2.0.0
*/
namespace WP_Ultimo\Admin_Pages;
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* WP Ultimo Email Template Customize/Add New Admin Page.
*/
class Email_Template_Customize_Admin_Page extends Customizer_Admin_Page {
/**
* Holds the ID for this page, this is also used as the page slug.
*
* @var string
*/
protected $id = 'wp-ultimo-customize-email-template';
/**
* Is this a top-level menu or a submenu?
*
* @since 1.8.2
* @var string
*/
protected $type = 'submenu';
/**
* Object ID being customizeed.
*
* @since 1.8.2
* @var string
*/
public $object_id = 'email_template';
/**
* 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-broadcasts';
/**
* 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 = array(
'network_admin_menu' => 'wu_customize_email_template',
);
/**
* Overrides the init method to add additional hooks.
*
* @since 2.0.0
* @return void
*/
public function init() {
parent::init();
add_action('wp_ajax_wu-email-template-preview', array($this, 'email_template_preview'));
} // end init;
/**
* Return the page object
*
* @since 2.0.0
*
* @return object $this The Current Object
*/
public function get_object() {
return $this;
} // end get_object;
/**
* Renders the preview of a given form being customized.
*
* @since 2.0.0
* @return void
*/
public function email_template_preview() {
$object = $this;
$content = wpautop('
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam nulla diam, iaculis sit amet tellus sit amet, tempus hendrerit risus. Proin elementum aliquet lorem ut cursus. Ut varius pharetra magna, eu malesuada metus feugiat id. Aenean cursus purus et massa commodo pretium id ut erat. Suspendisse erat odio, auctor ac elit eget, rhoncus iaculis nulla. Aliquam turpis leo, egestas eget dui a, imperdiet ullamcorper felis. Suspendisse ut lacinia mauris.
Phasellus vitae diam euismod diam tristique faucibus. Proin gravida, augue in molestie porttitor, orci justo aliquam mauris, et commodo mauris nisi vitae tortor. Mauris vulputate fringilla purus et finibus. Duis lacus turpis, tincidunt vel dui ac, fermentum aliquet dolor. Donec auctor tristique consequat. In pharetra lacus quis mi dictum, ut dapibus eros bibendum. Donec tristique nibh ac sem bibendum, at feugiat turpis molestie. Suspendisse eget eleifend nunc. Sed tempor varius nisi non tincidunt. Sed leo arcu, feugiat dapibus sollicitudin a, tincidunt eu ligula. Nam ut arcu id arcu auctor vulputate non molestie quam. Nunc non diam mauris. Praesent erat est, posuere sit amet hendrerit non, molestie eget sem. Cras ac tempor est.'
);
$content .= '<table cellpadding="0" cellspacing="0" style="width:100%; font-family:Roboto,HelveticaNeue,sans-serif; font-size: 15px">
<tbody><tr>
<td style="text-align: right; width: 120px; padding: 8px; background: #eee; border: 1px solid #eee; border-width: 1px 0;"><b>Amount:</b></td>
<td style="padding: 8px; background: #fff; border: 1px solid #eee;"><a href="#" style="color: #29abe2; text-decoration: none;" rel="nofollow">$99.00 USD</a></td>
</tr>
<tr>
<td style="text-align: right; width: 120px; padding: 8px; background: #eee;"><b>Paid with:</b></td>
<td style="padding: 8px; background: #fdfdfd; border: 1px solid #eee; border-top-width: 0;">Credit Card</td>
</tr>
<tr>
<td style="text-align: right; width: 120px; padding: 8px; background: #eee; border: 1px solid #eee; border-width: 1px 0;"><b>External ID:</b></td>
<td style="padding: 8px; background: #fff; border: 1px solid #eee; border-top-width: 0;"><a href="#" style="color: #29abe2; text-decoration: none;" rel="nofollow">ch_1IBe2OFmXz63vF5vkusIdsyv</a></td>
</tr>
<tr>
<td style="text-align: right; width: 120px; padding: 8px; background: #eee;"><b>ID:</b></td>
<td style="padding: 8px; background: #fdfdfd; border: 1px solid #eee; border-top-width: 0;"><a href="#" style="color: #29abe2; text-decoration: none;" rel="nofollow">342257</a></td>
</tr>
<tr>
<td style="text-align: right; width: 120px; padding: 8px; background: #eee; border: 1px solid #eee; border-width: 1px 0;"><b>Processed at:</b></td>
<td style="padding: 8px; background: #fff; border: 1px solid #eee; border-top-width: 0;">Jan 20, 2021 GMT</td>
</tr>
<tr>
<td style="text-align: right; width: 120px; padding: 8px; background: #eee;"><b>Invoice:</b></td>
<td style="padding: 8px; background: #fdfdfd; border: 1px solid #eee; border-top-width: 0;"><a href="#" style="color: #29abe2; text-decoration: none;" rel="nofollow">Download PDF</a></td>
</tr>
<tr>
<td style="text-align: right; width: 120px; padding: 8px; background: #eee; border: 1px solid #eee; border-width: 1px 0;"><b>Type:</b></td>
<td style="padding: 8px; background: #fff; border: 1px solid #eee; border-top-width: 0;">Initial Payment</td>
</tr>
</tbody></table>';
/*
* use arbitrary field to determine if this is the first request for the preview.
*/
$first_request = !wu_request('background_color');
wu_get_template('broadcast/emails/base', array(
'site_name' => get_network_option(null, 'site_name'),
'site_url' => get_site_url(),
'logo_url' => wu_get_network_logo(),
'content' => $content,
'subject' => __('Sample Subject', 'wp-ultimo'),
'is_editor' => true,
'template_settings' => array(
'use_custom_logo' => wu_string_to_bool(wu_request('use_custom_logo', $first_request ? $object->get_setting('use_custom_logo', false) : false)),
'custom_logo' => wu_request('custom_logo', $object->get_setting('custom_logo', false)),
'background_color' => wu_request('background_color', $object->get_setting('background_color', '#f9f9f9')),
'title_color' => wu_request('title_color', $object->get_setting('title_color', '#000000')),
'title_size' => wu_request('title_size', $object->get_setting('title_size', 'h3')),
'title_align' => wu_request('title_align', $object->get_setting('title_align', 'center')),
'title_font' => wu_request('title_font', $object->get_setting('title_font', 'Helvetica Neue, Helvetica, Helvetica, Arial, sans-serif')),
'content_color' => wu_request('content_color', $object->get_setting('content_color', '#000000')),
'content_align' => wu_request('content_align', $object->get_setting('content_align', 'left')),
'content_font' => wu_request('content_font', $object->get_setting('content_font', 'Helvetica Neue, Helvetica, Helvetica, Arial, sans-serif')),
'footer_text' => wu_request('footer_text', $object->get_setting('footer_text', '')),
'footer_font' => wu_request('footer_font', $object->get_setting('footer_font', 'Helvetica Neue, Helvetica, Helvetica, Arial, sans-serif')),
'footer_color' => wu_request('footer_color', $object->get_setting('footer_color', '#000000')),
'footer_align' => wu_request('footer_align', $object->get_setting('footer_align', 'center')),
'display_company_address' => wu_string_to_bool(wu_request('display_company_address', $first_request ? $object->get_setting('display_company_address', true) : false)),
)
));
die;
} // end email_template_preview;
/**
* Returns the preview URL. This is then added to the iframe.
*
* @since 2.0.0
* @return string
*/
public function get_preview_url() {
$url = get_admin_url(wu_get_main_site_id(), 'admin-ajax.php');
return add_query_arg(array(
'action' => 'wu-email-template-preview',
'customizer' => 1,
), $url);
} // end get_preview_url;
/**
* Allow child classes to register widgets, if they need them.
*
* @since 1.8.2
* @return void
*/
public function register_widgets() {
$this->add_save_widget('save', array(
'html_attr' => array(
'data-wu-app' => 'save',
'data-state' => wu_convert_to_state(),
),
'fields' => array(
'note' => array(
'type' => 'note',
'desc' => __('System emails and broadcasts will be sent using this template.', 'wp-ultimo'),
),
)
));
$settings = $this->get_attributes();
$custom_logo = wu_get_isset($settings, 'custom_logo');
$custom_logo_args = wp_get_attachment_image_src($custom_logo, 'full');
$custom_logo_url = $custom_logo_args ? $custom_logo_args[0] : '';
$fields = array(
'tab' => array(
'type' => 'tab-select',
'wrapper_classes' => '',
'wrapper_html_attr' => array(
'v-cloak' => 1,
),
'html_attr' => array(
'v-model' => 'tab',
),
'options' => array(
'header' => __('Header', 'wp-ultimo'),
'content' => __('Content', 'wp-ultimo'),
'footer' => __('Footer', 'wp-ultimo'),
),
),
'use_custom_logo' => array(
'type' => 'toggle',
'title' => __('Use Custom Logo', 'wp-ultimo'),
'desc' => __('You can set a different logo to be used on the system emails.', 'wp-ultimo'),
'wrapper_html_attr' => array(
'v-show' => 'require("tab", "header")',
'v-cloak' => 1,
),
'html_attr' => array(
'v-model' => 'use_custom_logo',
),
),
'custom_logo' => array(
'type' => 'image',
'stacked' => true,
'title' => __('Custom Logo', 'wp-ultimo'),
'desc' => __('The custom logo is used in the email header, if HTML emails are used.', 'wp-ultimo'),
'value' => $custom_logo,
'img' => $custom_logo_url,
'wrapper_html_attr' => array(
'v-show' => 'require("tab", "header") && require("use_custom_logo", true)',
'v-cloak' => 1,
),
'html_attr' => array(
// 'v-model' => 'custom_logo',
),
),
'background_color' => array(
'type' => 'color-picker',
'title' => __('Background Color', 'wp-ultimo'),
'tooltip' => __('The cover background color of the email.', 'wp-ultimo'),
'value' => '#00a1ff',
'wrapper_html_attr' => array(
'v-show' => 'require("tab", "header")',
'v-cloak' => 1,
),
'html_attr' => array(
'v-model' => 'background_color',
),
),
'title_color' => array(
'type' => 'color-picker',
'title' => __('Title Color', 'wp-ultimo'),
'value' => '#00a1ff',
'wrapper_html_attr' => array(
'v-show' => 'require("tab", "header")',
'v-cloak' => 1,
),
'html_attr' => array(
'v-model' => 'title_color',
),
),
'title_size' => array(
'type' => 'select',
'title' => __('Title Size', 'wp-ultimo'),
'value' => wu_get_isset($settings, 'title_size'),
'options' => array(
'h1' => __('h1', 'wp-ultimo'),
'h2' => __('h2', 'wp-ultimo'),
'h3' => __('h3', 'wp-ultimo'),
'h4' => __('h4', 'wp-ultimo'),
'h5' => __('h5', 'wp-ultimo'),
),
'wrapper_html_attr' => array(
'v-show' => 'require("tab", "header")',
'v-cloak' => 1,
),
'html_attr' => array(
'v-model.lazy' => 'title_size',
),
),
'title_align' => array(
'type' => 'select',
'title' => __('Title Align', 'wp-ultimo'),
'tooltip' => __('Aligment of the font in the title.', 'wp-ultimo'),
'value' => wu_get_isset($settings, 'title_align', ''),
'options' => array(
'left' => __('Left', 'wp-ultimo'),
'center' => __('Center', 'wp-ultimo'),
'right' => __('Right', 'wp-ultimo'),
),
'wrapper_html_attr' => array(
'v-show' => 'require("tab", "header")',
'v-cloak' => 1,
),
'html_attr' => array(
'v-model.lazy' => 'title_align',
),
),
'title_font' => array(
'type' => 'select',
'title' => __('Title Font-Family', 'wp-ultimo'),
'value' => wu_get_isset($settings, 'title_font', ''),
'options' => array(
'Helvetica Neue, Helvetica, Helvetica, Arial, sans-serif' => __('Helvetica', 'wp-ultimo'),
'Arial, Helvetica, sans-serif' => __('Arial', 'wp-ultimo'),
'Times New Roman, Times, serif' => __('Times New Roman', 'wp-ultimo'),
'Lucida Console, Courier, monospace' => __('Lucida', 'wp-ultimo'),
),
'wrapper_html_attr' => array(
'v-show' => 'require("tab", "header")',
'v-cloak' => 1,
),
'html_attr' => array(
'v-model.lazy' => 'title_font',
),
),
'content_color' => array(
'type' => 'color-picker',
'title' => __('Content Color', 'wp-ultimo'),
'value' => '#000000',
'wrapper_html_attr' => array(
'v-show' => 'require("tab", "content")',
'v-cloak' => 1,
),
'html_attr' => array(
'v-model' => 'content_color',
),
),
'content_align' => array(
'type' => 'select',
'title' => __('Content Alignment', 'wp-ultimo'),
'tooltip' => __('Alignment of the font in the main email content.', 'wp-ultimo'),
'value' => wu_get_isset($settings, 'content_align', ''),
'options' => array(
'left' => __('Left', 'wp-ultimo'),
'center' => __('Center', 'wp-ultimo'),
'right' => __('Right', 'wp-ultimo'),
),
'wrapper_html_attr' => array(
'v-show' => 'require("tab", "content")',
'v-cloak' => 1,
),
'html_attr' => array(
'v-model.lazy' => 'content_align',
),
),
'content_font' => array(
'type' => 'select',
'title' => __('Content Font-Family', 'wp-ultimo'),
'value' => wu_get_isset($settings, 'content_font', ''),
'options' => array(
'Helvetica Neue, Helvetica, Helvetica, Arial, sans-serif' => __('Helvetica', 'wp-ultimo'),
'Arial, Helvetica, sans-serif' => __('Arial', 'wp-ultimo'),
'Times New Roman, Times, serif' => __('Times New Roman', 'wp-ultimo'),
'Lucida Console, Courier, monospace' => __('Lucida', 'wp-ultimo'),
),
'wrapper_html_attr' => array(
'v-show' => 'require("tab", "content")',
'v-cloak' => 1,
),
'html_attr' => array(
'v-model.lazy' => 'content_font',
),
),
'display_company_address' => array(
'type' => 'toggle',
'title' => __('Display Company Address', 'wp-ultimo'),
'desc' => __('Toggle to show/hide your company address.', 'wp-ultimo'),
'wrapper_html_attr' => array(
'v-show' => 'require("tab", "footer")',
'v-cloak' => 1,
),
'html_attr' => array(
'v-model' => 'display_company_address',
),
),
'footer_text' => array(
'type' => 'textarea',
'title' => __('Footer Content', 'wp-ultimo'),
'placeholder' => __('e.g. Extra info in the email footer.', 'wp-ultimo'),
'value' => wu_get_isset($settings, 'footer_text', ''),
'wrapper_html_attr' => array(
'v-show' => 'require("tab", "footer")',
'v-cloak' => 1,
),
'html_attr' => array(
'v-model.lazy' => 'footer_text',
),
),
'footer_font' => array(
'type' => 'select',
'title' => __('Footer Font-Family', 'wp-ultimo'),
'value' => wu_get_isset($settings, 'footer_font', ''),
'options' => array(
'Helvetica Neue, Helvetica, Helvetica, Arial, sans-serif' => __('Helvetica', 'wp-ultimo'),
'Arial, Helvetica, sans-serif' => __('Arial', 'wp-ultimo'),
'Times New Roman, Times, serif' => __('Times New Roman', 'wp-ultimo'),
'Lucida Console, Courier, monospace' => __('Lucida', 'wp-ultimo'),
),
'wrapper_html_attr' => array(
'v-show' => 'require("tab", "footer")',
'v-cloak' => 1,
),
'html_attr' => array(
'v-model.lazy' => 'footer_font',
),
),
'footer_color' => array(
'type' => 'color-picker',
'title' => __('Footer Color', 'wp-ultimo'),
'value' => '#000000',
'wrapper_html_attr' => array(
'v-show' => 'require("tab", "footer")',
'v-cloak' => 1,
),
'html_attr' => array(
'v-model' => 'footer_color',
),
),
'footer_align' => array(
'type' => 'select',
'title' => __('Footer Alignment', 'wp-ultimo'),
'tooltip' => __('Alignment of the font in the main email footer.', 'wp-ultimo'),
'value' => wu_get_isset($settings, 'footer_align', ''),
'options' => array(
'left' => __('Left', 'wp-ultimo'),
'center' => __('Center', 'wp-ultimo'),
'right' => __('Right', 'wp-ultimo'),
),
'wrapper_html_attr' => array(
'v-show' => 'require("tab", "footer")',
'v-cloak' => 1,
),
'html_attr' => array(
'v-model.lazy' => 'footer_align',
),
),
);
$state = array_merge($settings, array(
'tab' => 'header',
'refresh' => true,
));
$this->add_fields_widget('customizer', array(
'title' => __('Customizer', 'wp-ultimo'),
'position' => 'side',
'fields' => $fields,
'html_attr' => array(
'style' => 'margin-top: -6px;',
'data-wu-app' => 'email_template_customizer',
'data-wu-customizer-panel' => true,
'data-state' => json_encode($state),
),
));
} // end register_widgets;
/**
* Returns the title of the page.
*
* @since 2.0.0
* @return string Title of the page.
*/
public function get_title() {
return __('Customize Email Template:', 'wp-ultimo');
} // end get_title;
/**
* 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 __('Customize Email Template', 'wp-ultimo');
} // end get_menu_title;
/**
* Returns the action links for that page.
*
* @since 1.8.2
* @return array
*/
public function action_links() {
return array();
} // end action_links;
/**
* Returns the labels to be used on the admin page.
*
* @since 2.0.0
* @return array
*/
public function get_labels() {
return array(
'customize_label' => __('Customize Email Template', 'wp-ultimo'),
'add_new_label' => __('Customize Email Template', 'wp-ultimo'),
'edit_label' => __('Edit Email Template', 'wp-ultimo'),
'updated_message' => __('Email Template updated with success!', 'wp-ultimo'),
'title_placeholder' => __('Enter Email Template Name', 'wp-ultimo'),
'title_description' => __('This name is used for internal reference only.', 'wp-ultimo'),
'save_button_label' => __('Save Template', 'wp-ultimo'),
'save_description' => '',
'delete_button_label' => __('Delete Email Template', 'wp-ultimo'),
'delete_description' => __('Be careful. This action is irreversible.', 'wp-ultimo'),
);
} // end get_labels;
/**
* Should implement the processes necessary to save the changes made to the object.
*
* @since 2.0.0
* @return void
*/
public function handle_save() {
$_POST['footer_text'] = stripslashes((string) $_POST['footer_text']);
$_POST['footer_text'] = sanitize_text_field($_POST['footer_text']);
$_POST['use_custom_logo'] = wu_request('use_custom_logo');
$_POST['display_company_address'] = wu_request('display_company_address');
$this->save_settings($_POST);
$url = add_query_arg('updated', '1');
wp_redirect($url);
exit;
} // end handle_save;
/**
* Get the value of attributes.
*
* @since 2.0.0
* @return mixed
*/
public function get_attributes() {
$saved_atts = $this->get_settings();
$attributes = wp_parse_args($saved_atts, $this->get_default_settings());
return $attributes;
} // end get_attributes;
/**
* Gets the default email template settings.
*
* @since 2.0.0
* @return array
*/
public static function get_default_settings() {
return array(
'use_custom_logo' => false,
'custom_logo' => false,
'display_company_address' => true,
'background_color' => '#f1f1f1',
'title_color' => '#000000',
'title_size' => 'h3',
'title_align' => 'center',
'title_font' => 'Helvetica Neue, Helvetica, Helvetica, Arial, sans-serif',
'content_color' => '#000000',
'content_align' => 'left',
'content_font' => 'Helvetica Neue, Helvetica, Helvetica, Arial, sans-serif',
'footer_font' => 'Helvetica Neue, Helvetica, Helvetica, Arial, sans-serif',
'footer_text' => '',
'footer_color' => '#000000',
'footer_align' => 'center',
);
} // end get_default_settings;
/**
* Returns the list of saved settings to customize the email template.
*
* @since 2.0.0
*
* @return array
*/
public static function get_settings() {
return wu_get_option('email_template', array());
} // end get_settings;
/**
* Returns a specitic email template setting.
*
* @since 2.0.0
*
* @param string $setting The setting name.
* @param string $default In case there's no option.
* @return string With the requested setting.
*/
public function get_setting($setting, $default = false) {
if ($setting) {
$return = wu_get_option('email_template', array());
if ($return && isset($return[$setting])) {
$return = $return[$setting];
} else {
$return = $default;
} // end if;
return $return;
} // end if;
} // end get_setting;
/**
* Save settings.
*
* @since 2.0.0
*
* @param array $settings_to_save List of settings to save.
* @return boolean
*/
public function save_settings($settings_to_save) {
$allowed_keys = $this->get_attributes();
foreach ($settings_to_save as $setting_to_save => $value) {
if (!array_key_exists($setting_to_save, $allowed_keys)) {
unset($settings_to_save[$setting_to_save]);
} // end if;
} // end foreach;
return wu_save_option('email_template', $settings_to_save);
} // end save_settings;
} // end class Email_Template_Customize_Admin_Page;

View File

@ -0,0 +1,241 @@
<?php
/**
* WP Ultimo Event Admin Page.
*
* @package WP_Ultimo
* @subpackage Admin_Pages
* @since 2.0.0
*/
namespace WP_Ultimo\Admin_Pages;
use \WP_Ultimo\Models\Event;
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* WP Ultimo Event Admin Page.
*/
class Event_List_Admin_Page extends List_Admin_Page {
/**
* Holds the ID for this page, this is also used as the page slug.
*
* @var string
*/
protected $id = 'wp-ultimo-events';
/**
* Is this a top-level menu or a submenu?
*
* @since 1.8.2
* @var string
*/
protected $type = 'submenu';
/**
* 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 = '';
/**
* 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 = array(
'network_admin_menu' => 'wu_read_events',
);
/**
* Instantiate the necessary hooks.
*
* @since 2.0.0
* @return void
*/
public function init() {
add_action('init', array($this, 'set_badge_count'));
} // end init;
/**
* Adds hooks when the page loads.
*
* @since 2.0.0
* @return void
*/
public function page_loaded() {
parent::page_loaded();
add_action('in_admin_header', array($this, 'count_seen_events'));
} // end page_loaded;
/**
* Sets events badge notification subtracting the total number of events from the seen events in the user meta.
*
* @since 2.0.0
* @return void
*/
public function set_badge_count() {
global $wpdb;
$user_id = get_current_user_id();
$cache = get_site_transient("wu_{$user_id}_unseen_events_count");
if ($cache) {
$this->badge_count = $cache;
return;
} // end if;
$table_name = "{$wpdb->base_prefix}wu_events";
$last_seen = get_user_meta(get_current_user_id(), 'wu_seen_events', true);
$query = $wpdb->prepare("SELECT COUNT(id) FROM {$table_name} WHERE id > %d", $last_seen); // phpcs:ignore
$unseen = $wpdb->get_var($query); // phpcs:ignore
$this->badge_count = $unseen;
set_site_transient("wu_{$user_id}_unseen_events_count", $unseen, 5 * MINUTE_IN_SECONDS);
} // end set_badge_count;
/**
* Sets the seen events in the current user meta.
*
* @since 2.0.0
* @return void
*/
public function count_seen_events() {
$user_id = get_current_user_id();
delete_site_transient("wu_{$user_id}_unseen_events_count");
$last_event = wu_get_events(array(
'orderby' => 'id',
'fields' => 'ids',
'order' => 'DESC',
'number' => 1,
));
if (!empty($last_event)) {
$last_event_id = current($last_event);
update_user_meta($user_id, 'wu_seen_events', $last_event_id);
} // end if;
$this->badge_count = '';
} // end count_seen_events;
/**
* Allow child classes to register widgets, if they need them.
*
* @since 1.8.2
* @return void
*/
public function register_widgets() {} // end register_widgets;
/**
* Returns an array with the labels for the edit page.
*
* @since 1.8.2
* @return array
*/
public function get_labels() {
return array(
'deleted_message' => __('Event removed successfully.', 'wp-ultimo'),
'search_label' => __('Search Event', 'wp-ultimo'),
);
} // end get_labels;
/**
* Returns the title of the page.
*
* @since 2.0.0
* @return string Title of the page.
*/
public function get_title() {
return __('Events', 'wp-ultimo');
} // end get_title;
/**
* 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 __('Events', 'wp-ultimo');
} // end get_menu_title;
/**
* Allows admins to rename the sub-menu (first item) for a top-level page.
*
* @since 2.0.0
* @return string False to use the title menu or string with sub-menu title.
*/
public function get_submenu_title() {
return __('Events', 'wp-ultimo');
} // end get_submenu_title;
/**
* Returns the action links for that page.
*
* @since 1.8.2
* @return array
*/
public function action_links() {
return array(
array(
'url' => wu_network_admin_url('wp-ultimo-view-logs'),
'label' => __('View Logs'),
'icon' => 'dashicons dashicons-editor-ol',
),
);
} // end action_links;
/**
* Loads the list table for this particular page.
*
* @since 2.0.0
* @return \WP_Ultimo\List_Tables\Base_List_Table
*/
public function table() {
return new \WP_Ultimo\List_Tables\Event_List_Table();
} // end table;
} // end class Event_List_Admin_Page;

View File

@ -0,0 +1,303 @@
<?php
/**
* WP Ultimo Event View 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\Models\Event;
/**
* WP Ultimo Event View Admin Page.
*/
class Event_View_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-view-event';
/**
* 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 = 'event';
/**
* 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-events';
/**
* 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;
/**
* 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 = array(
'network_admin_menu' => 'wu_read_events',
);
/**
* Allow child classes to register scripts and styles that can be loaded on the output function, for example.
*
* @since 1.8.2
* @return void
*/
public function register_scripts() {
parent::register_scripts();
\WP_Ultimo\Scripts::get_instance()->register_script('wu-event-view', wu_get_asset('event-view-page.js', 'js'), array('jquery'));
wp_enqueue_script('wu-event-view');
wp_enqueue_script('clipboard');
wp_enqueue_script('wu-vue');
} // end register_scripts;
/**
* Register ajax forms that we use for membership.
*
* @since 2.0.0
* @return void
*/
public function register_forms() {
/*
* Delete Event - Confirmation modal
*/
add_filter('wu_data_json_success_delete_event_modal', fn($data_json) => array(
'redirect_url' => wu_network_admin_url('wp-ultimo-events', array('deleted' => 1))
));
} // end register_forms;
/**
* Allow child classes to register widgets, if they need them.
*
* @since 1.8.2
* @return void
*/
public function register_widgets() {
parent::register_widgets();
add_meta_box('wp-ultimo-message', __('Event Message', 'wp-ultimo'), array($this, 'output_default_widget_message'), get_current_screen()->id, 'normal', 'default');
add_meta_box('wp-ultimo-initiator', __('Event', 'wp-ultimo'), array($this, 'output_default_widget_initiator'), get_current_screen()->id, 'side', 'default');
add_meta_box('wp-ultimo-payload', __('Event Payload', 'wp-ultimo'), array($this, 'output_default_widget_payload'), get_current_screen()->id, 'normal', 'default');
$this->add_info_widget('info', array(
'title' => __('Timestamps', 'wp-ultimo'),
'position' => 'side',
'modified' => false,
));
} // end register_widgets;
/**
* Outputs the markup for the default Save widget.
*
* @since 2.0.0
* @return void
*/
public function output_default_widget_message() {
wu_get_template('events/widget-message', array(
'screen' => get_current_screen(),
'page' => $this,
'labels' => $this->get_labels(),
'object' => $this->get_object(),
));
} // end output_default_widget_message;
/**
* Outputs the markup for the payload widget.
*
* @since 2.0.0
* @return void
*/
public function output_default_widget_payload() {
$object = $this->get_object();
wu_get_template('events/widget-payload', array(
'title' => __('Event Payload', 'wp-ultimo'),
'loading_text' => __('Loading Payload', 'wp-ultimo'),
'payload' => json_encode($object->get_payload(), JSON_PRETTY_PRINT),
));
} // end output_default_widget_payload;
/**
* Outputs the markup for the initiator widget.
*
* @since 2.0.0
* @return void
*/
public function output_default_widget_initiator() {
$object = $this->get_object();
$args = array(
'object' => $object,
);
wu_get_template('events/widget-initiator', $args);
} // end output_default_widget_initiator;
/**
* Returns the title of the page.
*
* @since 2.0.0
* @return string Title of the page.
*/
public function get_title() {
return $this->edit ? __('Edit Event', 'wp-ultimo') : __('Add new Event', 'wp-ultimo');
} // end get_title;
/**
* 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 Event', 'wp-ultimo');
} // end get_menu_title;
/**
* Returns the action links for that page.
*
* @since 1.8.2
* @return array
*/
public function action_links() {
return array();
} // end action_links;
/**
* Returns the labels to be used on the admin page.
*
* @since 2.0.0
* @return array
*/
public function get_labels() {
return array(
'edit_label' => __('Edit Event', 'wp-ultimo'),
'add_new_label' => __('Add new Event', 'wp-ultimo'),
'updated_message' => __('Event updated with success!', 'wp-ultimo'),
'title_placeholder' => __('Enter Event', 'wp-ultimo'),
'title_description' => '',
'save_button_label' => __('Save Event', 'wp-ultimo'),
'save_description' => '',
'delete_button_label' => __('Delete Event', 'wp-ultimo'),
'delete_description' => __('Be careful. This action is irreversible.', 'wp-ultimo'),
);
} // end get_labels;
/**
* Returns the object being edit at the moment.
*
* @since 2.0.0
* @return \WP_Ultimo\Models\Event
*/
public function get_object() {
if (isset($_GET['id'])) {
$query = new \WP_Ultimo\Database\Events\Event_Query;
$item = $query->get_item_by('id', $_GET['id']);
if ($item) {
return $item;
} // end if;
} // end if;
wp_redirect(wu_network_admin_url('wp-ultimo-events'));
exit;
} // end get_object;
/**
* Events have titles.
*
* @since 2.0.0
*/
public function has_title(): bool {
return false;
} // end has_title;
/**
* Handles the save of this form.
*
* @since 2.0.0
*/
public function handle_save(): bool {
return true;
} // end handle_save;
} // end class Event_View_Admin_Page;

View File

@ -0,0 +1,367 @@
<?php
/**
* WP Ultimo Dashboard Admin Page.
*
* @package WP_Ultimo
* @subpackage Admin_Pages
* @since 2.0.0
*/
namespace WP_Ultimo\Admin_Pages;
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* WP Ultimo Dashboard Admin Page.
*/
class Hosting_Integration_Wizard_Admin_Page extends Wizard_Admin_Page {
/**
* Holds the ID for this page, this is also used as the page slug.
*
* @var string
*/
protected $id = 'wp-ultimo-hosting-integration-wizard';
/**
* Is this a top-level menu or a submenu?
*
* @since 1.8.2
* @var string
*/
protected $type = 'submenu';
/**
* 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-settings';
/**
* 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;
/**
* 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 = array(
'network_admin_menu' => 'manage_network',
);
/**
* Current integration being setup.
*
* @since 2.0.0
* @var WP_Ultimo\Integrations\Host_Providers\Base_Host_Provider
*/
protected $integration;
/**
* Allow child classes to add further initializations.
*
* @since 1.8.2
* @return void
*/
public function page_loaded() {
if (isset($_GET['integration'])) {
$domain_manager = \WP_Ultimo\Managers\Domain_Manager::get_instance();
$this->integration = $domain_manager->get_integration_instance($_GET['integration']);
} // end if;
if (!$this->integration) {
wp_redirect(network_admin_url('admin.php?page=wp-ultimo-settings'));
exit;
} // end if;
parent::page_loaded();
} // end page_loaded;
/**
* Returns the title of the page.
*
* @since 2.0.0
* @return string Title of the page.
*/
public function get_title(): string {
return sprintf(__('Integration Setup', 'wp-ultimo'));
} // end get_title;
/**
* 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 __('Host Provider Integration', 'wp-ultimo');
} // end get_menu_title;
/**
* Returns the sections for this Wizard.
*
* @since 2.0.0
* @return array
*/
public function get_sections() {
$sections = array(
'activation' => array(
'title' => __('Activation', 'wp-ultimo'),
'view' => array($this, 'section_activation'),
'handler' => array($this, 'handle_activation'),
),
'instructions' => array(
'title' => __('Instructions', 'wp-ultimo'),
'view' => array($this, 'section_instructions'),
),
'config' => array(
'title' => __('Configuration', 'wp-ultimo'),
'view' => array($this, 'section_configuration'),
'handler' => array($this, 'handle_configuration'),
),
'testing' => array(
'title' => __('Testing Integration', 'wp-ultimo'),
'view' => array($this, 'section_test'),
),
'done' => array(
'title' => __('Ready!', 'wp-ultimo'),
'view' => array($this, 'section_ready'),
),
);
/*
* Some host providers require no instructions.
*/
if ($this->integration->supports('no-instructions')) {
unset($sections['instructions']);
} // end if;
/*
* Some host providers require no additional setup.
*/
if ($this->integration->supports('no-config')) {
unset($sections['config']);
} // end if;
return $sections;
} // end get_sections;
/**
* Displays the content of the activation section.
*
* @since 2.0.0
* @return void
*/
public function section_activation() {
$explainer_lines = $this->integration->get_explainer_lines();
wu_get_template('wizards/host-integrations/activation', array(
'screen' => get_current_screen(),
'page' => $this,
'integration' => $this->integration,
'will' => $explainer_lines['will'],
'will_not' => $explainer_lines['will_not'],
));
} // end section_activation;
/**
* Displays the contents of the instructions section.
*
* @since 2.0.0
* @return void
*/
public function section_instructions() {
call_user_func(array($this->integration, 'get_instructions'));
$this->render_submit_box();
} // end section_instructions;
/**
* Displays the content of the configuration section.
*
* @since 2.0.0
* @return void
*/
public function section_configuration() {
$fields = $this->integration->get_fields();
foreach ($fields as $field_constant => &$field) {
$field['value'] = defined($field_constant) && constant($field_constant) ? constant($field_constant) : '';
} // end foreach;
$form = new \WP_Ultimo\UI\Form($this->get_current_section(), $fields, array(
'views' => 'admin-pages/fields',
'classes' => 'wu-widget-list wu-striped wu-m-0 wu--mt-2 wu--mb-3 wu--mx-3',
'field_wrapper_classes' => 'wu-w-full wu-box-border wu-items-center wu-flex wu-justify-between wu-px-6 wu-py-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',
));
if (wu_request('manual')) {
wu_get_template('wizards/host-integrations/configuration-results', array(
'screen' => get_current_screen(),
'page' => $this,
'integration' => $this->integration,
'form' => $form,
'post' => $_GET['post'],
));
return;
} // end if;
wu_get_template('wizards/host-integrations/configuration', array(
'screen' => get_current_screen(),
'page' => $this,
'integration' => $this->integration,
'form' => $form,
));
} // end section_configuration;
/**
* Displays the content of the final section.
*
* @since 2.0.0
* @return void
*/
public function section_ready() {
wu_get_template('wizards/host-integrations/ready', array(
'screen' => get_current_screen(),
'page' => $this,
'integration' => $this->integration,
));
} // end section_ready;
/**
* Handles the activation of a given integration.
*
* @since 2.0.0
* @return void
*/
public function handle_activation() {
$is_enabled = $this->integration->is_enabled();
if ($is_enabled) {
$this->integration->disable();
return;
} // end if;
$this->integration->enable();
wp_redirect($this->get_next_section_link());
exit;
} // end handle_activation;
/**
* Handles the configuration of a given integration.
*
* @since 2.0.0
* @return void
*/
public function handle_configuration() {
if (wu_request('submit') == '0') { // phpcs:ignore
$redirect_url = add_query_arg(array(
'manual' => '1',
'post' => $_POST,
));
wp_redirect($redirect_url);
exit;
} // end if;
if (wu_request('submit') == '1') { // phpcs:ignore
$this->integration->setup_constants($_POST);
} // end if;
$redirect_url = $this->get_next_section_link();
$redirect_url = remove_query_arg('post', $redirect_url);
$redirect_url = remove_query_arg('manual', $redirect_url);
wp_redirect($redirect_url);
exit;
} // end handle_configuration;
/**
* Handles the testing of a given configuration.
*
* @todo Move Vue to a scripts management class.
* @since 2.0.0
* @return void
*/
public function section_test() {
wp_enqueue_script('wu-vue');
wu_get_template('wizards/host-integrations/test', array(
'screen' => get_current_screen(),
'page' => $this,
'integration' => $this->integration,
));
} // end section_test;
} // end class Hosting_Integration_Wizard_Admin_Page;

View File

@ -0,0 +1,364 @@
<?php
/**
* WP Ultimo Customize/Add New Invoice Template Page.
*
* @package WP_Ultimo
* @subpackage Admin_Pages
* @since 2.0.0
*/
namespace WP_Ultimo\Admin_Pages;
use \WP_Ultimo\Invoices\Invoice;
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* WP Ultimo Invoice Template Customize/Add New Admin Page.
*/
class Invoice_Template_Customize_Admin_Page extends Customizer_Admin_Page {
/**
* Holds the ID for this page, this is also used as the page slug.
*
* @var string
*/
protected $id = 'wp-ultimo-customize-invoice-template';
/**
* Is this a top-level menu or a submenu?
*
* @since 1.8.2
* @var string
*/
protected $type = 'submenu';
/**
* Object ID being customizeed.
*
* @since 1.8.2
* @var string
*/
public $object_id = 'invoice_template';
/**
* 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-settings';
/**
* 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 = array(
'network_admin_menu' => 'wu_customize_invoice_template',
);
/**
* Overrides the original init to add the required ajax endpoints.
*
* @since 2.0.0
* @return void
*/
public function init() {
parent::init();
add_action('wp_ajax_wu-preview-invoice', array($this, 'generate_invoice_preview'));
} // end init;
/**
* Ajax endpoint to generate the Ajax Preview.
*
* @since 2.0.0
* @return void
*/
public function generate_invoice_preview() {
if (!current_user_can('wu_manage_invoice')) {
return;
} // end if;
$order = false;
$payment = wu_mock_payment();
$invoice = new Invoice($payment, $_REQUEST);
$invoice->print_file();
die;
} // end generate_invoice_preview;
/**
* Returns the preview URL. This is then added to the iframe.
*
* @since 2.0.0
* @return string
*/
public function get_preview_url() {
$url = get_admin_url(wu_get_main_site_id(), 'admin-ajax.php');
return add_query_arg(array(
'action' => 'wu-preview-invoice',
'customizer' => 1,
'invoice-customize' => 1
), $url);
} // end get_preview_url;
/**
* Allow child classes to register widgets, if they need them.
*
* @since 1.8.2
* @return void
*/
public function register_widgets() {
$settings = Invoice::get_settings();
$this->add_save_widget('save', array(
'fields' => array(
'note' => array(
'type' => 'note',
'desc' => __('Changes to this template will be applied to all PDF invoices generated after the change. <br><br>Existing PDF Invoices will not be affected unless explicitly re-generated', 'wp-ultimo'),
),
)
));
$custom_logo = wu_get_isset($settings, 'custom_logo');
$custom_logo_args = wp_get_attachment_image_src($custom_logo, 'full');
$custom_logo_url = $custom_logo_args ? $custom_logo_args[0] : '';
$fields = array(
'tab' => array(
'type' => 'tab-select',
'wrapper_classes' => '',
'wrapper_html_attr' => array(
'v-cloak' => 1,
),
'html_attr' => array(
'v-model' => 'tab',
),
'options' => array(
'general' => __('General', 'wp-ultimo'),
'colors' => __('Colors', 'wp-ultimo'),
'images' => __('Images', 'wp-ultimo'),
),
),
'paid_tag_text' => array(
'type' => 'text',
'title' => __('Paid Tag', 'wp-ultimo'),
'placeholder' => __('e.g. Paid.', 'wp-ultimo'),
'value' => wu_get_isset($settings, 'paid_tag_text', __('Paid', 'wp-ultimo')),
'wrapper_html_attr' => array(
'v-show' => 'require("tab", "general")',
'v-cloak' => 1,
),
'html_attr' => array(
'v-model.lazy' => 'paid_tag_text',
),
),
'font' => array(
'type' => 'select',
'title' => __('Font-Family', 'wp-ultimo'),
'value' => wu_get_isset($settings, 'font', ''),
'options' => array(
'DejaVuSansCondensed' => __('Sans-Serif', 'wp-ultimo'),
'FreeSerif' => __('Serif', 'wp-ultimo'),
'FreeMono' => __('Mono', 'wp-ultimo'),
),
'wrapper_html_attr' => array(
'v-show' => 'require("tab", "general")',
'v-cloak' => 1,
),
'html_attr' => array(
'v-model.lazy' => 'font',
),
),
'footer_message' => array(
'type' => 'textarea',
'title' => __('Footer Content', 'wp-ultimo'),
'placeholder' => __('e.g. Extra Info about the Invoice.', 'wp-ultimo'),
'value' => wu_get_isset($settings, 'footer_message', ''),
'wrapper_html_attr' => array(
'v-show' => 'require("tab", "general")',
'v-cloak' => 1,
),
'html_attr' => array(
'v-model.lazy' => 'footer_message',
),
),
'primary_color' => array(
'type' => 'color-picker',
'title' => __('Primary Color', 'wp-ultimo'),
'value' => '#00a1ff',
'wrapper_html_attr' => array(
'v-show' => 'require("tab", "colors")',
'v-cloak' => 1,
),
'html_attr' => array(
'v-model' => 'primary_color',
),
),
'use_custom_logo' => array(
'type' => 'toggle',
'title' => __('Use Custom Logo', 'wp-ultimo'),
'desc' => __('You can set a different logo to be used on the invoice.', 'wp-ultimo'),
'wrapper_html_attr' => array(
'v-show' => 'require("tab", "images")',
'v-cloak' => 1,
),
'html_attr' => array(
'v-model' => 'use_custom_logo',
),
),
'custom_logo' => array(
'type' => 'image',
'title' => __('Custom Logo', 'wp-ultimo'),
'desc' => __('This will be added to the top of the generated PDF.', 'wp-ultimo'),
'value' => '',
'img' => $custom_logo_url,
'stacked' => true,
'wrapper_html_attr' => array(
'v-show' => 'require("tab", "images") && require("use_custom_logo", true)',
'v-cloak' => 1,
),
'html_attr' => array(
'v-model' => 'custom_logo',
),
),
);
$settings = array(
'footer_message' => wu_get_isset($settings, 'footer_message', ''),
'paid_tag_text' => wu_get_isset($settings, 'paid_tag_text', __('Paid', 'wp-ultimo')),
'primary_color' => wu_get_isset($settings, 'primary_color', '00a1ff'),
'use_custom_logo' => wu_get_isset($settings, 'use_custom_logo'),
'custom_logo' => wu_get_isset($settings, 'custom_logo'),
'font' => wu_get_isset($settings, 'font', 'DejaVuSansCondensed'),
);
$state = array_merge($settings, array(
'tab' => 'general',
'refresh' => true,
));
$this->add_fields_widget('customizer', array(
'title' => __('Customizer', 'wp-ultimo'),
'position' => 'side',
'fields' => $fields,
'html_attr' => array(
'style' => 'margin-top: -6px;',
'data-wu-app' => 'invoice_customizer',
'data-wu-customizer-panel' => true,
'data-state' => json_encode($state),
),
));
} // end register_widgets;
/**
* Returns the title of the page.
*
* @since 2.0.0
* @return string Title of the page.
*/
public function get_title() {
return __('Customize Invoice Template', 'wp-ultimo');
} // end get_title;
/**
* 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 __('Customize Invoice Template', 'wp-ultimo');
} // end get_menu_title;
/**
* Returns the action links for that page.
*
* @since 1.8.2
* @return array
*/
public function action_links() {
return array();
} // end action_links;
/**
* Returns the labels to be used on the admin page.
*
* @since 2.0.0
* @return array
*/
public function get_labels() {
return array(
'customize_label' => __('Customize Invoice Template', 'wp-ultimo'),
'add_new_label' => __('Customize Invoice Template', 'wp-ultimo'),
'edit_label' => __('Edit Invoice Template', 'wp-ultimo'),
'updated_message' => __('Invoice Template updated with success!', 'wp-ultimo'),
'title_placeholder' => __('Enter Invoice Template Name', 'wp-ultimo'),
'title_description' => __('This name is used for internal reference only.', 'wp-ultimo'),
'save_button_label' => __('Save Invoice Template', 'wp-ultimo'),
'save_description' => __('Save Invoice Template', 'wp-ultimo'),
);
} // end get_labels;
/**
* Should implement the processes necessary to save the changes made to the object.
*
* @since 2.0.0
* @return void
*/
public function handle_save() {
Invoice::save_settings($_POST);
$url = add_query_arg('updated', '1');
wp_redirect($url);
exit;
} // end handle_save;
} // end class Invoice_Template_Customize_Admin_Page;

View File

@ -0,0 +1,169 @@
<?php
/**
* WP Ultimo Jobs Admin Page.
*
* @package WP_Ultimo
* @subpackage Admin_Pages
* @since 2.0.0
*/
namespace WP_Ultimo\Admin_Pages;
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* WP Ultimo Jobs Admin Page.
*/
class Jobs_List_Admin_Page extends Base_Admin_Page {
/**
* Holds the ID for this page, this is also used as the page slug.
*
* @var string
*/
protected $id = 'wp-ultimo-jobs';
/**
* Is this a top-level menu or a submenu?
*
* @since 1.8.2
* @var string
*/
protected $type = 'submenu';
/**
* If this is a submenu, we need a parent menu to attach this to
*
* @since 1.8.2
* @var string
*/
protected $parent = 'none';
/**
* Allows us to highlight another menu page, if this page has no parent page at all.
*
* @since 2.0.0
* @var boolean
*/
protected $highlight_menu_slug = 'wp-ultimo-settings';
/**
* 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;
/**
* 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 = array(
'network_admin_menu' => 'wu_read_jobs',
);
/**
* Overrides the init method to add additional hooks.
*
* @since 2.0.0
* @return void
*/
public function init() {
parent::init();
add_filter('action_scheduler_admin_view_class', array($this, 'hide_as_admin_page'), 9999, 1);
} // end init;
/**
* Hide the Action Scheduler admin page on sub-sites.
*
* @since 2.0.0
*
* @param string $admin_view_class Admin View class name.
* @return string
*/
public function hide_as_admin_page($admin_view_class) {
if (is_network_admin() || class_exists('WooCommerce')) {
return $admin_view_class;
} // end if;
return '\WP_Ultimo\Compat\AS_Admin_View';
} // end hide_as_admin_page;
/**
* Returns the title of the page.
*
* @since 2.0.0
* @return string Title of the page.
*/
public function get_title() {
return __('Jobs', 'wp-ultimo');
} // end get_title;
/**
* 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 __('Jobs', 'wp-ultimo');
} // end get_menu_title;
/**
* Allows admins to rename the sub-menu (first item) for a top-level page.
*
* @since 2.0.0
* @return string False to use the title menu or string with sub-menu title.
*/
public function get_submenu_title() {
return __('Jobs', 'wp-ultimo');
} // end get_submenu_title;
/**
* Runs the hooks for the admin list table.
*
* Required for searched to work as intended.
*
* @since 2.0.10
* @return void
*/
public function page_loaded() {
\ActionScheduler_AdminView::instance()->process_admin_ui();
} // end page_loaded;
/**
* Calls the Action Scheduler renderer.
*
* @since 2.0.0
* @return void
*/
public function output() {
\ActionScheduler_AdminView::instance()->render_admin_ui();
} // end output;
} // end class Jobs_List_Admin_Page;

View File

@ -0,0 +1,245 @@
<?php
/**
* Base admin page class.
*
* Abstract class that makes it easy to create new admin pages.
*
* Most of WP Ultimo pages are implemented using this class, which means that the filters and hooks
* listed below can be used to append content to all of our pages at once.
*
* @package WP_Ultimo
* @subpackage Admin_Pages
* @since 2.0.0
*/
namespace WP_Ultimo\Admin_Pages;
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Abstract class that makes it easy to create new admin pages.
*/
abstract class List_Admin_Page extends Base_Admin_Page {
/**
* @var bool
*/
public $has_search;
/**
* The id/name/slug of the object being edited/created. e.g: plan
*
* @since 1.8.2
* @var object
*/
protected $object_id;
/**
* Keep the labels
*
* @since 1.8.2
* @var array
*/
protected $labels = array();
/**
* Holds the WP_List_Table instance to be used on the list
*
* @since 1.8.2
* @var WP_List_Table
*/
protected $table;
/**
* Sets the default labels and get the object
*
* @since 1.8.2
* @return void
*/
public function page_loaded() {
/**
* Loads the list table
*/
$this->table = $this->table();
/**
* Gets the base labels
*/
$this->labels = $this->get_labels();
/**
* Loads if we need to get the search
*/
$this->has_search = $this->has_search();
/**
* Get the action links
*/
$this->action_links = $this->action_links();
/**
* Adds the process for process actions
*/
$this->process_single_action();
} // end page_loaded;
/**
* Initializes the class
*
* @since 1.8.2
* @return void
*/
public function init() {
/**
* Runs the parent init functions
*/
parent::init();
add_filter('set-screen-option', array($this, 'save_screen_option'), 8, 3);
} // end init;
/**
* Process lins actions of the tables
*
* @since 1.8.2
* @return void
*/
public function process_single_action() {
if ($this->table) {
$this->table->process_single_action();
} // end if;
} // end process_single_action;
/**
* Returns an array with the labels for the edit page.
*
* @since 1.8.2
* @return array
*/
public function get_labels() {
return array(
'deleted_message' => __('Object removed successfully.', 'wp-ultimo'),
'search_label' => __('Search Object', 'wp-ultimo'),
);
} // end get_labels;
/**
* Allow child classes to register scripts and styles that can be loaded on the output function, for example.
*
* @since 1.8.2
* @return void
*/
public function register_scripts() {
parent::register_scripts();
wp_enqueue_script('wu-vue-apps');
wp_enqueue_script('wu-fields');
wp_enqueue_style('wp-color-picker');
wp_enqueue_script('wu-selectizer');
} // end register_scripts;
/**
* Sets the default list template
*
* @since 1.8.2
* @return void
*/
public function output() {
/**
* Renders the base list page layout, with the columns and everything else =)
*/
wu_get_template('base/list', array(
'page' => $this,
'table' => $this->get_table(),
'classes' => $this->table->get_filters() ? 'wu-advanced-filters' : 'wu-no-advanced-filters',
));
} // end output;
/**
* Child classes can to implement to hide the search field
*
* @since 1.8.2
* @return boolean
*/
public function has_search() {
return true;
} // end has_search;
/**
* Set the screen options to allow users to set the pagination options of the subscriptions list
*
* @since 1.8.2
* @return void
*/
public function screen_options() {
if ($this->table) {
$args = array(
'default' => 20,
'label' => $this->table->get_per_page_option_label(),
'option' => $this->table->get_per_page_option_name(),
);
add_screen_option('per_page', $args);
} // end if;
} // end screen_options;
/**
* Tells WordPress we want to save screen options on our pages.
*
* @since 2.0.0
*
* @param mixed $value Value being saved.
* @param string $option Name of the option. This is usually a per_page.
* @param string $other_value Not sure, haha.
* @return bool
*/
public function save_screen_option($value, $option, $other_value) {
return $value === false && is_numeric($other_value) ? (int) $other_value : $value;
} // end save_screen_option;
/**
* Dumb function. Child classes need to implement this to set the table that WP Ultimo will use
*
* @since 1.8.2
* @return WP_List_Table
*/
public function get_table() {
return $this->table;
} // end get_table;
/**
* Loads the list table for this particular page.
*
* @since 2.0.0
* @return \WP_Ultimo\List_Tables\Base_List_Table
*/
abstract function table();
} // end class List_Admin_Page;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,330 @@
<?php
/**
* WP Ultimo Membership 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\Models\Membership;
use \WP_Ultimo\Database\Memberships\Membership_Status;
/**
* WP Ultimo Membership Admin Page.
*/
class Membership_List_Admin_Page extends List_Admin_Page {
/**
* Holds the ID for this page, this is also used as the page slug.
*
* @var string
*/
protected $id = 'wp-ultimo-memberships';
/**
* Is this a top-level menu or a submenu?
*
* @since 1.8.2
* @var string
*/
protected $type = 'submenu';
/**
* 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;
/**
* 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 = array(
'network_admin_menu' => 'wu_read_memberships',
);
/**
* Register ajax forms to handle adding new memberships.
*
* @since 2.0.0
* @return void
*/
public function register_forms() {
/*
* Add new Membership
*/
wu_register_form('add_new_membership', array(
'render' => array($this, 'render_add_new_membership_modal'),
'handler' => array($this, 'handle_add_new_membership_modal'),
'capability' => 'wu_edit_memberships',
));
} // end register_forms;
/**
* Renders the add new customer modal.
*
* @since 2.0.0
* @return void
*/
public function render_add_new_membership_modal() {
$fields = array(
'customer_id' => array(
'type' => 'model',
'title' => __('Customer', 'wp-ultimo'),
'placeholder' => __('Search Customer...', 'wp-ultimo'),
'desc' => __('The customer to attach this membership to.', 'wp-ultimo'),
'html_attr' => array(
'data-model' => 'customer',
'data-value-field' => 'id',
'data-label-field' => 'display_name',
'data-search-field' => 'display_name',
'data-max-items' => 1,
),
),
'product_ids' => array(
'type' => 'model',
'title' => __('Products', 'wp-ultimo'),
'placeholder' => __('Search Products...', 'wp-ultimo'),
'desc' => __('You can add multiples products to this membership.', 'wp-ultimo'),
'tooltip' => '',
'html_attr' => array(
'data-model' => 'product',
'data-value-field' => 'id',
'data-label-field' => 'name',
'data-search-field' => 'name',
'data-max-items' => 99,
),
),
'status' => array(
'type' => 'select',
'title' => __('Status', 'wp-ultimo'),
'placeholder' => __('Status', 'wp-ultimo'),
'desc' => __('The membership status.', 'wp-ultimo'),
'tooltip' => '',
'value' => Membership_Status::PENDING,
'options' => Membership_Status::to_array(),
),
'lifetime' => array(
'type' => 'toggle',
'title' => __('Lifetime', 'wp-ultimo'),
'desc' => __('Activate this toggle to mark the newly created membership as lifetime.', 'wp-ultimo'),
'value' => 1,
'html_attr' => array(
'v-model' => 'lifetime',
),
),
'date_expiration' => array(
'title' => __('Expiration Date', 'wp-ultimo'),
'desc' => __('Set the expiration date of the membership to be created.', 'wp-ultimo'),
'type' => 'text',
'date' => true,
'value' => gmdate('Y-m-d', strtotime('+1 month')),
'placeholder' => '2020-04-04',
'html_attr' => array(
'wu-datepicker' => 'true',
'data-format' => 'Y-m-d',
'data-allow-time' => 'false',
),
'wrapper_html_attr' => array(
'v-show' => '!lifetime',
'v-cloak' => 1,
),
),
'submit_button' => array(
'type' => 'submit',
'title' => __('Create Membership', 'wp-ultimo'),
'value' => 'save',
'classes' => 'button button-primary wu-w-full',
'wrapper_classes' => 'wu-items-end',
),
);
$form = new \WP_Ultimo\UI\Form('add_new_membership', $fields, array(
'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' => array(
'data-wu-app' => 'add_new_membership',
'data-on-load' => 'wu_initialize_datepickers',
'data-state' => wu_convert_to_state(array(
'lifetime' => 1
)),
),
));
$form->render();
} // end render_add_new_membership_modal;
/**
* Handles creation of a new memberships.
*
* @since 2.0.0
* @return void
*/
public function handle_add_new_membership_modal() {
global $wpdb;
$products = wu_request('product_ids', '');
$products = explode(',', (string) $products);
if (empty($products)) {
wp_send_json_error(new \WP_Error(
'empty-products',
__('Products can not be empty.', 'wp-ultimo')
));
} // end if;
$customer = wu_get_customer(wu_request('customer_id', 0));
if (empty($customer)) {
wp_send_json_error(new \WP_Error(
'customer-not-found',
__('The selected customer does not exist.', 'wp-ultimo')
));
} // end if;
$cart = new \WP_Ultimo\Checkout\Cart(array(
'products' => $products,
'country' => $customer->get_country(),
));
$data = $cart->to_membership_data();
$data['customer_id'] = $customer->get_id();
$data['status'] = wu_request('status');
$date_expiration = gmdate('Y-m-d 23:59:59', strtotime((string) wu_request('date_expiration')));
$maybe_lifetime = wu_request('lifetime');
if ($maybe_lifetime) {
$date_expiration = null;
} // end if;
$data['date_expiration'] = $date_expiration;
$membership = wu_create_membership($data);
if (is_wp_error($membership)) {
wp_send_json_error($membership);
} // end if;
wp_send_json_success(array(
'redirect_url' => wu_network_admin_url('wp-ultimo-edit-membership', array(
'id' => $membership->get_id(),
))
));
} // end handle_add_new_membership_modal;
/**
* Returns an array with the labels for the edit page.
*
* @since 1.8.2
* @return array
*/
public function get_labels() {
return array(
'deleted_message' => __('Membership removed successfully.', 'wp-ultimo'),
'search_label' => __('Search Membership', 'wp-ultimo'),
);
} // end get_labels;
/**
* Returns the title of the page.
*
* @since 2.0.0
* @return string Title of the page.
*/
public function get_title() {
return __('Memberships', 'wp-ultimo');
} // end get_title;
/**
* 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 __('Memberships', 'wp-ultimo');
} // end get_menu_title;
/**
* Allows admins to rename the sub-menu (first item) for a top-level page.
*
* @since 2.0.0
* @return string False to use the title menu or string with sub-menu title.
*/
public function get_submenu_title() {
return __('Memberships', 'wp-ultimo');
} // end get_submenu_title;
/**
* Returns the action links for that page.
*
* @since 1.8.2
* @return array
*/
public function action_links() {
return array(
array(
'label' => __('Add Membership'),
'icon' => 'wu-circle-with-plus',
'classes' => 'wubox',
'url' => wu_get_form_url('add_new_membership'),
),
);
} // end action_links;
/**
* Loads the list table for this particular page.
*
* @since 2.0.0
* @return \WP_Ultimo\List_Tables\Base_List_Table
*/
public function table() {
return new \WP_Ultimo\List_Tables\Membership_List_Table();
} // end table;
} // end class Membership_List_Admin_Page;

View File

@ -0,0 +1,181 @@
<?php
/**
* WP Ultimo Dashboard Admin Page.
*
* @package WP_Ultimo
* @subpackage Admin_Pages
* @since 2.0.24
*/
namespace WP_Ultimo\Admin_Pages;
// Exit if accessed directly
defined('ABSPATH') || exit;
use \WP_Ultimo\License;
use \WP_Ultimo\Installers\Migrator;
use \WP_Ultimo\Installers\Core_Installer;
use \WP_Ultimo\Installers\Default_Content_Installer;
use \WP_Ultimo\Logger;
/**
* WP Ultimo Dashboard Admin Page.
*/
class Migration_Alert_Admin_Page extends Wizard_Admin_Page {
/**
* Holds the ID for this page, this is also used as the page slug.
*
* @var string
*/
protected $id = 'wp-ultimo-migration-alert';
/**
* Is this a top-level menu or a submenu?
*
* @since 1.8.2
* @var string
*/
protected $type = 'submenu';
/**
* 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.24
* @var string
*/
protected $highlight_menu_slug = 'wp-ultimo-settings';
/**
* 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;
/**
* 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.24
* @var array
*/
protected $supported_panels = array(
'network_admin_menu' => 'manage_network',
);
/**
* Overrides original construct method.
*
* We need to override the construct method to make sure
* we make the necessary changes to the Wizard page when it's
* being run for the first time.
*
* @since 2.0.24
* @return void
*/
public function __construct() {
parent::__construct();
} // end __construct;
/**
* Returns the logo for the wizard.
*
* @since 2.0.24
* @return string
*/
public function get_logo() {
return wu_get_asset('logo.png', 'img');
} // end get_logo;
/**
* Returns the title of the page.
*
* @since 2.0.24
* @return string Title of the page.
*/
public function get_title(): string {
return sprintf(__('Migration', 'wp-ultimo'));
} // end get_title;
/**
* Returns the title of menu for this page.
*
* @since 2.0.24
* @return string Menu label of the page.
*/
public function get_menu_title() {
return WP_Ultimo()->is_loaded() ? __('WP Ultimo Migration Alert', 'wp-ultimo') : __('WP Ultimo', 'wp-ultimo');
} // end get_menu_title;
/**
* Returns the sections for this Wizard.
*
* @since 2.0.24
* @return array
*/
public function get_sections() {
return array(
'alert' => array(
'title' => __('Alert!', 'wp-ultimo'),
'view' => array($this, 'section_alert'),
'handler' => array($this, 'handle_proceed'),
),
);
} // end get_sections;
/**
* Displays the content of the final section.
*
* @since 2.0.24
* @return void
*/
public function section_alert() {
wu_get_template('wizards/setup/alert', array(
'screen' => get_current_screen(),
'page' => $this,
));
} // end section_alert;
/**
* Handles the proceed action.
*
* @since 2.0.24
* @return void
*/
public function handle_proceed() {
delete_network_option(null, 'wu_setup_finished');
delete_network_option(null, 'wu_is_migration_done');
wp_redirect(wu_network_admin_url('wp-ultimo-setup'));
exit;
} // end handle_proceed;
} // end class Migration_Alert_Admin_Page;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,292 @@
<?php
/**
* WP Ultimo Payment 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\Payments\Payment_Status;
/**
* WP Ultimo Payment Admin Page.
*/
class Payment_List_Admin_Page extends List_Admin_Page {
/**
* Holds the ID for this page, this is also used as the page slug.
*
* @var string
*/
protected $id = 'wp-ultimo-payments';
/**
* Is this a top-level menu or a submenu?
*
* @since 1.8.2
* @var string
*/
protected $type = 'submenu';
/**
* 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;
/**
* 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 = array(
'network_admin_menu' => 'wu_read_payments',
);
/**
* Register ajax forms that we use for payments.
*
* @since 2.0.0
* @return void
*/
public function register_forms() {
/*
* Edit/Add Line Item
*/
wu_register_form('add_new_payment', array(
'render' => array($this, 'render_add_new_payment_modal'),
'handler' => array($this, 'handle_add_new_payment_modal'),
'capability' => 'wu_edit_payments',
));
} // end register_forms;
/**
* Renders the add/edit line items form.
*
* @since 2.0.0
* @return void
*/
public function render_add_new_payment_modal() {
$fields = array(
'products' => array(
'type' => 'model',
'title' => __('Products', 'wp-ultimo'),
'placeholder' => __('Search Products...', 'wp-ultimo'),
'desc' => __('Each product will be added as a line item.', 'wp-ultimo'),
'value' => '',
'tooltip' => '',
'html_attr' => array(
'data-model' => 'product',
'data-value-field' => 'id',
'data-label-field' => 'name',
'data-search-field' => 'name',
'data-max-items' => 10,
),
),
'status' => array(
'type' => 'select',
'title' => __('Status', 'wp-ultimo'),
'placeholder' => __('Status', 'wp-ultimo'),
'desc' => __('The payment status to attach to the newly created payment.', 'wp-ultimo'),
'value' => Payment_Status::COMPLETED,
'options' => Payment_Status::to_array(),
'tooltip' => '',
),
'membership_id' => array(
'type' => 'model',
'title' => __('Membership', 'wp-ultimo'),
'placeholder' => __('Search Membership...', 'wp-ultimo'),
'desc' => __('The membership associated with this payment.', 'wp-ultimo'),
'value' => '',
'tooltip' => '',
'html_attr' => array(
'data-model' => 'membership',
'data-value-field' => 'id',
'data-label-field' => 'reference_code',
'data-max-items' => 1,
'data-selected' => '',
),
),
'add_setup_fees' => array(
'type' => 'toggle',
'title' => __('Include Setup Fees', 'wp-ultimo'),
'desc' => __('Checking this box will include setup fees attached to the selected products as well.', 'wp-ultimo'),
'value' => 1,
),
'submit_button' => array(
'type' => 'submit',
'title' => __('Add Payment', 'wp-ultimo'),
'value' => 'save',
'classes' => 'wu-w-full button button-primary',
'wrapper_classes' => 'wu-items-end',
),
);
$form = new \WP_Ultimo\UI\Form('add_payment', $fields, array(
'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' => array(
'data-wu-app' => 'add_payment',
'data-state' => wu_convert_to_state(array(
'taxable' => 0,
'type' => 'product',
)),
),
));
$form->render();
} // end render_add_new_payment_modal;
/**
* Handles the add/edit of line items.
*
* @since 2.0.0
* @return mixed
*/
public function handle_add_new_payment_modal() {
$membership = wu_get_membership(wu_request('membership_id'));
if (!$membership) {
$error = new \WP_Error('invalid-membership', __('Invalid membership.', 'wp-ultimo'));
return wp_send_json_error($error);
} // end if;
$cart = new \WP_Ultimo\Checkout\Cart(array(
'products' => explode(',', (string) wu_request('products')),
'cart_type' => wu_request('add_setup_fees') ? 'new' : 'renewal',
));
$payment_data = array_merge($cart->to_payment_data(), array(
'status' => wu_request('status'),
'membership_id' => $membership->get_id(),
'customer_id' => $membership->get_customer_id(),
));
$payment = wu_create_payment($payment_data);
if (is_wp_error($payment)) {
return wp_send_json_error($payment);
} // end if;
wp_send_json_success(array(
'redirect_url' => wu_network_admin_url('wp-ultimo-edit-payment', array(
'id' => $payment->get_id(),
))
));
} // end handle_add_new_payment_modal;
/**
* Allow child classes to register widgets, if they need them.
*
* @since 1.8.2
* @return void
*/
public function register_widgets() {} // end register_widgets;
/**
* Returns an array with the labels for the edit page.
*
* @since 1.8.2
* @return array
*/
public function get_labels() {
return array(
'deleted_message' => __('Payment removed successfully.', 'wp-ultimo'),
'search_label' => __('Search Payment', 'wp-ultimo'),
);
} // end get_labels;
/**
* Returns the title of the page.
*
* @since 2.0.0
* @return string Title of the page.
*/
public function get_title() {
return __('Payments', 'wp-ultimo');
} // end get_title;
/**
* 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 __('Payments', 'wp-ultimo');
} // end get_menu_title;
/**
* Allows admins to rename the sub-menu (first item) for a top-level page.
*
* @since 2.0.0
* @return string False to use the title menu or string with sub-menu title.
*/
public function get_submenu_title() {
return __('Payments', 'wp-ultimo');
} // end get_submenu_title;
/**
* Returns the action links for that page.
*
* @since 1.8.2
* @return array
*/
public function action_links() {
return array(
array(
'label' => __('Add Payment', 'wp-ultimo'),
'icon' => 'wu-circle-with-plus',
'classes' => 'wubox',
'url' => wu_get_form_url('add_new_payment'),
),
);
} // end action_links;
/**
* Loads the list table for this particular page.
*
* @since 2.0.0
* @return \WP_Ultimo\List_Tables\Base_List_Table
*/
public function table() {
return new \WP_Ultimo\List_Tables\Payment_List_Table();
} // end table;
} // end class Payment_List_Admin_Page;

View File

@ -0,0 +1,145 @@
<?php
/**
* WP Ultimo About Admin Page.
*
* @package WP_Ultimo
* @subpackage Admin_Pages
* @since 2.0.0
*/
namespace WP_Ultimo\Admin_Pages;
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* WP Ultimo About Admin Page.
*/
class Placeholders_Admin_Page extends Base_Admin_Page {
/**
* Holds the ID for this page, this is also used as the page slug.
*
* @var string
*/
protected $id = 'wp-ultimo-template-placeholders';
/**
* Is this a top-level menu or a submenu?
*
* @since 1.8.2
* @var string
*/
protected $type = 'submenu';
/**
* 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-settings';
/**
* 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 = array(
'network_admin_menu' => 'manage_network',
);
/**
* Returns the title of the page.
*
* @since 2.0.0
* @return string Title of the page.
*/
public function get_title() {
return __('Edit Template Placeholders', 'wp-ultimo');
} // end get_title;
/**
* 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 Template Placeholders', 'wp-ultimo');
} // end get_menu_title;
/**
* Allows admins to rename the sub-menu (first item) for a top-level page.
*
* @since 2.0.0
* @return string False to use the title menu or string with sub-menu title.
*/
public function get_submenu_title() {
return __('Edit Template Placeholders', 'wp-ultimo');
} // end get_submenu_title;
/**
* Every child class should implement the output method to display the contents of the page.
*
* @since 1.8.2
* @return void
*/
public function output() {
do_action('wu_load_edit_placeholders_list_page');
$columns = apply_filters('wu_edit_placeholders_columns', array(
'placeholder' => __('Placeholder', 'wp-ultimo'),
'content' => __('Content', 'wp-ultimo'),
));
wu_get_template('sites/edit-placeholders', array(
'columns' => $columns,
'types' => array(),
));
} // end output;
/**
* Adds the cure bg image here as well.
*
* @since 2.0.0
* @return void
*/
public function register_scripts() {
parent::register_scripts();
wp_register_script('wu-edit-placeholders', wu_get_asset('edit-placeholders.js', 'js'), array('wu-admin', 'wu-vue', 'underscore'), wu_get_version(), false);
wp_localize_script('wu-edit-placeholders', 'wu_placeholdersl10n', array(
'name' => __('Tax', 'wp-ultimo'),
'confirm_message' => __('Are you sure you want to delete this rows?', 'wp-ultimo'),
'confirm_delete_tax_category_message' => __('Are you sure you want to delete this tax category?', 'wp-ultimo'),
));
wp_enqueue_script('wu-edit-placeholders');
} // end register_scripts;
} // end class Placeholders_Admin_Page;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,146 @@
<?php
/**
* WP Ultimo Product Admin Page.
*
* @package WP_Ultimo
* @subpackage Admin_Pages
* @since 2.0.0
*/
namespace WP_Ultimo\Admin_Pages;
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* WP Ultimo Product Admin Page.
*/
class Product_List_Admin_Page extends List_Admin_Page {
/**
* Holds the ID for this page, this is also used as the page slug.
*
* @var string
*/
protected $id = 'wp-ultimo-products';
/**
* Is this a top-level menu or a submenu?
*
* @since 1.8.2
* @var string
*/
protected $type = 'submenu';
/**
* 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;
/**
* 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 = array(
'network_admin_menu' => 'wu_read_products',
);
/**
* Allow child classes to register widgets, if they need them.
*
* @since 1.8.2
* @return void
*/
public function hooks() {} // end hooks;
/**
* Returns an array with the labels for the edit page.
*
* @since 1.8.2
* @return array
*/
public function get_labels() {
return array(
'deleted_message' => __('Product removed successfully.', 'wp-ultimo'),
'search_label' => __('Search Product', 'wp-ultimo'),
);
} // end get_labels;
/**
* Returns the title of the page.
*
* @since 2.0.0
* @return string Title of the page.
*/
public function get_title() {
return __('Products', 'wp-ultimo');
} // end get_title;
/**
* 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 __('Products', 'wp-ultimo');
} // end get_menu_title;
/**
* Allows admins to rename the sub-menu (first item) for a top-level page.
*
* @since 2.0.0
* @return string False to use the title menu or string with sub-menu title.
*/
public function get_submenu_title() {
return __('Products', 'wp-ultimo');
} // end get_submenu_title;
/**
* Returns the action links for that page.
*
* @since 1.8.2
* @return array
*/
public function action_links() {
return array(
array(
'url' => wu_network_admin_url('wp-ultimo-edit-product'),
'label' => __('Add Product'),
'icon' => 'wu-circle-with-plus',
),
);
} // end action_links;
/**
* Loads the list table for this particular page.
*
* @since 2.0.0
* @return \WP_Ultimo\List_Tables\Base_List_Table
*/
public function table() {
return new \WP_Ultimo\List_Tables\Product_List_Table();
} // end table;
} // end class Product_List_Admin_Page;

View File

@ -0,0 +1,170 @@
<?php
/**
* WP Ultimo Rollback Admin Page.
*
* @package WP_Ultimo
* @subpackage Admin_Pages
* @since 2.0.0
*/
namespace WP_Ultimo\Admin_Pages;
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* WP Ultimo Rollback Admin Page.
*/
class Rollback_Admin_Page extends Base_Admin_Page {
/**
* Holds the ID for this page, this is also used as the page slug.
*
* @var string
*/
protected $id = 'wp-ultimo-rollback';
/**
* Is this a top-level menu or a submenu?
*
* @since 1.8.2
* @var string
*/
protected $type = 'submenu';
/**
* 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-settings';
/**
* Should we hide admin notices on this page?
*
* @since 2.0.0
* @var boolean
*/
protected $hide_admin_notices = true;
/**
* Should we force the admin menu into a folded state?
*
* @since 2.0.0
* @var boolean
*/
protected $fold_menu = 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 = array(
'network_admin_menu' => 'manage_network',
);
/**
* Creates the page with the necessary hooks.
*
* @since 1.8.2
*/
public function __construct() {
if (WP_Ultimo()->is_loaded() === false) {
$this->highlight_menu_slug = 'wp-ultimo-setup';
} // end if;
parent::__construct();
} // end __construct;
/**
* Returns the title of the page.
*
* @since 2.0.0
* @return string Title of the page.
*/
public function get_title() {
return __('Rollback', 'wp-ultimo');
} // end get_title;
/**
* 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 __('Rollback', 'wp-ultimo');
} // end get_menu_title;
/**
* Allows admins to rename the sub-menu (first item) for a top-level page.
*
* @since 2.0.0
* @return string False to use the title menu or string with sub-menu title.
*/
public function get_submenu_title() {
return __('Rollback', 'wp-ultimo');
} // end get_submenu_title;
/**
* Registers the necessary scripts.
*
* @since 2.0.0
* @return void
*/
public function register_scripts() {
/*
* If Ultimo is not yet loaded, we need to register vue.
*/
if (WP_Ultimo()->is_loaded() === false) {
wp_register_script('wu-vue', wu_get_asset('lib/vue.js', 'js'), false, wu_get_version());
} // end if;
wp_enqueue_script('wu-vue');
} // end register_scripts;
/**
* Every child class should implement the output method to display the contents of the page.
*
* @since 1.8.2
* @return void
*/
public function output() {
wu_get_template('rollback/rollback', array(
'n' => \WP_Ultimo\License::get_instance()->get_license_key(),
'versions' => \WP_Ultimo\Rollback\Rollback::get_instance()->get_available_versions(),
'page' => $this,
));
} // end output;
} // end class Rollback_Admin_Page;

View File

@ -0,0 +1,751 @@
<?php
/**
* WP Ultimo Dashboard Admin Page.
*
* @package WP_Ultimo
* @subpackage Admin_Pages
* @since 2.0.0
*/
namespace WP_Ultimo\Admin_Pages;
use \WP_Ultimo\Settings;
use \WP_Ultimo\UI\Form;
use \WP_Ultimo\UI\Field;
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* WP Ultimo Dashboard Admin Page.
*/
class Settings_Admin_Page extends Wizard_Admin_Page {
/**
* Holds the ID for this page, this is also used as the page slug.
*
* @var string
*/
protected $id = 'wp-ultimo-settings';
/**
* Is this a top-level menu or a submenu?
*
* @since 1.8.2
* @var string
*/
protected $type = 'submenu';
/**
* Dashicon to be used on the menu item. This is only used on top-level menus
*
* @since 1.8.2
* @var string
*/
protected $menu_icon = 'dashicons-wu-wp-ultimo';
/**
* 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;
/**
* 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 = array(
'network_admin_menu' => 'wu_read_settings',
);
/**
* Should we hide admin notices on this page?
*
* @since 2.0.0
* @var boolean
*/
protected $hide_admin_notices = false;
/**
* Should we force the admin menu into a folded state?
*
* @since 2.0.0
* @var boolean
*/
protected $fold_menu = false;
/**
* Holds the section slug for the URLs.
*
* @since 2.0.0
* @var string
*/
protected $section_slug = 'tab';
/**
* Defines if the step links on the side are clickable or not.
*
* @since 2.0.0
* @var boolean
*/
protected $clickable_navigation = true;
/**
* Allow child classes to register scripts and styles that can be loaded on the output function, for example.
*
* @since 1.8.2
* @return void
*/
public function register_scripts() {
wp_enqueue_editor();
parent::register_scripts();
/*
* Adds Vue.
*/
wp_enqueue_script('wu-vue-apps');
wp_enqueue_script('wu-fields');
wp_enqueue_style('wp-color-picker');
} // end register_scripts;
/**
* Registers widgets to the edit page.
*
* This implementation register the default save widget.
* Child classes that wish to inherit that widget while registering other,
* can do such by adding a parent::register_widgets() to their own register_widgets() method.
*
* @since 2.0.0
* @return void
*/
public function register_widgets() {
parent::register_widgets();
wu_register_settings_side_panel('general', array(
'title' => __('Add-ons', 'wp-ultimo'),
'render' => array($this, 'render_addons_side_panel'),
));
wu_register_settings_side_panel('login-and-registration', array(
'title' => __('Checkout Forms', 'wp-ultimo'),
'render' => array($this, 'render_checkout_forms_side_panel'),
));
wu_register_settings_side_panel('integrations', array(
'title' => __('Add-ons', 'wp-ultimo'),
'render' => array($this, 'render_addons_side_panel'),
));
wu_register_settings_side_panel('sites', array(
'title' => __('Template Previewer', 'wp-ultimo'),
'render' => array($this, 'render_site_template_side_panel'),
));
wu_register_settings_side_panel('sites', array(
'title' => __('Placeholder Editor', 'wp-ultimo'),
'render' => array($this, 'render_site_placeholders_side_panel'),
));
wu_register_settings_side_panel('payment-gateways', array(
'title' => __('Invoices', 'wp-ultimo'),
'render' => array($this, 'render_invoice_side_panel'),
));
wu_register_settings_side_panel('payment-gateways', array(
'title' => __('Additional Gateways', 'wp-ultimo'),
'render' => array($this, 'render_gateways_addons_side_panel'),
));
wu_register_settings_side_panel('emails', array(
'title' => __('System Emails', 'wp-ultimo'),
'render' => array($this, 'render_system_emails_side_panel'),
));
wu_register_settings_side_panel('emails', array(
'title' => __('Email Template', 'wp-ultimo'),
'render' => array($this, 'render_email_template_side_panel'),
));
wu_register_settings_side_panel('all', array(
'title' => __('Your License', 'wp-ultimo'),
'render' => array($this, 'render_account_side_panel'),
'show' => array(\WP_Ultimo\License::get_instance(), 'is_not_whitelabel'),
));
} // end register_widgets;
// phpcs:disable
/**
* Renders the addons side panel
*
* @since 2.0.0
* @return void
*/
public function render_addons_side_panel() { ?>
<div class="wu-widget-inset">
<div class="wu-p-4">
<span class="wu-text-gray-700 wu-font-bold wu-uppercase wu-tracking-wide wu-text-xs">
<?php _e('WP Ultimo Add-ons', 'wp-ultimo'); ?>
</span>
<div class="wu-py-2">
<img class="wu-w-full" alt="<?php esc_attr_e('WP Ultimo Add-ons', 'wp-ultimo'); ?>" src="<?php echo wu_get_asset('sidebar/add-ons.png'); ?>">
</div>
<p class="wu-text-gray-600 wu-p-0 wu-m-0">
<?php _e('You can extend WP Ultimo\'s functionality by installing one of our add-ons!', 'wp-ultimo'); ?>
</p>
</div>
<div class="wu-p-4 wu-bg-gray-100 wu-border-solid wu-border-0 wu-border-t wu-border-gray-300">
<a class="button wu-w-full wu-text-center" href="<?php echo wu_network_admin_url('wp-ultimo-addons'); ?>">
<?php _e('Check our Add-ons &rarr;', 'wp-ultimo'); ?>
</a>
</div>
</div>
<?php
} // end render_addons_side_panel;
/**
* Renders the account side panel
*
* @since 2.0.0
* @return void
*/
public function render_account_side_panel() {
$customer = \WP_Ultimo\License::get_instance()->get_customer();
$license = \WP_Ultimo\License::get_instance()->get_license();
?>
<div class="wu-widget-inset">
<?php if (empty($customer) || empty($license)) : ?>
<div class="wu-p-4">
<span class="wu-p-2 wu-bg-red-100 wu-text-red-600 wu-rounded wu-block">
<?php _e('Your copy of WP Ultimo is not currently active. That means you will not have access to plugin updates and add-ons.', 'wp-ultimo'); ?>
</span>
</div>
<div class="wu-p-4 wu-bg-gray-100 wu-border-solid wu-border-0 wu-border-t wu-border-gray-300">
<a id="wu-activate-license-key-button" class="button wu-w-full wu-text-center wubox" title="<?php esc_attr_e('Activate WP Ultimo', 'wp-ultimo'); ?>" href="<?php echo wu_get_form_url('license_activation'); ?>">
<?php _e('Activate WP Ultimo &rarr;', 'wp-ultimo'); ?>
</a>
</div>
<?php else : ?>
<div class="wu-p-4">
<span class="wu-text-gray-700 wu-font-bold wu-uppercase wu-tracking-wide wu-text-xs">
<?php _e('Registered to', 'wp-ultimo'); ?>
</span>
<p class="wu-text-gray-700 wu-p-0 wu-m-0 wu-mt-2">
<?php printf('%s %s', $customer->first, $customer->last); ?>
<span class="wu-text-xs wu-text-gray-600 wu-block"><?php echo $customer->email; ?></span>
<span class="
wu-flex wu-items-center wu-justify-between
wu-border wu-border-solid wu-border-gray-300 wu-rounded
wu-bg-gray-100 wu-text-gray-600
wu-py-1 wu-px-2
wu-mt-3
wu-text-xs
">
<?php echo substr_replace((string) $license->secret_key, str_repeat('*', 16), 4, 24); ?>
<a
title="<?php esc_attr_e('Deactivate WP Ultimo License', 'wp-ultimo'); ?>"
class="dashicons dashicons-trash wu-text-red-600 wubox"
href="<?php echo wu_get_form_url('license_deactivation'); ?>"
></a>
</span>
</p>
</div>
<!-- <?php if (current_user_can('wu_license')) : ?>
<div class="wu-p-4 wu-bg-gray-100 wu-border-solid wu-border-0 wu-border-t wu-border-gray-300">
<a id="wu-manage-account-button" class="button wu-w-full wu-text-center wubox" href="<?php echo wu_get_form_url('license_activation'); ?>">
<?php _e('Manage your Account &rarr;', 'wp-ultimo'); ?>
</a>
</div>
<?php endif; ?> -->
<?php endif; ?>
</div>
<?php
} // end render_account_side_panel;
/**
* Renders the addons side panel
*
* @since 2.0.0
* @return void
*/
public function render_gateways_addons_side_panel() { ?>
<div class="wu-widget-inset">
<div class="wu-p-4">
<span class="wu-text-gray-700 wu-font-bold wu-uppercase wu-tracking-wide wu-text-xs">
<?php _e('Accept Payments wherever you are', 'wp-ultimo'); ?>
</span>
<div class="wu-py-2">
<img class="wu-w-full" alt="<?php esc_attr_e('Accept payments wherever you are', 'wp-ultimo'); ?>" src="<?php echo wu_get_asset('sidebar/gateway-add-ons.png'); ?>">
</div>
<p class="wu-text-gray-600 wu-p-0 wu-m-0">
<?php _e('We are constantly adding support to new payment gateways that can be installed as add-ons.', 'wp-ultimo'); ?>
</p>
</div>
<div class="wu-p-4 wu-bg-gray-100 wu-border-solid wu-border-0 wu-border-t wu-border-gray-300">
<a class="button wu-w-full wu-text-center" href="<?php echo wu_network_admin_url('wp-ultimo-addons', array('tab' => 'gateways')); ?>">
<?php _e('Check our supported Gateways &rarr;', 'wp-ultimo'); ?>
</a>
</div>
</div>
<?php
} // end render_gateways_addons_side_panel;
/**
* Renders the addons side panel
*
* @since 2.0.0
* @return void
*/
public function render_checkout_forms_side_panel() { ?>
<div class="wu-widget-inset">
<div class="wu-p-4">
<span class="wu-text-gray-700 wu-font-bold wu-uppercase wu-tracking-wide wu-text-xs">
<?php _e('Checkout Forms', 'wp-ultimo'); ?>
</span>
<div class="wu-py-2">
<img class="wu-w-full" alt="<?php esc_attr_e('Checkout Forms', 'wp-ultimo'); ?>" src="<?php echo wu_get_asset('sidebar/checkout-forms.png'); ?>">
</div>
<p class="wu-text-gray-600 wu-p-0 wu-m-0">
<?php _e('You can create multiple Checkout Forms for different occasions (seasonal campaigns, launches, etc)!', 'wp-ultimo'); ?>
</p>
</div>
<?php if (current_user_can('wu_edit_checkout_forms')) : ?>
<div class="wu-p-4 wu-bg-gray-100 wu-border-solid wu-border-0 wu-border-t wu-border-gray-300">
<a class="button wu-w-full wu-text-center" href="<?php echo wu_network_admin_url('wp-ultimo-checkout-forms'); ?>">
<?php _e('Manage Checkout Forms &rarr;', 'wp-ultimo'); ?>
</a>
</div>
<?php endif; ?>
</div>
<?php
} // end render_checkout_forms_side_panel;
/**
* Renders the site template side panel
*
* @since 2.0.0
* @return void
*/
public function render_site_template_side_panel() { ?>
<div class="wu-widget-inset">
<div class="wu-p-4">
<span class="wu-text-gray-700 wu-font-bold wu-uppercase wu-tracking-wide wu-text-xs">
<?php _e('Customize the Template Previewer', 'wp-ultimo'); ?>
</span>
<div class="wu-py-2">
<img class="wu-w-full" alt="<?php esc_attr_e('Customize the Template Previewer', 'wp-ultimo'); ?>" src="<?php echo wu_get_asset('sidebar/site-template.png'); ?>">
</div>
<p class="wu-text-gray-600 wu-p-0 wu-m-0">
<?php _e('Did you know that you can customize colors, logos, and more options of the Site Template Previewer top-bar?', 'wp-ultimo'); ?>
</p>
</div>
<?php if (current_user_can('wu_edit_sites')) : ?>
<div class="wu-p-4 wu-bg-gray-100 wu-border-solid wu-border-0 wu-border-t wu-border-gray-300">
<a class="button wu-w-full wu-text-center" target="_blank" href="<?php echo wu_network_admin_url('wp-ultimo-customize-template-previewer'); ?>">
<?php _e('Go to Customizer &rarr;', 'wp-ultimo'); ?>
</a>
</div>
<?php endif; ?>
</div>
<?php
} // end render_site_template_side_panel;
/**
* Renders the site placeholder side panel
*
* @since 2.0.0
* @return void
*/
public function render_site_placeholders_side_panel() { ?>
<div class="wu-widget-inset">
<div class="wu-p-4">
<span class="wu-text-gray-700 wu-font-bold wu-uppercase wu-tracking-wide wu-text-xs">
<?php _e('Customize the Template Placeholders', 'wp-ultimo'); ?>
</span>
<div class="wu-py-2">
<img class="wu-w-full" alt="<?php esc_attr_e('Customize the Template Placeholders', 'wp-ultimo'); ?>" src="<?php echo wu_get_asset('sidebar/template-placeholders.png'); ?>">
</div>
<p class="wu-text-gray-600 wu-p-0 wu-m-0">
<?php _e('If you are using placeholder substitutions inside your site templates, use this tool to add, remove, or change the default content of those placeholders.', 'wp-ultimo'); ?>
</p>
</div>
<?php if (current_user_can('wu_edit_sites')) : ?>
<div class="wu-p-4 wu-bg-gray-100 wu-border-solid wu-border-0 wu-border-t wu-border-gray-300">
<a class="button wu-w-full wu-text-center" target="_blank" href="<?php echo wu_network_admin_url('wp-ultimo-template-placeholders'); ?>">
<?php _e('Edit Placeholders &rarr;', 'wp-ultimo'); ?>
</a>
</div>
<?php endif; ?>
</div>
<?php
} // end render_site_placeholders_side_panel;
/**
* Renders the invoice side panel
*
* @since 2.0.0
* @return void
*/
public function render_invoice_side_panel() { ?>
<div class="wu-widget-inset">
<div class="wu-p-4">
<span class="wu-text-gray-700 wu-font-bold wu-uppercase wu-tracking-wide wu-text-xs">
<?php _e('Customize the Invoice Template', 'wp-ultimo'); ?>
</span>
<div class="wu-py-2">
<img class="wu-w-full" alt="<?php esc_attr_e('Customize the Invoice Template', 'wp-ultimo'); ?>" src="<?php echo wu_get_asset('sidebar/invoice-template.png'); ?>">
</div>
<p class="wu-text-gray-600 wu-p-0 wu-m-0">
<?php _e('Did you know that you can customize colors, logos, and more options of the Invoice PDF template?', 'wp-ultimo'); ?>
</p>
</div>
<?php if (current_user_can('wu_edit_payments')) : ?>
<div class="wu-p-4 wu-bg-gray-100 wu-border-solid wu-border-0 wu-border-t wu-border-gray-300">
<a class="button wu-w-full wu-text-center" target="_blank" href="<?php echo wu_network_admin_url('wp-ultimo-customize-invoice-template'); ?>">
<?php _e('Go to Customizer &rarr;', 'wp-ultimo'); ?>
</a>
</div>
<?php endif; ?>
</div>
<?php
} // end render_invoice_side_panel;
/**
* Renders system emails side panel.
*
* @since 2.0.0
* @return void
*/
public function render_system_emails_side_panel() { ?>
<div class="wu-widget-inset">
<div class="wu-p-4">
<span class="wu-text-gray-700 wu-font-bold wu-uppercase wu-tracking-wide wu-text-xs">
<?php _e('Customize System Emails', 'wp-ultimo'); ?>
</span>
<div class="wu-py-2">
<img class="wu-w-full" alt="<?php esc_attr_e('Customize System Emails', 'wp-ultimo'); ?>" src="<?php echo wu_get_asset('sidebar/system-emails.png'); ?>">
</div>
<p class="wu-text-gray-600 wu-p-0 wu-m-0">
<?php _e('You can completely customize the contents of the emails sent out by WP Ultimo when particular events occur, such as Account Creation, Payment Failures, etc.', 'wp-ultimo'); ?>
</p>
</div>
<?php if (current_user_can('wu_edit_broadcasts')) : ?>
<div class="wu-p-4 wu-bg-gray-100 wu-border-solid wu-border-0 wu-border-t wu-border-gray-300">
<a class="button wu-w-full wu-text-center" target="_blank" href="<?php echo wu_network_admin_url('wp-ultimo-emails'); ?>">
<?php _e('Customize System Emails &rarr;', 'wp-ultimo'); ?>
</a>
</div>
<?php endif; ?>
</div>
<?php
} // end render_system_emails_side_panel;
/**
* Renders the email template side panel.
*
* @since 2.0.0
* @return void
*/
public function render_email_template_side_panel() { ?>
<div class="wu-widget-inset">
<div class="wu-p-4">
<span class="wu-text-gray-700 wu-font-bold wu-uppercase wu-tracking-wide wu-text-xs">
<?php _e('Customize Email Template', 'wp-ultimo'); ?>
</span>
<div class="wu-py-2">
<img class="wu-w-full" alt="<?php esc_attr_e('Customize Email Template', 'wp-ultimo'); ?>" src="<?php echo wu_get_asset('sidebar/email-template.png'); ?>">
</div>
<p class="wu-text-gray-600 wu-p-0 wu-m-0">
<?php _e('If your network is using the HTML email option, you can customize the look and feel of the email template.', 'wp-ultimo'); ?>
</p>
</div>
<?php if (current_user_can('wu_edit_broadcasts')) : ?>
<div class="wu-p-4 wu-bg-gray-100 wu-border-solid wu-border-0 wu-border-t wu-border-gray-300">
<a class="button wu-w-full wu-text-center" target="_blank" href="<?php echo wu_network_admin_url('wp-ultimo-customize-email-template'); ?>">
<?php _e('Customize Email Template &rarr;', 'wp-ultimo'); ?>
</a>
</div>
<?php endif; ?>
</div>
<?php
} // end render_email_template_side_panel;
// phpcs:enable
/**
* Returns the title of the page.
*
* @since 2.0.0
* @return string Title of the page.
*/
public function get_title() {
return __('Settings', 'wp-ultimo');
} // end get_title;
/**
* 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 __('Settings', 'wp-ultimo');
} // end get_menu_title;
/**
* Every child class should implement the output method to display the contents of the page.
*
* @since 1.8.2
* @return void
*/
public function output() {
/*
* Enqueue the base Dashboard Scripts
*/
wp_enqueue_media();
wp_enqueue_script('dashboard');
wp_enqueue_style('wp-color-picker');
wp_enqueue_script('wp-color-picker');
wp_enqueue_script('media');
wp_enqueue_script('wu-vue');
wp_enqueue_script('wu-selectizer');
do_action('wu_render_settings');
wu_get_template('base/settings', array(
'screen' => get_current_screen(),
'page' => $this,
'classes' => '',
'sections' => $this->get_sections(),
'current_section' => $this->get_current_section(),
'clickable_navigation' => $this->clickable_navigation,
));
} // end output;
/**
* Returns the list of settings sections.
*
* @since 2.0.0
* @return array
*/
public function get_sections() {
return WP_Ultimo()->settings->get_sections();
} // end get_sections;
/**
* Default handler for step submission. Simply redirects to the next step.
*
* @since 2.0.0
* @return void
*/
public function default_handler() {
if (!current_user_can('wu_edit_settings')) {
wp_die(__('You do not have the permissions required to change settings.', 'wp-ultimo'));
} // end if;
if (!isset($_POST['active_gateways']) && wu_request('tab') === 'payment-gateways') {
$_POST['active_gateways'] = array();
} // end if;
WP_Ultimo()->settings->save_settings($_POST);
wp_redirect(add_query_arg('updated', 1, wu_get_current_url()));
exit;
} // end default_handler;
/**
* Default method for views.
*
* @since 2.0.0
* @return void
*/
public function default_view() {
$sections = $this->get_sections();
$section_slug = $this->get_current_section();
$section = $this->current_section;
$fields = array_filter($section['fields'], fn($item) => current_user_can($item['capability']));
uasort($fields, 'wu_sort_by_order');
/*
* Get Field to save
*/
$fields['save'] = array(
'type' => 'submit',
'title' => __('Save Settings', 'wp-ultimo'),
'classes' => 'button button-primary button-large wu-ml-auto wu-w-full md:wu-w-auto',
'wrapper_classes' => 'wu-sticky wu-bottom-0 wu-save-button wu-mr-px wu-w-full md:wu-w-auto',
'html_attr' => array(
'v-on:click' => 'send("window", "wu_block_ui", "#wpcontent")'
),
);
if (!current_user_can('wu_edit_settings')) {
$fields['save']['html_attr']['disabled'] = 'disabled';
} // end if;
$form = new Form($section_slug, $fields, array(
'views' => 'admin-pages/fields',
'classes' => 'wu-modal-form wu-widget-list wu-striped wu--mt-5 wu--mx-in wu--mb-in',
'field_wrapper_classes' => 'wu-w-full wu-box-border wu-items-center wu-flex wu-justify-between wu-p-4 wu-py-5 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' => array(
'style' => '',
'data-on-load' => 'remove_block_ui',
'data-wu-app' => str_replace('-', '_', $section_slug),
'data-state' => json_encode(wu_array_map_keys('wu_replace_dashes', Settings::get_instance()->get_all(true))),
),
));
$form->render();
} // end default_view;
} // end class Settings_Admin_Page;

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,212 @@
<?php
/**
* WP Ultimo Shortcodes Admin Page.
*
* @package WP_Ultimo
* @subpackage Admin_Pages
* @since 2.0.24
*/
namespace WP_Ultimo\Admin_Pages;
use WP_Ultimo\UI\Base_Element;
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* WP Ultimo Shortcodes Admin Page.
*/
class Shortcodes_Admin_Page extends Base_Admin_Page {
/**
* Holds the ID for this page, this is also used as the page slug.
*
* @var string
*/
protected $id = 'wp-ultimo-shortcodes';
/**
* Is this a top-level menu or a submenu?
*
* @since 1.8.2
* @var string
*/
protected $type = 'submenu';
/**
* If this is a submenu, we need a parent menu to attach this to
*
* @since 1.8.2
* @var string
*/
protected $parent = 'none';
/**
* Allows us to highlight another menu page, if this page has no parent page at all.
*
* @since 2.0.0
* @var boolean
*/
protected $highlight_menu_slug = 'wp-ultimo-settings';
/**
* 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;
/**
* 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 = array(
'network_admin_menu' => 'manage_network',
);
/**
* Allow child classes to add further initializations.
*
* @since 1.8.2
* @return void
*/
public function init() {
parent::init();
} // end init;
/**
* Returns the title of the page.
*
* @since 2.0.0
* @return string Title of the page.
*/
public function get_title() {
return __('Available Shortcodes', 'wp-ultimo');
} // end get_title;
/**
* 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 __('Available Shortcodes', 'wp-ultimo');
} // end get_menu_title;
/**
* Allows admins to rename the sub-menu (first item) for a top-level page.
*
* @since 2.0.0
* @return string False to use the title menu or string with sub-menu title.
*/
public function get_submenu_title() {
return __('Dashboard', 'wp-ultimo');
} // end get_submenu_title;
/**
* Every child class should implement the output method to display the contents of the page.
*
* @since 1.8.2
* @return void
*/
public function output() {
$screen = get_current_screen();
wu_get_template('shortcodes/shortcodes', array(
'screen' => $screen,
'data' => $this->get_data(),
));
} // end output;
/**
* Get data for shortcodes
*
* @since 2.0.0
* @return array
*/
public function get_data() {
$elements = Base_Element::get_public_elements();
$data = array();
foreach ($elements as $element) {
$defaults = $element->defaults();
$params = array_filter($element->fields(), fn($el) => $el['type'] !== 'note' && $el['type'] !== 'header');
foreach ($params as $key => $value) {
$params[$key]['default'] = wu_get_isset($defaults, $key, '');
$params[$key]['desc'] = !isset($value['desc']) ? '' : $params[$key]['desc'];
switch ($value['type']) {
case 'toggle':
$params[$key]['options'] = '0 | 1';
break;
case 'select':
$params[$key]['options'] = implode(' | ', array_keys(wu_get_isset($value, 'options', array())));
break;
case 'int':
$params[$key]['options'] = __('integer', 'wp-ultimo');
break;
case 'number':
$params[$key]['options'] = __('number', 'wp-ultimo');
break;
case 'text':
$params[$key]['options'] = __('text', 'wp-ultimo');
break;
case 'textarea':
$params[$key]['options'] = __('text', 'wp-ultimo');
break;
default:
$params[$key]['options'] = $value['type'];
break;
} // end switch;
} // end foreach;
$id = $element->get_id();
if (strncmp((string) $id, 'wp-ultimo/', strlen('wp-ultimo/')) === 0) {
$id = substr((string) $element->get_id(), strlen('wp-ultimo/'));
} // end if;
$data[] = array(
'generator_form_url' => wu_get_form_url("shortcode_{$id}"),
'title' => $element->get_title(),
'shortcode' => $element->get_shortcode_id(),
'description' => $element->get_description(),
'params' => $params,
);
} // end foreach;
return $data;
} // end get_data;
} // end class Shortcodes_Admin_Page;

View File

@ -0,0 +1,752 @@
<?php
/**
* WP Ultimo Site Edit 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\Sites\Site_Type;
use \WP_Ultimo\Models\Site;
/**
* WP Ultimo Site Edit New Admin Page.
*/
class Site_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-site';
/**
* 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 = 'site';
/**
* 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-sites';
/**
* 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;
/**
* 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 = array(
'network_admin_menu' => 'wu_edit_sites',
);
/**
* Registers the necessary scripts and styles for this admin page.
*
* @since 2.0.0
* @return void
*/
public function register_scripts() {
parent::register_scripts();
WP_Ultimo()->scripts->register_script('wu-screenshot-scraper', wu_get_asset('screenshot-scraper.js', 'js'), array('jquery'));
wp_enqueue_script('wu-screenshot-scraper');
wp_enqueue_media();
wp_enqueue_editor();
} // end register_scripts;
/**
* Register ajax forms that we use for site.
*
* @since 2.0.0
* @return void
*/
public function register_forms() {
/*
* Transfer site - Confirmation modal
*/
wu_register_form('transfer_site', array(
'render' => array($this, 'render_transfer_site_modal'),
'handler' => array($this, 'handle_transfer_site_modal'),
'capability' => 'wu_transfer_sites',
));
/*
* Delete Site - Confirmation modal
*/
add_filter('wu_data_json_success_delete_site_modal', fn($data_json) => array(
'redirect_url' => wu_network_admin_url('wp-ultimo-sites', array('deleted' => 1))
));
add_filter("wu_page_{$this->id}_load", array($this, 'add_new_site_template_warning_message'));
} // end register_forms;
/**
* Adds the new site_template warning.
*
* @since 2.0.0
* @return void
*/
public function add_new_site_template_warning_message() {
if (wu_request('wu-new-model')) {
if (!$this->get_object() || $this->get_object()->get_type() !== Site_Type::SITE_TEMPLATE) {
return;
} // end if;
\WP_Ultimo\UI\Tours::get_instance()->create_tour('new_site_template_warning', array(
array(
'id' => 'new-site-template-warning',
'title' => __('On adding a new Site Template...', 'wp-ultimo'),
'text' => array(
__("You just successfully added a new site template to your WP Ultimo network and that's awesome!", 'wp-ultimo'),
__('Keep in mind that newly created site templates do not appear automatically in your checkout forms.', 'wp-ultimo'),
__('To make a site template available on registration, you will need to manually add it to the template selection field of your checkout forms.', 'wp-ultimo'),
),
'buttons' => array(
array(
'classes' => 'button wu-text-xs sm:wu-normal-case wu-float-left',
'text' => __('Go to Checkout Forms', 'wp-ultimo'),
'url' => wu_network_admin_url('wp-ultimo-checkout-forms'),
)
),
'attachTo' => array(
'element' => '#message.updated',
'on' => 'top',
),
),
));
} // end if;
} // end add_new_site_template_warning_message;
/**
* Renders the transfer confirmation form.
*
* @since 2.0.0
* @return void
*/
function render_transfer_site_modal() {
$site = wu_get_site(wu_request('id'));
if (!$site) {
return;
} // end if;
$fields = array(
'confirm' => array(
'type' => 'toggle',
'title' => __('Confirm Transfer', 'wp-ultimo'),
'desc' => __('This will start the transfer of assets from one membership to another.', 'wp-ultimo'),
'html_attr' => array(
'v-model' => 'confirmed',
),
),
'submit_button' => array(
'type' => 'submit',
'title' => __('Start Transfer', 'wp-ultimo'),
'placeholder' => __('Start Transfer', 'wp-ultimo'),
'value' => 'save',
'classes' => 'button button-primary wu-w-full',
'wrapper_classes' => 'wu-items-end',
'html_attr' => array(
'v-bind:disabled' => '!confirmed',
),
),
'id' => array(
'type' => 'hidden',
'value' => $site->get_id(),
),
'target_membership_id' => array(
'type' => 'hidden',
'value' => wu_request('target_membership_id'),
),
);
$form = new \WP_Ultimo\UI\Form('total-actions', $fields, array(
'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' => array(
'data-wu-app' => 'transfer_site',
'data-state' => json_encode(array(
'confirmed' => false,
)),
),
));
$form->render();
} // end render_transfer_site_modal;
/**
* Handles the transfer of site.
*
* @since 2.0.0
* @return void
*/
public function handle_transfer_site_modal() {
global $wpdb;
$site = wu_get_site(wu_request('id'));
$target_membership = wu_get_membership(wu_request('target_membership_id'));
if (!$site) {
wp_send_json_error(new \WP_Error('not-found', __('Site not found.', 'wp-ultimo')));
} // end if;
if (!$target_membership) {
wp_send_json_error(new \WP_Error('not-found', __('Membership not found.', 'wp-ultimo')));
} // end if;
$site->set_membership_id($target_membership->get_id());
$site->set_customer_id($target_membership->get_customer_id());
$site->set_type('customer_owned');
$saved = $site->save();
if (is_wp_error($saved)) {
wp_send_json_error($saved);
} // end if;
wp_send_json_success(array(
'redirect_url' => wu_network_admin_url('wp-ultimo-edit-site', array(
'id' => $site->get_id(),
'updated' => 1,
))
));
} // end handle_transfer_site_modal;
/**
* Allow child classes to register widgets, if they need them.
*
* @since 1.8.2
* @return void
*/
public function register_widgets() {
parent::register_widgets();
$label = $this->get_object()->get_type_label();
$class = $this->get_object()->get_type_class();
$tag = "<span class='wu-bg-gray-200 wu-py-1 wu-px-2 wu-rounded-sm wu-text-xs wu-font-mono $class'>{$label}</span>";
$this->add_fields_widget('at_a_glance', array(
'title' => __('At a Glance', 'wp-ultimo'),
'position' => 'normal',
'classes' => 'wu-overflow-hidden wu-m-0 wu--mt-1 wu--mx-3 wu--mb-3',
'field_wrapper_classes' => 'wu-w-1/4 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',
'html_attr' => array(
'style' => 'margin-top: -6px;',
),
'fields' => array(
'type' => array(
'type' => 'text-display',
'title' => __('Site Type', 'wp-ultimo'),
'display_value' => $tag,
'tooltip' => '',
),
'id' => array(
'type' => 'text-display',
'copy' => true,
'title' => __('Site ID', 'wp-ultimo'),
'display_value' => $this->get_object()->get_id(),
'tooltip' => '',
),
),
));
$this->add_fields_widget('description', array(
'title' => __('Description', 'wp-ultimo'),
'position' => 'normal',
'fields' => array(
'description' => array(
'type' => 'textarea',
'title' => __('Site Description', 'wp-ultimo'),
'placeholder' => __('Tell your customers what this site is about.', 'wp-ultimo'),
'value' => $this->get_object()->get_option_blogdescription(),
'html_attr' => array(
'rows' => 3,
),
),
),
));
$this->add_tabs_widget('options', array(
'title' => __('Site Options', 'wp-ultimo'),
'position' => 'normal',
'sections' => $this->get_site_option_sections(),
));
$this->add_list_table_widget('domains', array(
'title' => __('Mapped Domains', 'wp-ultimo'),
'table' => new \WP_Ultimo\List_Tables\Sites_Domain_List_Table(),
'query_filter' => array($this, 'domain_query_filter'),
));
if ($this->get_object()->get_type() === 'customer_owned') {
$this->add_list_table_widget('membership', array(
'title' => __('Linked Membership', 'wp-ultimo'),
'table' => new \WP_Ultimo\List_Tables\Customers_Membership_List_Table(),
'query_filter' => function($query) {
$query['id'] = $this->get_object()->get_membership_id();
return $query;
},
));
$this->add_list_table_widget('customer', array(
'title' => __('Linked Customer', 'wp-ultimo'),
'table' => new \WP_Ultimo\List_Tables\Site_Customer_List_Table(),
'query_filter' => function($query) {
$query['id'] = $this->get_object()->get_customer_id();
return $query;
},
));
} // end if;
$this->add_list_table_widget('events', array(
'title' => __('Events', 'wp-ultimo'),
'table' => new \WP_Ultimo\List_Tables\Inside_Events_List_Table(),
'query_filter' => array($this, 'query_filter'),
));
$membership_selected = $this->get_object()->get_membership() ? $this->get_object()->get_membership()->to_search_results() : '';
$template_selected = $this->get_object()->get_template() ? $this->get_object()->get_template()->to_search_results() : '';
$this->add_fields_widget('save', array(
'html_attr' => array(
'data-wu-app' => 'site_type',
'data-state' => json_encode(array(
'type' => $this->get_object()->get_type(),
'original_membership_id' => $this->get_object()->get_membership_id(),
'membership_id' => $this->get_object()->get_membership_id(),
)),
),
'fields' => array(
// Fields for price
'type_main' => array(
'type' => 'text-display',
'title' => __('Site Type', 'wp-ultimo'),
'display_value' => __('Main Site', 'wp-ultimo'),
'tooltip' => __('You can\'t change the main site type.', 'wp-ultimo'),
'wrapper_html_attr' => array(
'v-cloak' => '1',
'v-show' => 'type === "main"',
),
),
'type' => array(
'type' => 'select',
'title' => __('Site Type', 'wp-ultimo'),
'placeholder' => __('Select Site Type', 'wp-ultimo'),
'desc' => __('Different site types have different options and settings.', 'wp-ultimo'),
'value' => $this->get_object()->get_type(),
'tooltip' => '',
'options' => array(
'default' => __('Regular WordPress', 'wp-ultimo'),
'site_template' => __('Site Template', 'wp-ultimo'),
'customer_owned' => __('Customer-owned', 'wp-ultimo'),
),
'html_attr' => array(
'v-model' => 'type',
),
'wrapper_html_attr' => array(
'v-cloak' => '1',
'v-show' => 'type !== "main"',
),
),
'categories' => array(
'type' => 'select',
'title' => __('Template Categories', 'wp-ultimo'),
'placeholder' => __('e.g.: Landing Page, Health...', 'wp-ultimo'),
'desc' => __('Customers will be able to filter by categories during signup.', 'wp-ultimo'),
'value' => $this->get_object()->get_categories(),
'options' => Site::get_all_categories(),
'html_attr' => array(
'data-selectize-categories' => 1,
'multiple' => 1,
),
'wrapper_html_attr' => array(
'v-show' => "type === 'site_template'",
'v-cloak' => '1',
),
),
'membership_id' => array(
'type' => 'model',
'title' => __('Associated Membership', 'wp-ultimo'),
'placeholder' => __('Search Membership...', 'wp-ultimo'),
'desc' => __('The membership that owns this site.', 'wp-ultimo'),
'value' => $this->get_object()->get_membership_id(),
'tooltip' => '',
'wrapper_html_attr' => array(
'v-show' => "type === 'customer_owned'",
'v-cloak' => 1,
),
'html_attr' => array(
'data-model' => 'membership',
'data-value-field' => 'id',
'data-label-field' => 'reference_code',
'data-search-field' => 'reference_code',
'data-max-items' => 1,
'data-selected' => json_encode($membership_selected),
),
),
'transfer_note' => array(
'type' => 'note',
'desc' => __('Changing the membership will transfer the site and all its assets to the new membership.', 'wp-ultimo'),
'classes' => 'wu-p-2 wu-bg-red-100 wu-text-red-600 wu-rounded wu-w-full',
'wrapper_html_attr' => array(
'v-show' => '(original_membership_id != membership_id) && membership_id',
'v-cloak' => '1',
),
),
'submit_save' => array(
'type' => 'submit',
'title' => __('Save Site', 'wp-ultimo'),
'placeholder' => __('Save Site', 'wp-ultimo'),
'value' => 'save',
'classes' => 'button button-primary wu-w-full',
'wrapper_html_attr' => array(
'v-show' => 'original_membership_id == membership_id || !membership_id',
'v-cloak' => 1,
),
),
'transfer' => array(
'type' => 'link',
'display_value' => __('Transfer Site', 'wp-ultimo'),
'wrapper_classes' => 'wu-bg-gray-200',
'classes' => 'button wubox wu-w-full wu-text-center',
'wrapper_html_attr' => array(
'v-show' => 'original_membership_id != membership_id && membership_id',
'v-cloak' => '1',
),
'html_attr' => array(
'v-bind:href' => "'" . wu_get_form_url('transfer_site', array(
'id' => $this->get_object()->get_id(),
'target_membership_id' => '',
)) . "=' + membership_id",
'title' => __('Transfer Site', 'wp-ultimo'),
),
),
),
));
$this->add_fields_widget('active', array(
'title' => __('Active', 'wp-ultimo'),
'fields' => array(
'active' => array(
'type' => 'toggle',
'title' => __('Active', 'wp-ultimo'),
'desc' => __('Use this option to manually enable or disable this site.', 'wp-ultimo'),
'value' => $this->get_object()->is_active(),
),
),
));
$this->add_fields_widget('image', array(
'title' => __('Site Image', 'wp-ultimo'),
'fields' => array(
'featured_image_id' => array(
'type' => 'image',
'stacked' => true,
'title' => __('Site Image', 'wp-ultimo'),
'desc' => __('This image is used on lists of sites and other places. It can be automatically generated by the screenshot scraper.', 'wp-ultimo'),
'value' => $this->get_object()->get_featured_image_id(),
'img' => $this->get_object()->get_featured_image(),
),
'scraper_note' => array(
'type' => 'note',
'desc' => __('You need to save the site for the change to take effect.', 'wp-ultimo'),
'wrapper_classes' => 'wu-hidden wu-scraper-note',
),
'scraper_error' => array(
'type' => 'note',
'desc' => '<span class="wu-scraper-error-message wu-p-2 wu-bg-red-100 wu-text-red-600 wu-rounded wu-block"></span>',
'wrapper_classes' => 'wu-hidden wu-scraper-error',
),
'scraper_message' => array(
'type' => 'note',
'desc' => sprintf('<span class="wu-p-2 wu-bg-red-100 wu-text-red-600 wu-rounded wu-block">%s</span>', __('We detected that this network might be running locally. If that\'s the case, WP Ultimo will not be able to take a screenshot of the site. A site needs to be publicly available to the outside world in order for this feature to work.', 'wp-ultimo')),
'wrapper_classes' => \WP_Ultimo\Domain_Mapping\Helper::is_development_mode() ? '' : 'wu-hidden',
),
'scraper' => array(
'type' => 'submit',
'title' => __('Take Screenshot', 'wp-ultimo'),
'title' => __('Take Screenshot', 'wp-ultimo'),
'classes' => 'button wu-w-full',
),
),
));
} // end register_widgets;
/**
* Returns the list of sections and its fields for the site page.
*
* Can be filtered via 'wu_site_options_sections'.
*
* @see inc/managers/class-limitation-manager.php
*
* @since 2.0.0
* @return array
*/
protected function get_site_option_sections() {
$sections = array();
$sections = apply_filters('wu_site_options_sections', $sections, $this->get_object());
return $sections;
} // end get_site_option_sections;
/**
* Returns the title of the page.
*
* @since 2.0.0
* @return string Title of the page.
*/
public function get_title() {
return $this->edit ? __('Edit Site', 'wp-ultimo') : __('Add new Site', 'wp-ultimo');
} // end get_title;
/**
* 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 Site', 'wp-ultimo');
} // end get_menu_title;
/**
* Returns the action links for that page.
*
* @since 1.8.2
* @return array
*/
public function action_links() {
return array(
array(
'url' => network_admin_url('site-settings.php?id=' . $this->get_object()->get_id()),
'label' => __('Go to the Default Edit Screen', 'wp-ultimo'),
'icon' => 'wu-cog',
),
array(
'url' => get_site_url($this->get_object()->get_id()),
'label' => __('Visit Site', 'wp-ultimo'),
'icon' => 'wu-link',
),
array(
'url' => get_admin_url($this->get_object()->get_id()),
'label' => __('Dashboard', 'wp-ultimo'),
'icon' => 'dashboard',
),
);
} // end action_links;
/**
* Returns the labels to be used on the admin page.
*
* @since 2.0.0
* @return array
*/
public function get_labels() {
return array(
'edit_label' => __('Edit Site', 'wp-ultimo'),
'add_new_label' => __('Add new Site', 'wp-ultimo'),
'updated_message' => __('Site updated with success!', 'wp-ultimo'),
'title_placeholder' => __('Enter Site Name', 'wp-ultimo'),
'title_description' => __('This name will be used as the site title.', 'wp-ultimo'),
'save_button_label' => __('Save Site', 'wp-ultimo'),
'save_description' => '',
'delete_button_label' => __('Delete Site', 'wp-ultimo'),
'delete_description' => __('Be careful. This action is irreversible.', 'wp-ultimo'),
);
} // end get_labels;
/**
* 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 domain_query_filter($args) {
$extra_args = array(
'blog_id' => absint($this->get_object()->get_id()),
);
return array_merge($args, $extra_args);
} // end domain_query_filter;
/**
* 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 query_filter($args) {
$extra_args = array(
'object_type' => 'site',
'object_id' => absint($this->get_object()->get_id()),
);
return array_merge($args, $extra_args);
} // end query_filter;
/**
* Returns the object being edit at the moment.
*
* @since 2.0.0
* @return \WP_Ultimo\Models\Site
*/
public function get_object() {
if ($this->object !== null) {
return $this->object;
} // end if;
$item_id = wu_request('id', 0);
$item = wu_get_site($item_id);
if (!$item) {
wp_redirect(wu_network_admin_url('wp-ultimo-sites'));
exit;
} // end if;
$this->object = $item;
return $this->object;
} // end get_object;
/**
* Sites have titles.
*
* @since 2.0.0
*/
public function has_title(): bool {
return true;
} // end has_title;
/**
* Should implement the processes necessary to save the changes made to the object.
*
* @since 2.0.23
* @return true
*/
public function handle_save() {
$_POST['categories'] = wu_get_isset($_POST, 'categories', array());
if ($_POST['type'] !== Site_Type::CUSTOMER_OWNED) {
$_POST['membership_id'] = false;
$_POST['customer_id'] = false;
} // end if;
return parent::handle_save();
} // end handle_save;
} // end class Site_Edit_Admin_Page;

View File

@ -0,0 +1,576 @@
<?php
/**
* WP Ultimo Sites Admin Page.
*
* @package WP_Ultimo
* @subpackage Admin_Pages
* @since 2.0.0
*/
namespace WP_Ultimo\Admin_Pages;
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* WP Ultimo Sites Admin Page.
*/
class Site_List_Admin_Page extends List_Admin_Page {
/**
* Holds the ID for this page, this is also used as the page slug.
*
* @var string
*/
protected $id = 'wp-ultimo-sites';
/**
* Is this a top-level menu or a submenu?
*
* @since 1.8.2
* @var string
*/
protected $type = 'submenu';
/**
* 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;
/**
* 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 = array(
'network_admin_menu' => 'wu_read_sites',
);
/**
* Register ajax forms that we use for sites.
*
* @since 2.0.0
* @return void
*/
public function register_forms() {
/*
* Edit/Add New Site
*/
wu_register_form('add_new_site', array(
'render' => array($this, 'render_add_new_site_modal'),
'handler' => array($this, 'handle_add_new_site_modal'),
'capability' => 'wu_add_sites',
));
/*
* Publish pending site.
*/
wu_register_form('publish_pending_site', array(
'render' => array($this, 'render_publish_pending_site_modal'),
'handler' => array($this, 'handle_publish_pending_site_modal'),
'capability' => 'wu_publish_sites',
));
add_action('wu_handle_bulk_action_form_site_screenshot', array($this, 'handle_bulk_screenshots'), 10, 3);
} // end register_forms;
/**
* Handles the screenshot bulk action.
*
* @since 2.0.0
*
* @param string $action The action.
* @param string $model The model.
* @param array $ids The ids list.
* @return void
*/
public function handle_bulk_screenshots($action, $model, $ids) {
$item_ids = array_filter($ids);
foreach ($item_ids as $item_id) {
wu_enqueue_async_action('wu_async_take_screenshot', array(
'site_id' => $item_id,
), 'site');
} // end foreach;
} // end handle_bulk_screenshots;
/**
* Renders the deletion confirmation form.
*
* @since 2.0.0
* @return void
*/
public function render_publish_pending_site_modal() {
$membership = wu_get_membership(wu_request('membership_id'));
if (!$membership) {
return;
} // end if;
$fields = array(
'confirm' => array(
'type' => 'toggle',
'title' => __('Confirm Publication', 'wp-ultimo'),
'desc' => __('This action can not be undone.', 'wp-ultimo'),
'html_attr' => array(
'v-model' => 'confirmed',
),
),
'submit_button' => array(
'type' => 'submit',
'title' => __('Publish', 'wp-ultimo'),
'placeholder' => __('Publish', 'wp-ultimo'),
'value' => 'publish',
'classes' => 'button button-primary wu-w-full',
'wrapper_classes' => 'wu-items-end',
'html_attr' => array(
'v-bind:disabled' => '!confirmed',
),
),
'wu-when' => array(
'type' => 'hidden',
'value' => base64_encode('init'),
),
'membership_id' => array(
'type' => 'hidden',
'value' => $membership->get_id(),
),
);
$form = new \WP_Ultimo\UI\Form('total-actions', $fields, array(
'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' => array(
'data-wu-app' => 'true',
'data-state' => json_encode(array(
'confirmed' => false,
)),
),
));
$form->render();
} // end render_publish_pending_site_modal;
/**
* Handles the deletion of line items.
*
* @since 2.0.0
* @return void
*/
public function handle_publish_pending_site_modal() {
$membership = wu_get_membership(wu_request('membership_id'));
if (!$membership) {
wp_send_json_error(new \WP_Error('not-found', __('Pending site not found.', 'wp-ultimo')));
} // end if;
$pending_site = $membership->get_pending_site();
if (!is_a($pending_site, '\\WP_Ultimo\\Models\\Site')) {
wp_send_json_error(new \WP_Error('not-found', __('Pending site not found.', 'wp-ultimo')));
} // end if;
$pending_site->set_type('customer_owned');
$saved = $pending_site->save();
if (is_wp_error($saved)) {
wp_send_json_error($saved);
} // end if;
$membership->delete_pending_site();
/*
* Trigger event that marks the publication of a site.
*/
do_action('wu_pending_site_published', $pending_site, $membership);
$redirect = current_user_can('wu_edit_sites') ? 'wp-ultimo-edit-site' : 'wp-ultimo-sites';
wp_send_json_success(array(
'redirect_url' => wu_network_admin_url($redirect, array(
'id' => $pending_site->get_id(),
))
));
} // end handle_publish_pending_site_modal;
/**
* Handles the add/edit of line items.
*
* @since 2.0.0
* @return mixed
*/
public function handle_add_new_site_modal() {
global $current_site;
$domain_type = wu_request('tab', is_subdomain_install() ? 'sub-domain' : 'sub-directory');
if ($domain_type === 'domain') {
$domain = wu_request('domain', '');
$path = '/';
} else {
$d = wu_get_site_domain_and_path(wu_request('domain', ''));
$domain = $d->domain;
$path = $d->path;
} // end if;
$atts = array(
'domain' => $domain,
'path' => $path,
'title' => wu_request('title'),
'type' => wu_request('type'),
'template_id' => wu_request('template_site', 0),
'membership_id' => wu_request('membership_id', false),
'duplication_arguments' => array(
'copy_media' => wu_request('copy_media'),
)
);
$site = wu_create_site($atts);
if (is_wp_error($site)) {
return wp_send_json_error($site);
} // end if;
if ($site->get_blog_id() === false) {
$error = new \WP_Error('error', __('Something wrong happened.', 'wp-ultimo'));
return wp_send_json_error($error);
} // end if;
$redirect = current_user_can('wu_edit_sites') ? 'wp-ultimo-edit-site' : 'wp-ultimo-sites';
wp_send_json_success(array(
'redirect_url' => wu_network_admin_url($redirect, array(
'id' => $site->get_id(),
'wu-new-model' => 1,
'updated' => 1,
))
));
} // end handle_add_new_site_modal;
/**
* Renders the add/edit line items form.
*
* @since 2.0.0
* @return void
*/
public function render_add_new_site_modal() {
global $current_site;
$duplicate_id = wu_request('id');
$site = wu_get_site($duplicate_id);
$type = 'site_template';
$title = '';
$path = 'mysite';
$template_id = '';
$membership_id = '';
/*
* Checks if this is a duplication process.
*/
if ($duplicate_id && $site) {
// translators: the %s is the site title.
$title = sprintf(__('Copy of %s', 'wp-ultimo'), $site->get_title());
$path = sprintf('%s%s', trim($site->get_path(), '/'), 'copy');
$type = $site->get_type();
$template_id = $duplicate_id;
$membership_id = $site->get_membership_id();
} // end if;
$save_label = $duplicate_id ? __('Duplicate Site', 'wp-ultimo') : __('Add new Site', 'wp-ultimo');
$options = array(
'sub-domain' => __('Subdomain', 'wp-ultimo'),
'sub-directory' => __('Subdirectory', 'wp-ultimo'),
'domain' => __('Domain', 'wp-ultimo'),
);
/*
* Only keep the tab that correspond to the install type.
*/
if (is_subdomain_install()) {
unset($options['sub-directory']);
} else {
unset($options['sub-domain']);
} // end if;
$fields = array(
'tab' => array(
'type' => 'tab-select',
'wrapper_html_attr' => array(
'v-cloak' => 1,
),
'html_attr' => array(
'v-model' => 'tab',
),
'options' => $options,
),
'title' => array(
'type' => 'text',
'title' => __('Site Title', 'wp-ultimo'),
'placeholder' => __('New Network Site', 'wp-ultimo'),
'value' => $title,
),
'domain_group' => array(
'type' => 'group',
// translators: the %s is the site preview url.
'desc' => sprintf(__('The site URL will be: %s', 'wp-ultimo'), '<span class="wu-font-mono">{{ tab === "domain" ? domain : ( tab === "sub-directory" ? scheme + base_url + domain : scheme + domain + "." + base_url ) }}</span>'),
'fields' => array(
'domain' => array(
'type' => 'text',
'title' => __('Site Domain/Path', 'wp-ultimo'),
'tooltip' => __('Enter the complete domain for the site', 'wp-ultimo'),
'wrapper_classes' => 'wu-w-full',
'html_attr' => array(
'v-bind:placeholder' => 'tab === "domain" ? "mysite.com" : "mysite"',
'v-on:input' => 'domain = tab === "domain" ? $event.target.value.toLowerCase().replace(/[^a-z0-9-.-]+/g, "") : $event.target.value.toLowerCase().replace(/[^a-z0-9-]+/g, "")',
'v-bind:value' => 'domain',
),
),
),
),
'type' => array(
'type' => 'select',
'title' => __('Site Type', 'wp-ultimo'),
'value' => $type,
'placeholder' => '',
'options' => array(
'default' => __('Regular WP Site', 'wp-ultimo'),
'site_template' => __('Site Template', 'wp-ultimo'),
'customer_owned' => __('Customer-Owned', 'wp-ultimo'),
),
'html_attr' => array(
'v-model' => 'type',
),
),
'membership_id' => array(
'type' => 'model',
'title' => __('Associated Membership', 'wp-ultimo'),
'placeholder' => __('Search Membership...', 'wp-ultimo'),
'value' => '',
'tooltip' => '',
'wrapper_html_attr' => array(
'v-show' => "type === 'customer_owned'",
),
'html_attr' => array(
'data-model' => 'membership',
'data-value-field' => 'id',
'data-label-field' => 'reference_code',
'data-search-field' => 'reference_code',
'data-max-items' => 1,
),
),
'copy' => array(
'type' => 'toggle',
'title' => __('Copy Site', 'wp-ultimo'),
'desc' => __('Select an existing site to use as a starting point.', 'wp-ultimo'),
'html_attr' => array(
'v-model' => 'copy',
),
),
'template_site' => array(
'type' => 'model',
'title' => __('Template Site', 'wp-ultimo'),
'placeholder' => __('Search Sites...', 'wp-ultimo'),
'desc' => __('The site selected will be copied and used as a starting point.', 'wp-ultimo'),
'value' => $template_id,
'html_attr' => array(
'data-model' => 'site',
'data-selected' => $site ? json_encode($site->to_search_results()) : '',
'data-value-field' => 'blog_id',
'data-label-field' => 'title',
'data-search-field' => 'title',
'data-max-items' => 1,
),
'wrapper_html_attr' => array(
'v-show' => 'copy',
),
),
'copy_media' => array(
'type' => 'toggle',
'title' => __('Copy Media on Duplication', 'wp-ultimo'),
'desc' => __('Copy media files from the template site on duplication. Disabling this can lead to broken images on the new site.', 'wp-ultimo'),
'value' => true,
'wrapper_html_attr' => array(
'v-show' => 'copy',
),
),
'wu-when' => array(
'type' => 'hidden',
'value' => base64_encode('init'),
),
'submit_button' => array(
'type' => 'submit',
'title' => $save_label,
'placeholder' => $save_label,
'value' => 'save',
'classes' => 'button button-primary wu-w-full',
'wrapper_classes' => 'wu-items-end wu-text-right',
'html_attr' => array(
'v-bind:disabled' => 'install_type !== tab && tab !== "domain"',
),
),
);
$d = wu_get_site_domain_and_path('replace');
$form = new \WP_Ultimo\UI\Form('add_new_site', $fields, array(
'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' => array(
'data-wu-app' => 'add_new_site',
'data-state' => wu_convert_to_state(array(
'tab' => is_subdomain_install() ? 'sub-domain' : 'sub-directory',
'install_type' => is_subdomain_install() ? 'sub-domain' : 'sub-directory',
'membership' => $membership_id,
'type' => $type,
'copy' => $site ? $site->get_id() : 0,
'base_url' => str_replace('replace.', '', (string) $d->domain) . '/',
'scheme' => is_ssl() ? 'https://' : 'http://',
'domain' => $path,
)),
),
));
$form->render();
} // end render_add_new_site_modal;
/**
* Allow child classes to register widgets, if they need them.
*
* @since 1.8.2
* @return void
*/
public function register_widgets() {} // end register_widgets;
/**
* Returns an array with the labels for the edit page.
*
* @since 1.8.2
* @return array
*/
public function get_labels() {
return array(
'deleted_message' => __('Site removed successfully.', 'wp-ultimo'),
'search_label' => __('Search Site', 'wp-ultimo'),
);
} // end get_labels;
/**
* Returns the title of the page.
*
* @since 2.0.0
* @return string Title of the page.
*/
public function get_title() {
return __('Sites', 'wp-ultimo');
} // end get_title;
/**
* 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 __('Sites', 'wp-ultimo');
} // end get_menu_title;
/**
* Allows admins to rename the sub-menu (first item) for a top-level page.
*
* @since 2.0.0
* @return string False to use the title menu or string with sub-menu title.
*/
public function get_submenu_title() {
return __('Sites', 'wp-ultimo');
} // end get_submenu_title;
/**
* Returns the action links for that page.
*
* @since 1.8.2
* @return array
*/
public function action_links() {
return array(
array(
'label' => __('Add Site'),
'icon' => 'wu-circle-with-plus',
'classes' => 'wubox',
'url' => wu_get_form_url('add_new_site'),
),
);
} // end action_links;
/**
* Loads the list table for this particular page.
*
* @since 2.0.0
* @return \WP_Ultimo\List_Tables\Base_List_Table
*/
public function table() {
return new \WP_Ultimo\List_Tables\Site_List_Table();
} // end table;
} // end class Site_List_Admin_Page;

View File

@ -0,0 +1,881 @@
<?php
/**
* WP Ultimo System Info Admin Page.
*
* @package WP_Ultimo
* @subpackage Admin_Pages
* @since 2.0.0
*/
namespace WP_Ultimo\Admin_Pages;
use WP_Ultimo\Logger;
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* WP Ultimo System Info Admin Page.
*/
class System_Info_Admin_Page extends Base_Admin_Page {
/**
* Holds the ID for this page, this is also used as the page slug.
*
* @var string
*/
protected $id = 'wp-ultimo-system-info';
/**
* Is this a top-level menu or a submenu?
*
* @since 1.8.2
* @var string
*/
protected $type = 'submenu';
/**
* If this is a submenu, we need a parent menu to attach this to
*
* @since 1.8.2
* @var string
*/
protected $parent = 'none';
/**
* Allows us to highlight another menu page, if this page has no parent page at all.
*
* @since 2.0.0
* @var boolean
*/
protected $highlight_menu_slug = 'wp-ultimo-settings';
/**
* 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;
/**
* 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 = array(
'network_admin_menu' => 'manage_network',
);
/**
* Allow child classes to add further initializations.
*
* @since 1.8.2
* @return void
*/
public function init() {
add_action('wp_ajax_wu_generate_text_file_system_info', array($this, 'generate_text_file_system_info'));
} // end init;
/**
* Allow child classes to register scripts and styles that can be loaded on the output function, for example.
*
* @since 1.8.2
* @return void
*/
public function register_scripts() {
wp_enqueue_script('dashboard');
wp_enqueue_script('clipboard');
} // end register_scripts;
/**
* Allow child classes to register widgets, if they need them.
*
* @since 1.8.2
* @return void
*/
public function register_widgets() {
$screen = get_current_screen();
foreach ($this->get_data() as $name_type => $data) {
add_meta_box('wp-table-system-info-' . sanitize_title($name_type), $name_type, function() use ($data) {
$this->output_table_system_info($data);
}, $screen->id, 'normal', null);
} // end foreach;
} // end register_widgets;
/**
* Display system info Table
*
* @since 2.0.0
*
* @param array $data Data.
* @return void
*/
public function output_table_system_info($data) {
$screen = get_current_screen();
wu_get_template('system-info/system-info-table', array(
'data' => $data,
'screen' => $screen,
));
} // end output_table_system_info;
/**
* Returns the title of the page.
*
* @since 2.0.0
* @return string Title of the page.
*/
public function get_title() {
return __('System Info', 'wp-ultimo');
} // end get_title;
/**
* 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 __('System Info', 'wp-ultimo');
} // end get_menu_title;
/**
* Allows admins to rename the sub-menu (first item) for a top-level page.
*
* @since 2.0.0
* @return string False to use the title menu or string with sub-menu title.
*/
public function get_submenu_title() {
return __('Dashboard', 'wp-ultimo');
} // end get_submenu_title;
/**
* Every child class should implement the output method to display the contents of the page.
*
* @since 1.8.2
* @return void
*/
public function output() {
$screen = get_current_screen();
wu_get_template('system-info/system-info', array(
'data' => $this->get_data(),
'screen' => $screen,
));
} // end output;
/**
* Get data for system info
*
* @since 2.0.0
* @return array
*/
public function get_data() {
global $wp_filesystem, $wpdb;
$pad_spaces = 45;
$theme = wp_get_theme();
$browser = $this->get_browser();
$plugins = $this->get_all_plugins();
$active_plugins = $this->get_active_plugins();
$active_plugins_main_site = $this->get_active_plugins_on_main_site();
$memory_limit = (int) str_replace('M', '', ini_get('memory_limit'));
$memory_usage = $this->get_memory_usage();
// translators: %s is the number of seconds.
$max_execution_time = sprintf(__('%s seconds', 'wp-ultimo'), ini_get('max_execution_time'));
$all_options = $this->get_all_options();
$all_options_serialized = serialize($all_options);
$all_options_bytes = round(mb_strlen($all_options_serialized, '8bit') / 1024, 2);
$all_options_transients = $this->get_transients_in_options($all_options);
$array_active_plugins = array();
$array_constants_options = array(
'SAVEQUERIES',
'WP_DEBUG',
'WP_DEBUG_DISPLAY',
'WP_DEBUG_LOG',
'WP_DISABLE_FATAL_ERROR_HANDLER',
'SCRIPT_DEBUG',
'WP_ENV',
'NOBLOGREDIRECT',
);
$array_constants = array();
foreach ($array_constants_options as $constant) {
$array_constants[] = array(
'tooltip' => '',
'title' => $constant,
'value' => defined($constant) ? (is_bool(constant($constant)) ? __('Enabled', 'wp-ultimo') : constant($constant)) : __('Disabled', 'wp-ultimo'),
);
} // end foreach;
foreach ($plugins as $plugin_path => $plugin) {
if (in_array($plugin_path, array_keys($active_plugins), true)) {
$plugin_uri = '';
if (isset($plugin['PluginURI'])) {
$plugin_uri = ' (' . $plugin['PluginURI'] . ')';
} // end if;
$array_active_plugins[] = array(
'tooltip' => '',
'title' => $plugin['Name'],
'value' => $plugin['Version'] . $plugin_uri
);
} // end if;
} // end foreach;
$array_active_plugins_main_site = array();
foreach ($plugins as $plugin_path => $plugin) {
if (in_array($plugin_path, $active_plugins_main_site, true)) {
$plugin_uri = '';
if (isset($plugin['PluginURI'])) {
$plugin_uri = ' (' . $plugin['PluginURI'] . ')';
} // end if;
$array_active_plugins_main_site[] = array(
'tooltip' => '',
'title' => $plugin['Name'],
'value' => $plugin['Version'] . $plugin_uri
);
} // end if;
} // end foreach;
$wpultimo_settings = array();
foreach ($this->get_all_wp_ultimo_settings() as $setting => $value) {
if (is_array($value)) {
continue;
} // end if;
$wpultimo_settings[$setting] = array(
'tooltip' => '',
'title' => $setting,
'value' => $value
);
} // end foreach;
$array_wu_tables = array();
foreach ($wpdb->ms_global_tables as $key => $value) {
if (strncmp((string) $value, 'wu_', strlen('wu_')) === 0 && !array_key_exists($value, $array_wu_tables)) {
$array_wu_tables[$value] = array(
'tooltip' => '',
'title' => $value,
'value' => get_network_option(null, "wpdb_{$value}_version")
);
} // end if;
} // end foreach;
$array_license_data = array();
$customer = \WP_Ultimo\License::get_instance()->get_customer();
$license = \WP_Ultimo\License::get_instance()->get_license();
if (!empty($customer) && !empty($license)) {
$array_license_data = array(
'username' => array(
'tooltip' => '',
'title' => 'Username',
'value' => vsprintf('%s %s', array( $customer->first, $customer->last ) ),
),
'email' => array(
'tooltip' => '',
'title' => 'E-mail',
'value' => $customer->email,
),
'license-key' => array(
'tooltip' => '',
'title' => 'License Key',
'value' => substr_replace((string) $license->secret_key, str_repeat('*', 16), 4, 24),
),
);
} // end if;
return apply_filters('wu_system_info_data', array(
'WordPress and System Settings' => array(
'wp-ultimo-version' => array(
'tooltip' => 'WP Ultimo current version installed locally',
'title' => 'WP Ultimo Version',
'value' => wu_get_version(),
),
'wordpress-version' => array(
'tooltip' => '',
'title' => 'WordPress Version',
'value' => get_bloginfo('version')
),
'php-version' => array(
'tooltip' => '',
'title' => 'PHP Version',
'value' => PHP_VERSION
),
'mysql-version' => array(
'tooltip' => '',
'title' => 'MySQL Version ',
'value' => $wpdb->db_version()
),
'web-server' => array(
'tooltip' => '',
'title' => 'Web Server',
'value' => $_SERVER['SERVER_SOFTWARE']
),
'wordpress-url' => array(
'tooltip' => '',
'title' => 'WordPress URL',
'value' => get_bloginfo('wpurl')
),
'home-url' => array(
'tooltip' => '',
'title' => 'Home URL',
'value' => get_bloginfo('url')
),
'content-directory' => array(
'tooltip' => '',
'title' => 'Content Directory',
'value' => WP_CONTENT_DIR
),
'content-url' => array(
'tooltip' => '',
'title' => 'Content URL',
'value' => WP_CONTENT_URL
),
'plugins-directory' => array(
'tooltip' => '',
'title' => 'Plugins Directory',
'value' => WP_PLUGIN_DIR
),
'pluguins-url' => array(
'tooltip' => '',
'title' => 'Plugins URL',
'value' => WP_PLUGIN_URL
),
'uploads-directory' => array(
'tooltip' => '',
'title' => 'Uploads Directory',
'value' => (defined('UPLOADS') ? UPLOADS : WP_CONTENT_DIR . '/uploads')
),
'pluguins-url' => array(
'tooltip' => '',
'title' => 'Cookie Domain',
'value' => defined('COOKIE_DOMAIN') ? COOKIE_DOMAIN ? COOKIE_DOMAIN : __('Disabled', 'wp-ultimo') : __('Not set', 'wp-ultimo')
),
'multisite-active' => array(
'tooltip' => '',
'title' => 'Multi-Site Active',
'value' => is_multisite() ? __('Yes', 'wp-ultimo') : __('No', 'wp-ultimo')
),
'php-current-time-gmt' => array(
'tooltip' => '',
'title' => 'PHP Current Time - GMT',
'value' => wu_get_current_time('mysql', true),
),
'timezone' => array(
'tooltip' => '',
'title' => 'Timezone',
'value' => wp_timezone_string(),
),
'php-current-time' => array(
'tooltip' => '',
'title' => 'PHP Current Time - with Timezone',
'value' => wu_get_current_time()
),
'database-current-time' => array(
'tooltip' => '',
'title' => 'Database Current Time',
'value' => gmdate('Y-m-d H:i:s', strtotime((string) $wpdb->get_row('SELECT NOW() as time;')->time))
),
'php-curl-support' => array(
'tooltip' => '',
'title' => 'PHP cURL Support',
'value' => function_exists('curl_init') ? __('Yes', 'wp-ultimo') : __('No', 'wp-ultimo')
),
'php-gd-time' => array(
'tooltip' => '',
'title' => 'PHP GD Support',
'value' => function_exists('gd_info') ? __('Yes', 'wp-ultimo') : __('No', 'wp-ultimo')
),
'php-memory-limit' => array(
'tooltip' => '',
'title' => 'PHP Memory Limit',
'value' => $memory_limit . 'M'
),
'php-memory-usage' => array(
'tooltip' => '',
'title' => 'PHP Memory Usage',
'value' => $memory_usage . 'M (' . round($memory_usage / $memory_limit * $pad_spaces, 0) . '%)'
),
'php-post-max-size' => array(
'tooltip' => '',
'title' => 'PHP Post Max Size',
'value' => ini_get('post_max_size')
),
'php-upload-max-size' => array(
'tooltip' => '',
'title' => 'PHP Upload Max Size',
'value' => ini_get('upload_max_filesize')
),
'php-max-execution-time' => array(
'tooltip' => '',
'title' => 'PHP Max Execution Time',
'value' => $max_execution_time
),
'php-allow-url-fopen' => array(
'tooltip' => '',
'title' => 'PHP Allow URL Fopen',
'value' => ini_get('allow_url_fopen')
),
'php-max-file-uploads' => array(
'tooltip' => '',
'title' => 'PHP Max File Uploads',
'value' => ini_get('max_file_uploads')
),
'wp-options-count' => array(
'tooltip' => '',
'title' => 'WP Options Count',
'value' => count($all_options)
),
'wp-options-size' => array(
'tooltip' => '',
'title' => 'WP Options Size',
'value' => $all_options_bytes . 'kb'
),
'wp-options-transients' => array(
'tooltip' => '',
'title' => 'WP Options Transients',
'value' => count($all_options_transients)
),
'wp-debug' => array(
'tooltip' => '',
'title' => 'WP Options Transients',
'value' => defined('WP_DEBUG') ? WP_DEBUG ? __('Enabled', 'wp-ultimo') : __('Disabled', 'wp-ultimo') : __('Not set', 'wp-ultimo')
),
'script-debug' => array(
'tooltip' => '',
'title' => 'WP Options Transients',
'value' => defined('SCRIPT_DEBUG') ? SCRIPT_DEBUG ? __('Enabled', 'wp-ultimo') : __('Disabled', 'wp-ultimo') : __('Not set', 'wp-ultimo')
),
'save-queries' => array(
'tooltip' => '',
'title' => 'WP Options Transients',
'value' => defined('SAVEQUERIES') ? SAVEQUERIES ? __('Enabled', 'wp-ultimo') : __('Disabled', 'wp-ultimo') : __('Not set', 'wp-ultimo')
),
'autosave-interval' => array(
'tooltip' => '',
'title' => 'WP Options Transients',
'value' => defined('AUTOSAVE_INTERVAL') ? AUTOSAVE_INTERVAL ? AUTOSAVE_INTERVAL : __('Disabled', 'wp-ultimo') : __('Not set', 'wp-ultimo')
),
'wp_post_revisions' => array(
'tooltip' => '',
'title' => 'WP Options Transients',
'value' => defined('WP_POST_REVISIONS') ? WP_POST_REVISIONS ? WP_POST_REVISIONS : __('Disabled', 'wp-ultimo') : __('Not set', 'wp-ultimo')
),
'disable_wp_cron' => array(
'tooltip' => '',
'title' => 'DISABLE_WP_CRON',
'value' => defined('DISABLE_WP_CRON') ? DISABLE_WP_CRON ? DISABLE_WP_CRON : __('Yes', 'wp-ultimo') : __('No', 'wp-ultimo')
),
'wp_lang' => array(
'tooltip' => '',
'title' => 'WPLANG',
'value' => defined('WPLANG') ? WPLANG ? WPLANG : __('Yes', 'wp-ultimo') : __('No', 'wp-ultimo')
),
'wp_memory_limit' => array(
'tooltip' => '',
'title' => 'WP_MEMORY_LIMIT',
'value' => (defined('WP_MEMORY_LIMIT') && WP_MEMORY_LIMIT) ? WP_MEMORY_LIMIT : __('Not set', 'wp-ultimo')
),
'wp_max_memory_limit' => array(
'tooltip' => '',
'title' => 'WP_MAX_MEMORY_LIMIT',
'value' => (defined('WP_MAX_MEMORY_LIMIT') && WP_MAX_MEMORY_LIMIT) ? WP_MAX_MEMORY_LIMIT : __('Not set', 'wp-ultimo')
),
'operating-system' => array(
'tooltip' => '',
'title' => 'Operating System',
'value' => $browser['platform']
),
'browser' => array(
'tooltip' => '',
'title' => 'Browser',
'value' => $browser['name'] . ' ' . $browser['version']
),
'user-agent' => array(
'tooltip' => '',
'title' => 'User Agent',
'value' => $browser['user_agent']
),
),
'Active Theme' => array(
'active-theme' => array(
'tooltip' => '',
'title' => 'Active Theme',
'value' => $theme->get('Name') . ' - ' . $theme->get('Version') . '(' . $theme->get('ThemeURI') . ')'
),
),
'Active Plugins' => $array_active_plugins,
'Active Plugins on Main Site' => $array_active_plugins_main_site,
'WP Ultimo Database Status' => $array_wu_tables,
'WP Ultimo Core Settings' => array_merge(
array(
'logs-directory' => array(
'tooltip' => '',
'title' => 'Logs Directory',
'value' => is_writable(Logger::get_logs_folder()) ? __('Writable', 'wp-ultimo') : __('Not Writable', 'wp-ultimo')
),
),
$wpultimo_settings
),
'Defined Constants' => $array_constants,
'License' => $array_license_data
));
} // end get_data;
/**
* Generate text file of system info data
*
* @since 2.0.0
* @return void
*/
public function generate_text_file_system_info() {
$file_name = sprintf("$this->id-%s.txt", gmdate('Y-m-d'));
$txt = fopen($file_name, 'w') or die('Unable to open file!');
foreach ($this->get_data() as $type) {
foreach ($type as $item) {
fwrite($txt, $item['title'] . ': ' . $item['value'] . PHP_EOL);
} // end foreach;
} // end foreach;
fclose($txt);
header('Content-Description: File Transfer');
header('Content-Disposition: attachment; filename=' . basename($file_name));
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: ' . filesize($file_name));
header('Content-Type: text/plain');
readfile($file_name);
die;
} // end generate_text_file_system_info;
/**
* Get browser data
*
* @since 1.1.5
* @return array
*/
public function get_browser() {
// http://www.php.net/manual/en/function.get-browser.php#101125.
// Cleaned up a bit, but overall it's the same.
$user_agent = $_SERVER['HTTP_USER_AGENT'];
$browser_name = 'Unknown';
$platform = 'Unknown';
$version = '';
// First get the platform
if (preg_match('/linux/i', (string) $user_agent)) {
$platform = 'Linux';
} elseif (preg_match('/macintosh|mac os x/i', (string) $user_agent)) {
$platform = 'Mac';
} elseif (preg_match('/windows|win32/i', (string) $user_agent)) {
$platform = 'Windows';
} // end if;
// Next get the name of the user agent yes seperately and for good reason
if (preg_match('/MSIE/i', (string) $user_agent) && !preg_match('/Opera/i', (string) $user_agent)) {
$browser_name = 'Internet Explorer';
$browser_name_short = 'MSIE';
} elseif (preg_match('/Firefox/i', (string) $user_agent)) {
$browser_name = 'Mozilla Firefox';
$browser_name_short = 'Firefox';
} elseif (preg_match('/Chrome/i', (string) $user_agent)) {
$browser_name = 'Google Chrome';
$browser_name_short = 'Chrome';
} elseif (preg_match('/Safari/i', (string) $user_agent)) {
$browser_name = 'Apple Safari';
$browser_name_short = 'Safari';
} elseif (preg_match('/Opera/i', (string) $user_agent)) {
$browser_name = 'Opera';
$browser_name_short = 'Opera';
} elseif (preg_match('/Netscape/i', (string) $user_agent)) {
$browser_name = 'Netscape';
$browser_name_short = 'Netscape';
} // end if;
// Finally get the correct version number
$known = array('Version', $browser_name_short, 'other');
$pattern = '#(?<browser>' . join('|', $known) . ')[/ ]+(?<version>[0-9.|a-zA-Z.]*)#';
if (!preg_match_all($pattern, (string) $user_agent, $matches)) {
// We have no matching number just continue
} // end if;
// See how many we have
$i = count($matches['browser']);
if ($i !== 1) {
// We will have two since we are not using 'other' argument yet
// See if version is before or after the name
if (strripos((string) $user_agent, 'Version') < strripos((string) $user_agent, (string) $browser_name_short)) {
$version = $matches['version'][0];
} else {
$version = $matches['version'][1];
} // end if;
} else {
$version = $matches['version'][0];
} // end if;
// Check if we have a version number
if (empty($version)) {
$version = '?';
} // end if;
return array(
'user_agent' => $user_agent,
'name' => $browser_name,
'version' => $version,
'platform' => $platform,
'pattern' => $pattern
);
} // end get_browser;
/**
* Get list of all the plugins
*
* @return array
*/
public function get_all_plugins() {
return get_plugins();
} // end get_all_plugins;
/**
* Get only the active plugins
*
* @return array
*/
public function get_active_plugins() {
return (array) get_site_option( 'active_sitewide_plugins', array() );
} // end get_active_plugins;
/**
* Get only the active plugins on main site
*
* @return array
*/
public function get_active_plugins_on_main_site() {
return (array) get_option('active_plugins', array());
} // end get_active_plugins_on_main_site;
/**
* Get memory usage
*/
public function get_memory_usage(): float {
return round(memory_get_usage() / 1024 / 1024, 2);
} // end get_memory_usage;
/**
* Get all the ioptions
*
* @return array
*/
public function get_all_options() {
// Not to be confused with the core deprecated get_alloptions
return wp_load_alloptions();
} // end get_all_options;
/**
* Return all the desired WP Ultimo Settings
*
* @since 1.1.5
* @return array
*/
public function get_all_wp_ultimo_settings() {
$exclude = array(
'email',
'logo',
'color',
'from_name',
'paypal',
'stripe',
'terms_content',
'wu-',
'license_key',
'api-',
'manual_payment_instructions',
);
$include = array('enable');
$return_settings = array();
$settings = new \WP_Ultimo\Settings;
foreach ($settings->get_all() as $setting => $value) {
$add = true;
foreach ($exclude as $ex) {
if (stristr($setting, $ex) !== false) {
$add = false;
break;
} // end if;
} // end foreach;
if ($add) {
$return_settings[$setting] = $value;
} // end if;
} // end foreach;
return $return_settings;
} // end get_all_wp_ultimo_settings;
/**
* Get the transients om the options
*
* @param array $options Options.
* @return array
*/
public function get_transients_in_options($options) {
$transients = array();
foreach ($options as $name => $value) {
if (stristr($name, 'transient')) {
$transients[$name] = $value;
} // end if;
} // end foreach;
return $transients;
} // end get_transients_in_options;
} // end class System_Info_Admin_Page;

View File

@ -0,0 +1,215 @@
<?php
/**
* WP Ultimo About Admin Page.
*
* @package WP_Ultimo
* @subpackage Admin_Pages
* @since 2.0.0
*/
namespace WP_Ultimo\Admin_Pages;
use \WP_Ultimo\Tax\Tax;
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* WP Ultimo About Admin Page.
*/
class Tax_Rates_Admin_Page extends Base_Admin_Page {
/**
* Holds the ID for this page, this is also used as the page slug.
*
* @var string
*/
protected $id = 'wp-ultimo-tax-rates';
/**
* Is this a top-level menu or a submenu?
*
* @since 1.8.2
* @var string
*/
protected $type = 'submenu';
/**
* 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-settings';
/**
* 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 = array(
'network_admin_menu' => 'manage_network',
);
/**
* Returns the title of the page.
*
* @since 2.0.0
* @return string Title of the page.
*/
public function get_title() {
return __('Tax Rates', 'wp-ultimo');
} // end get_title;
/**
* 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 __('Tax Rates', 'wp-ultimo');
} // end get_menu_title;
/**
* Allows admins to rename the sub-menu (first item) for a top-level page.
*
* @since 2.0.0
* @return string False to use the title menu or string with sub-menu title.
*/
public function get_submenu_title() {
return __('Tax Rates', 'wp-ultimo');
} // end get_submenu_title;
/**
* Every child class should implement the output method to display the contents of the page.
*
* @since 1.8.2
* @return void
*/
public function output() {
do_action('wu_load_tax_rates_list_page');
$columns = apply_filters('wu_tax_rates_columns', array(
'title' => __('Label', 'wp-ultimo'),
'country' => __('Country', 'wp-ultimo'),
'state' => __('State / Province', 'wp-ultimo'),
'city' => __('City', 'wp-ultimo'),
'tax_rate' => __('Tax Rate (%)', 'wp-ultimo'),
'move' => '',
));
wu_get_template('taxes/list', array(
'columns' => $columns,
'screen' => get_current_screen(),
'types' => Tax::get_instance()->get_tax_rate_types(),
));
} // end output;
/**
* Adds the cure bg image here as well.
*
* @since 2.0.0
* @return void
*/
public function register_scripts() {
parent::register_scripts();
wp_register_script('wu-tax-rates', wu_get_asset('tax-rates.js', 'js'), array('wu-admin', 'wu-vue', 'underscore', 'wu-selectizer'), wu_get_version(), false);
wp_localize_script('wu-tax-rates', 'wu_tax_ratesl10n', array(
'name' => __('Tax', 'wp-ultimo'),
'confirm_message' => __('Are you sure you want to delete this rows?', 'wp-ultimo'),
'confirm_delete_tax_category_message' => __('Are you sure you want to delete this tax category?', 'wp-ultimo'),
));
wp_enqueue_script('wu-vue-sortable', '//cdn.jsdelivr.net/npm/sortablejs@1.8.4/Sortable.min.js', array(), wu_get_version());
wp_enqueue_script('wu-vue-draggable', '//cdnjs.cloudflare.com/ajax/libs/Vue.Draggable/2.20.0/vuedraggable.umd.min.js', array(), wu_get_version());
wp_enqueue_script('wu-tax-rates');
} // end register_scripts;
/**
* Adds field widgets to edit pages with the same Form/Field APIs used elsewhere.
*
* @see Take a look at /inc/ui/form and inc/ui/field for reference.
* @since 2.0.0
*
* @param string $id ID of the widget.
* @param array $atts Array of attributes to pass to the form.
* @return void
*/
protected function add_fields_widget($id, $atts = array()) {
$atts = wp_parse_args($atts, array(
'widget_id' => $id,
'before' => '',
'after' => '',
'title' => __('Fields', 'wp-ultimo'),
'position' => 'side',
'screen' => get_current_screen(),
'fields' => array(),
'html_attr' => array(),
'classes' => '',
'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',
));
add_meta_box("wp-ultimo-{$id}-widget", $atts['title'], function() use ($atts) {
if (wu_get_isset($atts['html_attr'], 'data-wu-app')) {
$atts['fields']['loading'] = array(
'type' => 'note',
'desc' => sprintf('<div class="wu-block wu-text-center wu-blinking-animation wu-text-gray-600 wu-my-1 wu-text-2xs wu-uppercase wu-font-semibold">%s</div>', __('Loading...', 'wp-ultimo')),
'wrapper_html_attr' => array(
'v-if' => 0,
),
);
} // end if;
/**
* Instantiate the form for the order details.
*
* @since 2.0.0
*/
$form = new \WP_Ultimo\UI\Form($atts['widget_id'], $atts['fields'], array(
'views' => 'admin-pages/fields',
'classes' => 'wu-widget-list wu-striped wu-m-0 wu--mt-2 wu--mb-3 wu--mx-3 ' . $atts['classes'],
'field_wrapper_classes' => $atts['field_wrapper_classes'],
'html_attr' => $atts['html_attr'],
'before' => $atts['before'],
'after' => $atts['after'],
));
$form->render();
}, $atts['screen']->id, $atts['position'], null);
} // end add_fields_widget;
} // end class Tax_Rates_Admin_Page;

View File

@ -0,0 +1,312 @@
<?php
/**
* WP Ultimo Customize/Add New Template Previewer Page.
*
* @package WP_Ultimo
* @subpackage Admin_Pages
* @since 2.0.0
*/
namespace WP_Ultimo\Admin_Pages;
use \WP_Ultimo\UI\Template_Previewer;
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* WP Ultimo Template Previewer Customize/Add New Admin Page.
*/
class Template_Previewer_Customize_Admin_Page extends Customizer_Admin_Page {
/**
* Holds the ID for this page, this is also used as the page slug.
*
* @var string
*/
protected $id = 'wp-ultimo-customize-template-previewer';
/**
* Is this a top-level menu or a submenu?
*
* @since 1.8.2
* @var string
*/
protected $type = 'submenu';
/**
* 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-settings';
/**
* 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 = array(
'network_admin_menu' => 'wu_customize_invoice_template',
);
/**
* Returns the preview URL. This is then added to the iframe.
*
* @since 2.0.0
* @return string
*/
public function get_preview_url() {
$url = get_site_url(null);
return add_query_arg(array(
'customizer' => 1,
Template_Previewer::get_instance()->get_preview_parameter() => 1,
), $url);
} // end get_preview_url;
/**
* Allow child classes to register widgets, if they need them.
*
* @since 1.8.2
* @return void
*/
public function register_widgets() {
$this->add_save_widget('save', array(
'fields' => array(
'preview_url_parameter' => array(
'type' => 'text',
'title' => __('URL Parameter', 'wp-ultimo'),
'desc' => __('This is the URL parameter WP Ultimo will use to generate the template preview URLs.', 'wp-ultimo'),
'value' => Template_Previewer::get_instance()->get_setting('preview_url_parameter', 'template-preview'),
),
'enabled' => array(
'type' => 'toggle',
'title' => __('Active', 'wp-ultimo'),
'desc' => __('If your site templates are not loading, you can disable the top-bar using this setting.', 'wp-ultimo'),
'value' => Template_Previewer::get_instance()->get_setting('enabled', true),
'html_attr' => array(
),
),
),
));
$custom_logo_id = Template_Previewer::get_instance()->get_setting('custom_logo');
$custom_logo = wp_get_attachment_image_src($custom_logo_id, 'full');
$custom_logo = $custom_logo ? $custom_logo[0] : false;
$fields = array(
'tab' => array(
'type' => 'tab-select',
'wrapper_classes' => '',
'wrapper_html_attr' => array(
'v-cloak' => 1,
),
'html_attr' => array(
'v-model' => 'tab',
),
'options' => array(
'general' => __('General', 'wp-ultimo'),
'colors' => __('Colors', 'wp-ultimo'),
'images' => __('Images', 'wp-ultimo'),
),
),
'display_responsive_controls' => array(
'type' => 'toggle',
'title' => __('Show Responsive Controls', 'wp-ultimo'),
'desc' => __('Toggle to show or hide the responsive controls.', 'wp-ultimo'),
'value' => true,
'wrapper_html_attr' => array(
'v-show' => 'require("tab", "general")',
'v-cloak' => 1,
),
'html_attr' => array(
'v-model' => 'display_responsive_controls',
),
),
'button_text' => array(
'type' => 'text',
'title' => __('Button Text', 'wp-ultimo'),
'value' => __('Use this Template', 'wp-ultimo'),
'wrapper_html_attr' => array(
'v-show' => 'require("tab", "general")',
'v-cloak' => 1,
),
'html_attr' => array(
'v-model.lazy' => 'button_text',
),
),
'bg_color' => array(
'type' => 'color-picker',
'title' => __('Background Color', 'wp-ultimo'),
'desc' => __('Choose the background color for the top-bar.', 'wp-ultimo'),
'value' => '#f9f9f9',
'wrapper_html_attr' => array(
'v-show' => 'require("tab", "colors")',
'v-cloak' => 1,
),
'html_attr' => array(
'v-model' => 'bg_color',
),
),
'button_bg_color' => array(
'type' => 'color-picker',
'title' => __('Button BG Color', 'wp-ultimo'),
'desc' => __('Pick the background color for the button.', 'wp-ultimo'),
'wrapper_html_attr' => array(
'v-show' => 'require("tab", "colors")',
'v-cloak' => 1,
),
'html_attr' => array(
'v-model' => 'button_bg_color',
),
),
'use_custom_logo' => array(
'type' => 'toggle',
'title' => __('Use Custom Logo', 'wp-ultimo'),
'desc' => __('You can set a different logo to be used on the top-bar.', 'wp-ultimo'),
'wrapper_html_attr' => array(
'v-show' => 'require("tab", "images")',
'v-cloak' => 1,
),
'html_attr' => array(
'v-model' => 'use_custom_logo',
),
),
'custom_logo' => array(
'type' => 'image',
'stacked' => true,
'title' => __('Custom Logo', 'wp-ultimo'),
'desc' => __('The logo is displayed on the preview page top-bar.', 'wp-ultimo'),
'value' => $custom_logo_id,
'img' => $custom_logo,
'wrapper_html_attr' => array(
'v-show' => 'require("tab", "images") && require("use_custom_logo", true)',
'v-cloak' => 1,
),
),
);
$settings = Template_Previewer::get_instance()->get_settings();
$state = array_merge($settings, array(
'tab' => 'general',
'refresh' => true,
));
$this->add_fields_widget('customizer', array(
'title' => __('Customizer', 'wp-ultimo'),
'position' => 'side',
'fields' => $fields,
'html_attr' => array(
'style' => 'margin-top: -6px;',
'data-wu-app' => 'site_template_customizer',
'data-wu-customizer-panel' => true,
'data-state' => json_encode($state),
),
));
} // end register_widgets;
/**
* Returns the title of the page.
*
* @since 2.0.0
* @return string Title of the page.
*/
public function get_title() {
return __('Customize Template Previewer', 'wp-ultimo');
} // end get_title;
/**
* 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 __('Customize Template Previewer', 'wp-ultimo');
} // end get_menu_title;
/**
* Returns the action links for that page.
*
* @since 1.8.2
* @return array
*/
public function action_links() {
return array();
} // end action_links;
/**
* Returns the labels to be used on the admin page.
*
* @since 2.0.0
* @return array
*/
public function get_labels() {
return array(
'customize_label' => __('Customize Template Previewer', 'wp-ultimo'),
'add_new_label' => __('Customize Template Previewer', 'wp-ultimo'),
'edit_label' => __('Edit Template Previewer', 'wp-ultimo'),
'updated_message' => __('Template Previewer updated with success!', 'wp-ultimo'),
'title_placeholder' => __('Enter Template Previewer Name', 'wp-ultimo'),
'title_description' => __('This name is used for internal reference only.', 'wp-ultimo'),
'save_button_label' => __('Save Changes', 'wp-ultimo'),
'save_description' => '',
);
} // end get_labels;
/**
* Should implement the processes necessary to save the changes made to the object.
*
* @since 2.0.0
* @return void
*/
public function handle_save() {
$settings = Template_Previewer::get_instance()->save_settings($_POST);
$array_params = array(
'updated' => 1,
);
$url = add_query_arg($array_params);
wp_redirect($url);
exit;
} // end handle_save;
} // end class Template_Previewer_Customize_Admin_Page;

View File

@ -0,0 +1,261 @@
<?php
/**
* Admin bar shortcuts menu
*
* Adds the shortcuts menu to the admin bar.
*
* @category WP Ultimo
* @package WP_Ultimo
* @author Gustavo Modesto <gustavo@wpultimo.com>
* @since 2.0.0
*/
namespace WP_Ultimo\Admin_Pages;
use WP_Ultimo\Settings;
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* This class adds the top bar admin navigation menu
*
* @since 2.0.0
*/
class Top_Admin_Nav_Menu {
/**
* Adds the hooks and actions
*
* @since 1.0.0
* @return void
*/
public function __construct() {
add_action('admin_bar_menu', array($this, 'add_top_bar_menus'), 50);
} // end __construct;
/**
* Adds the WP Ultimo top-bar shortcut menu
*
* @since 1.1.0
* @param \WP_Admin_Bar $wp_admin_bar The admin bar identifier.
* @return void
*/
public function add_top_bar_menus($wp_admin_bar) {
// Only for super admins
if (!current_user_can('manage_network')) {
return;
} // end if;
// Add Parent element
$parent = array(
'id' => 'wp-ultimo',
'title' => __('WP Ultimo', 'wp-ultimo'),
'href' => current_user_can('wu_read_dashboard') ? network_admin_url('admin.php?page=wp-ultimo') : '#',
'meta' => array(
'class' => 'wp-ultimo-top-menu',
'title' => __('Go to the dashboard', 'wp-ultimo'),
)
);
// Site
$sites = array(
'id' => 'wp-ultimo-sites',
'parent' => 'wp-ultimo',
'title' => __('Manage Sites', 'wp-ultimo'),
'href' => network_admin_url('admin.php?page=wp-ultimo-sites'),
'meta' => array(
'class' => 'wp-ultimo-top-menu',
'title' => __('Go to the sites page', 'wp-ultimo'),
)
);
// Memberships
$memberships = array(
'id' => 'wp-ultimo-memberships',
'parent' => 'wp-ultimo',
'title' => __('Manage Memberships', 'wp-ultimo'),
'href' => network_admin_url('admin.php?page=wp-ultimo-memberships'),
'meta' => array(
'class' => 'wp-ultimo-top-menu',
'title' => __('Go to the memberships page', 'wp-ultimo'),
)
);
// Customers
$customers = array(
'id' => 'wp-ultimo-customers',
'parent' => 'wp-ultimo',
'title' => __('Customers', 'wp-ultimo'),
'href' => network_admin_url('admin.php?page=wp-ultimo-customers'),
'meta' => array(
'class' => 'wp-ultimo-top-menu',
'title' => __('Go to the customers page', 'wp-ultimo'),
)
);
// Products
$products = array(
'id' => 'wp-ultimo-products',
'parent' => 'wp-ultimo',
'title' => __('Products', 'wp-ultimo'),
'href' => network_admin_url('admin.php?page=wp-ultimo-products'),
'meta' => array(
'class' => 'wp-ultimo-top-menu',
'title' => __('Go to the products page', 'wp-ultimo'),
)
);
// Payments
$payments = array(
'id' => 'wp-ultimo-payments',
'parent' => 'wp-ultimo',
'title' => __('Payments', 'wp-ultimo'),
'href' => network_admin_url('admin.php?page=wp-ultimo-payments'),
'meta' => array(
'class' => 'wp-ultimo-top-menu',
'title' => __('Go to the payments page', 'wp-ultimo'),
)
);
// Discount Codes
$discount_codes = array(
'id' => 'wp-ultimo-discount-codes',
'parent' => 'wp-ultimo',
'title' => __('Discount Codes', 'wp-ultimo'),
'href' => network_admin_url('admin.php?page=wp-ultimo-discount-codes'),
'meta' => array(
'class' => 'wp-ultimo-top-menu',
'title' => __('Go to the discount codes page', 'wp-ultimo'),
)
);
$container = array(
'id' => 'wp-ultimo-settings-group',
'parent' => 'wp-ultimo',
'group' => true,
'title' => __('Settings Container', 'wp-ultimo'),
'href' => '#',
'meta' => array(
'class' => 'wp-ultimo-top-menu ab-sub-secondary',
'title' => __('Go to the settings page', 'wp-ultimo'),
)
);
// Settings
$settings = array(
'id' => 'wp-ultimo-settings',
'parent' => 'wp-ultimo-settings-group',
'title' => __('Settings', 'wp-ultimo'),
'href' => network_admin_url('admin.php?page=wp-ultimo-settings'),
'meta' => array(
'class' => 'wp-ultimo-top-menu ab-sub-secondary',
'title' => __('Go to the settings page', 'wp-ultimo'),
)
);
/**
* Add items to the top bar.
*/
$wp_admin_bar->add_node($parent);
if (current_user_can('wu_read_sites')) {
$wp_admin_bar->add_node($sites);
} //end if;
if (current_user_can('wu_read_memberships')) {
$wp_admin_bar->add_node($memberships);
} //end if;
if (current_user_can('wu_read_customers')) {
$wp_admin_bar->add_node($customers);
} //end if;
if (current_user_can('wu_read_products')) {
$wp_admin_bar->add_node($products);
} //end if;
if (current_user_can('wu_read_payments')) {
$wp_admin_bar->add_node($payments);
} //end if;
if (current_user_can('wu_read_discount_codes')) {
$wp_admin_bar->add_node($discount_codes);
} //end if;
if (current_user_can('wu_read_settings')) {
$wp_admin_bar->add_node($container);
$wp_admin_bar->add_node($settings);
} //end if;
/*
* Add the sub-menus.
*/
$settings_tabs = Settings::get_instance()->get_sections();
$has_addons = false;
foreach ($settings_tabs as $tab => $tab_info) {
if (wu_get_isset($tab_info, 'invisible')) {
continue;
} // end if;
$parent = 'wp-ultimo-settings';
if (wu_get_isset($tab_info, 'addon', false)) {
$parent = 'wp-ultimo-settings-addons';
} // end if;
$settings_tab = array(
'id' => 'wp-ultimo-settings-' . $tab,
'parent' => $parent,
'title' => $tab_info['title'],
'href' => network_admin_url('admin.php?page=wp-ultimo-settings&tab=') . $tab,
'meta' => array(
'class' => 'wp-ultimo-top-menu',
'title' => __('Go to the settings page', 'wp-ultimo'),
)
);
$wp_admin_bar->add_node($settings_tab);
$addons_item = array(
'id' => 'wp-ultimo-settings-addons',
'parent' => 'wp-ultimo-settings-group',
'title' => __('Add-ons', 'wp-ultimo'),
'href' => wu_network_admin_url('wp-ultimo-addons'),
'meta' => array(
'class' => 'wp-ultimo-top-menu ab-sub-secondary',
'title' => __('Go to the add-ons page', 'wp-ultimo'),
),
);
$wp_admin_bar->add_node($addons_item);
} // end foreach;
} // end add_top_bar_menus;
} // end class Top_Admin_Nav_Menu;

View File

@ -0,0 +1,380 @@
<?php
/**
* WP Ultimo System Info Admin Page.
*
* @package WP_Ultimo
* @subpackage Admin_Pages
* @since 2.0.0
*/
namespace WP_Ultimo\Admin_Pages;
use WP_Ultimo\Logger;
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* WP Ultimo System Info Admin Page.
*/
class View_Logs_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-view-logs';
/**
* Is this a top-level menu or a submenu?
*
* @since 1.8.2
* @var string
*/
protected $type = 'submenu';
/**
* If this is a submenu, we need a parent menu to attach this to
*
* @since 1.8.2
* @var string
*/
protected $parent = 'none';
/**
* Allows us to highlight another menu page, if this page has no parent page at all.
*
* @since 2.0.0
* @var boolean
*/
protected $highlight_menu_slug = 'wp-ultimo-events';
/**
* 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;
/**
* 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 = array(
'network_admin_menu' => 'manage_network',
);
/**
* Allow child classes to add further initializations.
*
* @since 1.8.2
* @return void
*/
public function init() {
add_action('wp_ajax_wu_handle_view_logs', array($this, 'handle_view_logs'));
} // end init;
/**
* Registers extra scripts needed for this page.
*
* @since 2.0.0
* @return void
*/
public function register_scripts() {
parent::register_scripts();
\WP_Ultimo\Scripts::get_instance()->register_script('wu-view-log', wu_get_asset('view-logs.js', 'js'), array('jquery'));
wp_localize_script('wu-view-log', 'wu_view_logs', array(
'i18n' => array(
'copied' => __('Copied!', 'wp-ultimo'),
),
));
wp_enqueue_script('wu-view-log');
wp_enqueue_script('clipboard');
} // end register_scripts;
/**
* Returns the title of the page.
*
* @since 2.0.0
* @return string Title of the page.
*/
public function get_title() {
return __('View Log', 'wp-ultimo');
} // end get_title;
/**
* 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 __('View Log', 'wp-ultimo');
} // end get_menu_title;
/**
* Handles the actions for the logs and system info.
*
* @since 2.0.0
*
* @return array
*/
public function handle_view_logs() {
$logs_list = list_files(Logger::get_logs_folder(), 2, array(
'index.html',
));
$logs_list = array_combine(array_values($logs_list), array_map(fn($file) => str_replace(Logger::get_logs_folder(), '', (string) $file), $logs_list));
if (empty($logs_list)) {
$logs_list[''] = __('No log files found', 'wp-ultimo');
} // end if;
$file = wu_request('file');
$file_name = '';
$contents = '';
// Security check
if ($file && !stristr((string) $file, Logger::get_logs_folder())) {
wp_die(__('You can see files that are not WP Ultimo\'s logs', 'wp-ultimo'));
} // end if;
if (!$file && !empty($logs_list)) {
$file = !$file && !empty($logs_list) ? current(array_keys($logs_list)) : false;
} // end if;
$file_name = str_replace(Logger::get_logs_folder(), '', (string) $file);
$default_content = wu_request('return_ascii', 'yes') === 'yes' ? wu_get_template_contents('events/ascii-badge') : __('No log entries found.', 'wp-ultimo');
$contents = $file && file_exists($file) ? file_get_contents($file) : $default_content;
$response = array(
'file' => $file,
'file_name' => $file_name,
'contents' => $contents,
'logs_list' => $logs_list,
);
if (wp_doing_ajax()) {
wp_send_json_success($response);
} else {
return $response;
} // end if;
} // end handle_view_logs;
/**
* Allow child classes to register widgets, if they need them.
*
* @since 1.8.2
* @return void
*/
public function register_widgets() {
$info = $this->handle_view_logs();
add_meta_box('wp-ultimo-log-contents', __('Log Contents', 'wp-ultimo'), array($this, 'output_default_widget_payload'), get_current_screen()->id, 'normal', null, $info);
$this->add_fields_widget('file-selector', array(
'title' => __('Log Files', 'wp-ultimo'),
'fields' => array(
'log_file' => array(
'type' => 'select',
'title' => __('Select Log File', 'wp-ultimo'),
'placeholder' => __('Select Log File', 'wp-ultimo'),
'value' => wu_request('file'),
'tooltip' => '',
'options' => $info['logs_list'],
),
'download' => array(
'type' => 'submit',
'title' => __('Download Log', 'wp-ultimo'),
'value' => 'download',
'classes' => 'button button-primary wu-w-full',
),
),
));
$this->add_fields_widget('info', array(
'title' => __('Timestamps', 'wp-ultimo'),
'position' => 'side',
'fields' => array(
'date_modified' => array(
'title' => __('Last Modified at', 'wp-ultimo'),
'type' => 'text-edit',
'date' => true,
'value' => date_i18n('Y-m-d H:i:s', filemtime($info['file'])),
'display_value' => date_i18n('Y-m-d H:i:s', filemtime($info['file'])),
)
),
));
} // end register_widgets;
/**
* Outputs the pre block that shows the content.
*
* @since 2.0.0
*
* @param mixed $unused Not sure.
* @param array $data Arguments passed by add_meta_box.
* @return void
*/
public function output_default_widget_payload($unused, $data) {
wu_get_template('events/widget-payload', array(
'title' => __('Event Payload', 'wp-ultimo'),
'loading_text' => __('Loading Payload', 'wp-ultimo'),
'payload' => $data['args']['contents'],
));
} // end output_default_widget_payload;
/**
* Returns the labels to be used on the admin page.
*
* @since 2.0.0
* @return array
*/
public function get_labels() {
return array(
'edit_label' => __('View Log', 'wp-ultimo'),
'add_new_label' => __('View Log', 'wp-ultimo'),
'title_placeholder' => __('Enter Customer', 'wp-ultimo'),
'title_description' => __('Viewing file: ', 'wp-ultimo'),
'delete_button_label' => __('Delete Log File', 'wp-ultimo'),
'delete_description' => __('Be careful. This action is irreversible.', 'wp-ultimo'),
);
} // end get_labels;
/**
* Returns the object being edit at the moment.
*
* @since 2.0.0
* @return array
*/
public function get_object() {
return array();
} // end get_object;
/**
* Register additional hooks to page load such as the action links and the save processing.
*
* @since 2.0.0
* @return void
*/
public function page_loaded() {
/**
* Get the action links
*/
$this->action_links = $this->action_links();
/**
* Process save, if necessary
*/
$this->process_save();
} // end page_loaded;
/**
* Should implement the processes necessary to save the changes made to the object.
*
* @since 2.0.0
* @return void
*/
public function handle_save() {
$action = wu_request('submit_button', 'none');
if ($action === 'none') {
WP_Ultimo()->notices->add(__('Something wrong happened', 'wp-ultimo'), 'error', 'network-admin');
return;
} // end if;
$file = wu_request('log_file', false);
if (!file_exists($file)) {
WP_Ultimo()->notices->add(__('File not found', 'wp-ultimo'), 'error', 'network-admin');
return;
} // end if;
if ($action === 'download') {
$file_name = str_replace(Logger::get_logs_folder(), '', (string) $file);
header('Content-Type: application/octet-stream');
header("Content-Disposition: attachment; filename=$file_name");
header('Pragma: no-cache');
readfile($file);
exit;
} elseif ($action === 'delete') {
$status = unlink($file);
if (!$status) {
WP_Ultimo()->notices->add(__('We were unable to delete file', 'wp-ultimo'), 'error', 'network-admin');
return;
} // end if;
} // end if;
$url = remove_query_arg('log_file');
wp_redirect(add_query_arg('deleted', 1, $url));
exit;
} // end handle_save;
} // end class View_Logs_Admin_Page;

View File

@ -0,0 +1,414 @@
<?php
/**
* WP Ultimo Webhook 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\Models\Webhook;
/**
* WP Ultimo Webhook Edit/Add New Admin Page.
*/
class Webhook_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-webhook';
/**
* 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 = 'webhook';
/**
* 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-webhooks';
/**
* 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;
/**
* 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 = array(
'network_admin_menu' => 'wu_edit_webhooks',
);
/**
* Registers the necessary scripts and styles for this admin page.
*
* @since 2.0.0
* @return void
*/
public function register_scripts() {
parent::register_scripts();
wp_register_script('wu-webhook-page', wu_get_asset('webhook-page.js', 'js'), array('jquery', 'wu-sweet-alert'));
wp_localize_script('wu-webhook-page', 'wu_webhook_page', array(
'i18n' => array(
'error_title' => __('Webhook Test', 'wp-ultimo'),
'error_message' => __('An error occurred when sending the test webhook, please try again.', 'wp-ultimo'),
'copied' => __('Copied!', 'wp-ultimo'),
),
));
wp_enqueue_script('wu-webhook-page');
} // end register_scripts;
/**
* Register ajax forms that we use for webhook.
*
* @since 2.0.0
* @return void
*/
public function register_forms() {
/*
* Delete Webhook - Confirmation modal
*/
add_filter('wu_data_json_success_delete_webhook_modal', fn($data_json) => array(
'redirect_url' => wu_network_admin_url('wp-ultimo-webhooks', array('deleted' => 1))
));
} // end register_forms;
/**
* Allow child classes to register widgets, if they need them.
*
* @since 1.8.2
* @return void
*/
public function register_widgets() {
parent::register_widgets();
$this->add_fields_widget('domain-url', array(
'title' => __('Webhook URL', 'wp-ultimo'),
'position' => 'normal',
'fields' => array(
'webhook_url' => array(
'type' => 'url',
'title' => __('Webhook URL', 'wp-ultimo'),
'desc' => __('The URL where we will send the payload when the event triggers.', 'wp-ultimo'),
'placeholder' => __('https://example.com', 'wp-ultimo'),
'value' => $this->get_object()->get_webhook_url(),
),
'actions' => array(
'type' => 'actions',
'tooltip' => __('The event .', 'wp-ultimo'),
'actions' => array(
'send_test_event' => array(
'title' => __('Send Test Event', 'wp-ultimo'),
'action' => 'wu_send_test_event',
'object_id' => $this->get_object()->get_id(),
'loading_text' => 'Sending Test...',
),
),
'html_attr' => array(
'data-page' => 'edit',
),
'wrapper_classes' => 'wu-items-left wu-justify-start',
),
),
));
add_meta_box('wp-ultimo-payload', __('Event Payload', 'wp-ultimo'), array($this, 'output_default_widget_payload'), get_current_screen()->id, 'normal');
$this->add_list_table_widget('events', array(
'title' => __('Events', 'wp-ultimo'),
'table' => new \WP_Ultimo\List_Tables\Inside_Events_List_Table(),
'query_filter' => array($this, 'query_filter'),
));
$event_list = array();
foreach (wu_get_event_types() as $key => $value) {
$event_list[$key] = $value['name'];
} // end foreach;
$this->add_save_widget('save', array(
'fields' => array(
'event' => array(
'type' => 'select',
'title' => __('Event', 'wp-ultimo'),
'desc' => __('The event that triggers this webhook.', 'wp-ultimo'),
'placeholder' => __('Select Event', 'wp-ultimo'),
'options' => $event_list,
'value' => $this->get_object()->get_event(),
),
),
));
$this->add_fields_widget('active', array(
'title' => __('Active', 'wp-ultimo'),
'fields' => array(
'active' => array(
'type' => 'toggle',
'title' => __('Active', 'wp-ultimo'),
'tooltip' => __('Deactivate will end the event trigger for this webhook.', 'wp-ultimo'),
'desc' => __('Use this option to manually enable or disable this webhook.', 'wp-ultimo'),
'value' => $this->get_object()->is_active(),
),
),
));
$this->add_fields_widget('options', array(
'title' => __('Options', 'wp-ultimo'),
'fields' => array(
'integration' => array(
'edit' => true,
'title' => __('Integration', 'wp-ultimo'),
'type' => 'text-edit',
'placeholder' => 'manual',
'value' => $this->get_object()->get_integration(),
'display_value' => ucwords((string) $this->get_object()->get_integration()),
'tooltip' => __('Name of the service responsible for creating this webhook. If you are manually creating this webhook, use the value "manual".', 'wp-ultimo'),
),
'event_count' => array(
'title' => __('Run Count', 'wp-ultimo'),
'type' => 'text-edit',
'min' => 0,
'placeholder' => 0,
'edit' => true,
'value' => $this->get_object()->get_event_count(),
// translators: %d is the number of times that this webhook was triggered.
'display_value' => sprintf(__('This webhook was triggered %d time(s).', 'wp-ultimo'), $this->get_object()->get_event_count()),
'tooltip' => __('The number of times that this webhook was triggered so far. It includes test runs.', 'wp-ultimo'),
),
),
));
} // end register_widgets;
/**
* Outputs the markup for the payload widget.
*
* @since 2.0.0
* @return void
*/
public function output_default_widget_payload() {
$object_event_slug = $this->get_object()->get_event();
$event = wu_get_event_type($object_event_slug);
$payload = isset($event['payload']) ? json_encode(wu_maybe_lazy_load_payload($event['payload']), JSON_PRETTY_PRINT) : '{}';
wu_get_template('events/widget-payload', array(
'title' => __('Event Payload', 'wp-ultimo'),
'loading_text' => __('Loading Payload', 'wp-ultimo'),
'payload' => $payload,
));
} // end output_default_widget_payload;
/**
* 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 query_filter($args) {
$extra_args = array(
'object_type' => 'webhook',
'object_id' => absint($this->get_object()->get_id()),
);
return array_merge($args, $extra_args);
} // end query_filter;
/**
* Returns the title of the page.
*
* @since 2.0.0
* @return string Title of the page.
*/
public function get_title() {
return $this->edit ? __('Edit Webhook', 'wp-ultimo') : __('Add new Webhook', 'wp-ultimo');
} // end get_title;
/**
* 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 Webhook', 'wp-ultimo');
} // end get_menu_title;
/**
* Returns the action links for that page.
*
* @since 1.8.2
* @return array
*/
public function action_links() {
return array();
} // end action_links;
/**
* Returns the labels to be used on the admin page.
*
* @since 2.0.0
* @return array
*/
public function get_labels() {
return array(
'edit_label' => __('Edit Webhook', 'wp-ultimo'),
'add_new_label' => __('Add new Webhook', 'wp-ultimo'),
'updated_message' => __('Webhook updated successfully!', 'wp-ultimo'),
'title_placeholder' => __('Enter Webhook', 'wp-ultimo'),
'title_description' => '',
'save_button_label' => __('Save Webhook', 'wp-ultimo'),
'save_description' => '',
'delete_button_label' => __('Delete Webhook', 'wp-ultimo'),
'delete_description' => __('Be careful. This action is irreversible.', 'wp-ultimo'),
);
} // end get_labels;
/**
* Returns the object being edit at the moment.
*
* @since 2.0.0
* @return \WP_Ultimo\Models\Webhook
*/
public function get_object() {
if (wu_request('id')) {
$query = new \WP_Ultimo\Database\Webhooks\Webhook_Query;
$item = $query->get_item_by('id', wu_request('id'));
if (!$item) {
wp_redirect(wu_network_admin_url('wp-ultimo-webhooks'));
exit;
} // end if;
return $item;
} // end if;
return new Webhook;
} // end get_object;
/**
* Webhooks have titles.
*
* @since 2.0.0
*/
public function has_title(): bool {
return true;
} // end has_title;
/**
* Handles the save of this form.
*
* @since 2.0.0
* @return void
*/
public function handle_save() {
$object = $this->get_object();
$object->attributes($_POST);
if (is_wp_error($object->save())) {
$errors = implode('<br>', $object->save()->get_error_messages());
WP_Ultimo()->notices->add($errors, 'error', 'network-admin');
return;
} else {
$array_params = array(
'updated' => 1,
);
if ($this->edit === false) {
$array_params['id'] = $object->get_id();
} // end if;
$url = add_query_arg($array_params);
wp_redirect($url);
exit;
} // end if;
} // end handle_save;
} // end class Webhook_Edit_Admin_Page;

View File

@ -0,0 +1,281 @@
<?php
/**
* WP Ultimo Webhook Admin Page.
*
* @package WP_Ultimo
* @subpackage Admin_Pages
* @since 2.0.0
*/
namespace WP_Ultimo\Admin_Pages;
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* WP Ultimo Webhook Admin Page.
*/
class Webhook_List_Admin_Page extends List_Admin_Page {
/**
* Holds the ID for this page, this is also used as the page slug.
*
* @var string
*/
protected $id = 'wp-ultimo-webhooks';
/**
* Is this a top-level menu or a submenu?
*
* @since 1.8.2
* @var string
*/
protected $type = 'submenu';
/**
* 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;
/**
* 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 = array(
'network_admin_menu' => 'wu_read_webhooks',
);
/**
* Registers the necessary scripts and styles for this admin page.
*
* @since 2.0.0
* @return void
*/
public function register_scripts() {
parent::register_scripts();
wp_register_script('wu-webhook-page', wu_get_asset('webhook-page.js', 'js'), array('jquery', 'wu-sweet-alert'));
wp_localize_script('wu-webhook-page', 'wu_webhook_page', array(
'i18n' => array(
'error_title' => __('Webhook Test', 'wp-ultimo'),
'error_message' => __('An error occurred when sending the test webhook, please try again.', 'wp-ultimo'),
'copied' => __('Copied!', 'wp-ultimo'),
),
));
wp_enqueue_script('wu-webhook-page');
} // end register_scripts;
/**
* Register ajax forms that we use for add new webhooks.
*
* @since 2.0.0
* @return void
*/
public function register_forms() {
/*
* Add new webhook.
*/
wu_register_form('add_new_webhook_modal', array(
'render' => array($this, 'render_add_new_webhook_modal'),
'handler' => array($this, 'handle_add_new_webhook_modal'),
'capability' => 'wu_edit_webhooks',
));
} // end register_forms;
/**
* Renders the add new webhook modal.
*
* @since 2.0.0
* @return void
*/
function render_add_new_webhook_modal() {
$events = wu_get_event_types();
$event_options = array();
foreach ($events as $slug => $event) {
$event_options[$slug] = $event['name'];
} // end foreach;
$fields = array(
'name' => array(
'type' => 'text',
'title' => __('Webhook Name', 'wp-ultimo'),
'desc' => __('A name to easily identify your webhook.', 'wp-ultimo'),
'placeholder' => __('E.g. Zapier Integration', 'wp-ultimo'),
),
'event' => array(
'title' => __('Event', 'wp-ultimo'),
'type' => 'select',
'desc' => __('The event that will trigger the webhook.', 'wp-ultimo'),
'options' => $event_options
),
'webhook_url' => array(
'type' => 'url',
'title' => __('Webhook Url', 'wp-ultimo'),
'desc' => __('The url of your webhook.', 'wp-ultimo'),
'placeholder' => __('E.g. https://example.com/', 'wp-ultimo'),
),
'submit_button' => array(
'type' => 'submit',
'title' => __('Add New Webhook', 'wp-ultimo'),
'value' => 'save',
'classes' => 'button button-primary wu-w-full',
'wrapper_classes' => 'wu-items-end',
'html_attr' => array(
// 'v-bind:disabled' => '!confirmed',
),
),
);
$form = new \WP_Ultimo\UI\Form('edit_line_item', $fields, array(
'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' => array(
'data-wu-app' => 'edit_line_item',
'data-state' => json_encode(array(
'event' => ''
)),
),
));
$form->render();
} // end render_add_new_webhook_modal;
/**
* Handles the add new webhook modal.
*
* @since 2.0.0
* @return void
*/
public function handle_add_new_webhook_modal() {
$status = wu_create_webhook($_POST);
if (is_wp_error($status)) {
wp_send_json_error($status);
} else {
wp_send_json_success(array(
'redirect_url' => wu_network_admin_url('wp-ultimo-edit-webhook', array(
'id' => $status->get_id()
))
));
} // end if;
} // end handle_add_new_webhook_modal;
/**
* Allow child classes to register widgets, if they need them.
*
* @since 1.8.2
* @return void
*/
public function register_widgets() {} // end register_widgets;
/**
* Returns an array with the labels for the edit page.
*
* @since 1.8.2
* @return array
*/
public function get_labels() {
return array(
'deleted_message' => __('Webhook removed successfully.', 'wp-ultimo'),
'search_label' => __('Search Webhook', 'wp-ultimo'),
);
} // end get_labels;
/**
* Returns the title of the page.
*
* @since 2.0.0
* @return string Title of the page.
*/
public function get_title() {
return __('Webhooks', 'wp-ultimo');
} // end get_title;
/**
* 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 __('Webhooks', 'wp-ultimo');
} // end get_menu_title;
/**
* Allows admins to rename the sub-menu (first item) for a top-level page.
*
* @since 2.0.0
* @return string False to use the title menu or string with sub-menu title.
*/
public function get_submenu_title() {
return __('Webhooks', 'wp-ultimo');
} // end get_submenu_title;
/**
* Returns the action links for that page.
*
* @since 1.8.2
* @return array
*/
public function action_links() {
return array(
array(
'label' => __('Add New Webhook', 'wp-ultimo'),
'icon' => 'wu-circle-with-plus',
'classes' => 'wubox',
'url' => wu_get_form_url('add_new_webhook_modal'),
),
);
} // end action_links;
/**
* Loads the list table for this particular page.
*
* @since 2.0.0
* @return \WP_Ultimo\List_Tables\Base_List_Table
*/
public function table() {
return new \WP_Ultimo\List_Tables\Webhook_List_Table();
} // end table;
} // end class Webhook_List_Admin_Page;

View File

@ -0,0 +1,401 @@
<?php
/**
* Base admin page class.
*
* Abstract class that makes it easy to create new admin pages.
*
* Most of WP Ultimo pages are implemented using this class, which means that the filters and hooks
* listed below can be used to append content to all of our pages at once.
*
* @package WP_Ultimo
* @subpackage Admin_Pages
* @since 2.0.0
*/
namespace WP_Ultimo\Admin_Pages;
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Abstract class that makes it easy to create new admin pages.
*/
abstract class Wizard_Admin_Page extends Base_Admin_Page {
/**
* Should we hide admin notices on this page?
*
* @since 2.0.0
* @var boolean
*/
protected $hide_admin_notices = true;
/**
* Should we force the admin menu into a folded state?
*
* @since 2.0.0
* @var boolean
*/
protected $fold_menu = true;
/**
* Holds the section slug for the URLs.
*
* @since 2.0.0
* @var string
*/
protected $section_slug = 'step';
/**
* Defines if the step links on the side are clickable or not.
*
* @since 2.0.0
* @var boolean
*/
protected $clickable_navigation = false;
/**
* Defined the id to be used on the main form element.
*
* @since 2.0.0
* @var boolean
*/
protected $form_id = '';
/**
* Holds the active section for the wizard.
*
* @since 2.0.0
* @var array
*/
public $current_section;
/**
* Register additional hooks to page load such as the action links and the save processing.
*
* @since 2.0.0
* @return void
*/
public function page_loaded() {
/*
* Load sections to memory.
*/
$sections = $this->get_sections();
/*
* Sets current section for future reference.
*/
$this->current_section = $sections[$this->get_current_section()];
/*
* Process save, if necessary
*/
$this->process_save();
} // end page_loaded;
/**
* Handles saves, after verifying nonces and such. Should not be rewritten by child classes.
*
* @since 2.0.0
* @return void
*/
final public function process_save() {
$saving_tag = sprintf('saving_%s', $this->get_current_section());
if (isset($_REQUEST[$saving_tag])) {
check_admin_referer($saving_tag, '_wpultimo_nonce');
$handler = isset($this->current_section['handler']) ? $this->current_section['handler'] : array($this, 'default_handler');
/*
* Calls the saving function
*/
call_user_func($handler);
} // end if;
} // end process_save;
/**
* Returns the labels to be used on the admin page.
*
* @since 2.0.0
* @return array
*/
public function get_labels() {
return array(
'edit_label' => __('Edit Object', 'wp-ultimo'),
'add_new_label' => __('Add New Object', 'wp-ultimo'),
'updated_message' => __('Object updated with success!', 'wp-ultimo'),
'title_placeholder' => __('Enter Object Name', 'wp-ultimo'),
'title_description' => '',
'save_button_label' => __('Save', 'wp-ultimo'),
'save_description' => '',
);
} // end get_labels;
/**
* Registers widgets to the edit page.
*
* This implementation register the default save widget.
* Child classes that wish to inherit that widget while registering other,
* can do such by adding a parent::register_widgets() to their own register_widgets() method.
*
* @since 2.0.0
* @return void
*/
public function register_widgets() {
$screen = get_current_screen();
if (wu_get_isset($this->current_section, 'separator')) {
return;
} // end if;
add_meta_box('wp-ultimo-wizard-body', wu_get_isset($this->current_section, 'title', __('Section', 'wp-ultimo')), array($this, 'output_default_widget_body'), $screen->id, 'normal', null);
} // end register_widgets;
/**
* Outputs the markup for the default Save widget.
*
* @since 2.0.0
* @return void
*/
public function output_default_widget_body() {
echo '<div class="wu-p-4">';
$view = isset($this->current_section['view']) ? $this->current_section['view'] : array($this, 'default_view');
/*
* Calls the view function.
*/
call_user_func($view);
echo '</div>';
} // end output_default_widget_body;
/**
* Returns the logo to be used on the wizard.
*
* @since 2.0.0
* @return string
*/
public function get_logo() {
return '';
} // end get_logo;
/**
* Displays the contents of the edit page.
*
* @since 2.0.0
* @return void
*/
public function output() {
/*
* Renders the base edit page layout, with the columns and everything else =)
*/
wu_get_template('base/wizard', array(
'screen' => get_current_screen(),
'page' => $this,
'logo' => $this->get_logo(),
'labels' => $this->get_labels(),
'sections' => $this->get_sections(),
'current_section' => $this->get_current_section(),
'classes' => 'wu-w-full wu-mx-auto sm:wu-w-11/12 xl:wu-w-8/12 wu-mt-8 sm:wu-max-w-screen-lg',
'clickable_navigation' => $this->clickable_navigation,
'form_id' => $this->form_id,
));
} // end output;
/**
* Returns the first section of the signup process
*
* @return string
*/
public function get_first_section() {
$keys = array_keys($this->get_sections());
if (isset($keys[1])) {
return $keys[1];
} else {
return false;
} // end if;
} // end get_first_section;
/**
* Get the current section
*
* @return string
*/
public function get_current_section() {
$sections = $this->get_sections();
$sections = array_filter($sections, fn($item) => wu_get_isset($item, 'addon') === false);
$current_section = isset($_GET[$this->section_slug]) ? sanitize_key($_GET[$this->section_slug]) : current(array_keys($sections));
return $current_section;
} // end get_current_section;
/**
* Returns the page link for the current section.
*
* @since 2.0.0
*
* @param string $section Slug of the section. e.g. general.
* @return string
*/
public function get_section_link($section) {
return add_query_arg($this->section_slug, $section);
} // end get_section_link;
/**
* Returns the link to the next section on the wizard.
*
* @since 2.0.0
* @return string
*/
public function get_next_section_link() {
$sections = $this->get_sections();
$current_section = $this->get_current_section();
$keys = array_keys($sections);
return add_query_arg($this->section_slug, $keys[array_search($current_section, array_keys($sections), true) + 1]);
} // end get_next_section_link;
/**
* Returns the link to the previous section on the wizard.
*
* @since 2.0.0
* @return string
*/
public function get_prev_section_link() {
$sections = $this->get_sections();
$current_section = $this->get_current_section();
$keys = array_keys($sections);
return add_query_arg($this->section_slug, $keys[array_search($current_section, array_keys($sections), true) - 1]);
} // end get_prev_section_link;
/**
* Default handler for step submission. Simply redirects to the next step.
*
* @since 2.0.0
* @return void
*/
public function default_handler() {
wp_redirect($this->get_next_section_link());
exit;
} // end default_handler;
/**
* Default method for views.
*
* @since 2.0.0
* @return void
*/
public function default_view() {
$section = wp_parse_args($this->current_section, array(
'title' => '',
'description' => '',
'content' => '',
'fields' => array(),
'next_label' => __('Continue &rarr;', 'wp-ultimo'),
'back_label' => __('&larr; Go Back', 'wp-ultimo'),
'skip_label' => __('Skip this Step', 'wp-ultimo'),
'back' => false,
'skip' => false,
'next' => true,
));
/*
* Check if the section has fields
*/
if (!empty($section['fields'])) {
if (is_callable($section['fields'])) {
$section['fields'] = call_user_func($section['fields']);
} // end if;
$form = new \WP_Ultimo\UI\Form($this->get_current_section(), $section['fields'], array(
'views' => 'admin-pages/fields',
'classes' => 'wu-widget-list wu-striped wu-m-0 wu-mt-2 wu--mb-6 wu--mx-6',
'field_wrapper_classes' => 'wu-w-full wu-box-border wu-items-center wu-flex wu-justify-between wu-px-6 wu-py-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',
));
ob_start();
$form->render();
$section['content'] = ob_get_clean();
} // end if;
wu_get_template('wizards/setup/default', array_merge($section, array(
'page' => $this,
)));
} // end default_view;
/**
* Renders the default submit box with action buttons at the bottom of the wizard.
*
* @since 2.0.0
* @return void
*/
public function render_submit_box() {
wu_get_template('base/wizard/submit-box', array(
'screen' => get_current_screen(),
'page' => $this,
'labels' => $this->get_labels(),
));
} // end render_submit_box;
/**
* Wizard classes should implement a method that returns an array of sections and subsections.
*
* @since 2.0.0
* @return array
*/
abstract public function get_sections(); // end get_sections;
} // end class Wizard_Admin_Page;

View File

@ -0,0 +1,254 @@
<?php
/**
* WP Ultimo My_Account Admin Page.
*
* @package WP_Ultimo
* @subpackage Admin_Pages
* @since 2.0.0
*/
namespace WP_Ultimo\Admin_Pages\Customer_Panel;
// Exit if accessed directly
defined('ABSPATH') || exit;
use \WP_Ultimo\Admin_Pages\Base_Customer_Facing_Admin_Page;
/**
* WP Ultimo My_Account Admin Page.
*/
class Account_Admin_Page extends Base_Customer_Facing_Admin_Page {
/**
* Holds the ID for this page, this is also used as the page slug.
*
* @var string
*/
protected $id = 'account';
/**
* Menu position. This is only used for top-level menus
*
* @since 1.8.2
* @var integer
*/
protected $position = 101_010_101;
/**
* Dashicon to be used on the menu item. This is only used on top-level menus
*
* @since 1.8.2
* @var string
*/
protected $menu_icon = 'dashicons-wu-email';
/**
* 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;
/**
* Should we hide admin notices on this page?
*
* @since 2.0.0
* @var boolean
*/
protected $hide_admin_notices = true;
/**
* 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 = array(
'admin_menu' => 'exist',
'user_admin_menu' => 'exist',
);
/**
* The current site instance.
*
* @since 2.0.0
* @var \WP_Ultimo\Models\Site
*/
protected $current_site;
/**
* The current membership instance.
*
* @since 2.0.0
* @var \WP_Ultimo\Models\Membership
*/
protected $current_membership;
/**
* Checks if we need to add this page.
*
* @since 2.0.0
*/
public function __construct() {
$this->current_site = wu_get_current_site();
$this->current_membership = $this->current_site->get_membership();
$this->register_page_settings();
if ($this->current_site->get_type() === 'customer_owned') {
parent::__construct();
} // end if;
} // end __construct;
/**
* Loads the current site and membership.
*
* @since 1.8.2
* @return void
*/
public function page_loaded() {
$this->current_site = wu_get_current_site();
$this->current_membership = $this->current_site->get_membership();
$this->add_notices();
} // end page_loaded;
/**
* Adds notices after a membership is changed.
*
* @since 2.0.0
* @return void
*/
protected function add_notices() {
$nonce = wu_request('nonce');
$update_type = wu_request('updated');
if (empty($update_type)) {
return;
} // end if;
$update_message = apply_filters('wu_account_update_message', __('Your account was successfully updated.', 'wp-ultimo'), $update_type);
WP_Ultimo()->notices->add($update_message);
} // end add_notices;
/**
* Allow child classes to add hooks to be run once the page is loaded.
*
* @see https://codex.wordpress.org/Plugin_API/Action_Reference/load-(page)
* @since 1.8.2
* @return void
*/
public function hooks() {} // end hooks;
/**
* Allow child classes to add screen options; Useful for pages that have list tables.
*
* @since 1.8.2
* @return void
*/
public function screen_options() {} // end screen_options;
/**
* Allow child classes to register widgets, if they need them.
*
* @since 1.8.2
* @return void
*/
public function register_widgets() {
\WP_Ultimo\UI\Current_Membership_Element::get_instance()->as_metabox(get_current_screen()->id);
\WP_Ultimo\UI\Billing_Info_Element::get_instance()->as_metabox(get_current_screen()->id, 'side');
\WP_Ultimo\UI\Invoices_Element::get_instance()->as_metabox(get_current_screen()->id, 'side');
\WP_Ultimo\UI\Site_Actions_Element::get_instance()->as_metabox(get_current_screen()->id, 'side');
\WP_Ultimo\UI\Account_Summary_Element::get_instance()->as_metabox(get_current_screen()->id);
\WP_Ultimo\UI\Limits_Element::get_instance()->as_metabox(get_current_screen()->id);
\WP_Ultimo\UI\Domain_Mapping_Element::get_instance()->as_metabox(get_current_screen()->id, 'side');
\WP_Ultimo\UI\Login_Form_Element::get_instance()->as_inline_content(get_current_screen()->id, 'wu_dash_before_metaboxes');
\WP_Ultimo\UI\Simple_Text_Element::get_instance()->as_inline_content(get_current_screen()->id, 'wu_dash_before_metaboxes');
\WP_Ultimo\UI\Current_Site_Element::get_instance()->as_inline_content(get_current_screen()->id, 'wu_dash_before_metaboxes', array('show_admin_link' => false));
} // end register_widgets;
/**
* Returns the title of the page.
*
* @since 2.0.0
* @return string Title of the page.
*/
public function get_title() {
return __('Account', 'wp-ultimo');
} // end get_title;
/**
* 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 __('Account', 'wp-ultimo');
} // end get_menu_title;
/**
* Allows admins to rename the sub-menu (first item) for a top-level page.
*
* @since 2.0.0
* @return string False to use the title menu or string with sub-menu title.
*/
public function get_submenu_title() {
return __('Account', 'wp-ultimo');
} // end get_submenu_title;
/**
* Every child class should implement the output method to display the contents of the page.
*
* @since 1.8.2
* @return void
*/
public function output() {
/*
* Renders the base edit page layout, with the columns and everything else =)
*/
wu_get_template('base/dash', array(
'screen' => get_current_screen(),
'page' => $this,
'has_full_position' => false,
));
} // end output;
} // end class Account_Admin_Page;

View File

@ -0,0 +1,259 @@
<?php
/**
* WP Ultimo Add New Site Admin Page.
*
* @package WP_Ultimo
* @subpackage Admin_Pages
* @since 2.0.0
*/
namespace WP_Ultimo\Admin_Pages\Customer_Panel;
// Exit if accessed directly
defined('ABSPATH') || exit;
use \WP_Ultimo\Admin_Pages\Base_Customer_Facing_Admin_Page;
/**
* WP Ultimo Add New Site Admin Page.
*/
class Add_New_Site_Admin_Page extends Base_Customer_Facing_Admin_Page {
/**
* Holds the ID for this page, this is also used as the page slug.
*
* @var string
*/
protected $id = 'add-new-site';
/**
* Is this a top-level menu or a submenu?
*
* @since 1.8.2
* @var string
*/
protected $type = 'submenu';
/**
* Allows us to highlight another menu page, if this page has no parent page at all.
*
* @since 2.0.0
* @var boolean
*/
protected $highlight_menu_slug = 'sites';
/**
* Menu position. This is only used for top-level menus
*
* @since 1.8.2
* @var integer
*/
protected $position = 101_010_101;
/**
* Dashicon to be used on the menu item. This is only used on top-level menus
*
* @since 1.8.2
* @var string
*/
protected $menu_icon = 'dashicons-wu-browser';
/**
* 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;
/**
* Should we hide admin notices on this page?
*
* @since 2.0.0
* @var boolean
*/
protected $hide_admin_notices = true;
/**
* 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 = array(
'admin_menu' => 'exist',
'user_admin_menu' => 'exist',
);
/**
* The current customer instance.
*
* @since 2.0.0
* @var \WP_Ultimo\Models\Customer
*/
protected $customer;
/**
* The current site instance.
*
* @since 2.2.0
* @var \WP_Ultimo\Models\Site
*/
protected $current_site;
/**
* The current membership instance.
*
* @since 2.2.0
* @var \WP_Ultimo\Models\Membership|false
*/
protected $current_membership;
/**
* Checks if we need to add this page.
*
* @since 2.0.0
*/
public function __construct() {
$this->current_site = wu_get_current_site();
$this->current_membership = $this->current_site->get_membership();
$this->register_page_settings();
if ($this->current_site->get_type() === 'customer_owned') {
parent::__construct();
} // end if;
} // end __construct;
/**
* Loads the current site and membership.
*
* @since 1.8.2
* @return void
*/
public function page_loaded() {
$this->customer = wu_get_current_customer();
} // end page_loaded;
/**
* Allow child classes to add hooks to be run once the page is loaded.
*
* @see https://codex.wordpress.org/Plugin_API/Action_Reference/load-(page)
* @since 1.8.2
* @return void
*/
public function hooks() {} // end hooks;
/**
* Force the screen options so our customize options show up.
*
* @since 2.0.0
* @return void
*/
public function force_screen_options() {
if (get_current_screen()->id !== 'toplevel_page_sites') {
return;
} // end if;
// Forces Screen options so we can add our links.
add_screen_option('wu_fix', array(
'option' => 'test',
'value' => true,
));
} // end force_screen_options;
/**
* Allow child classes to add screen options; Useful for pages that have list tables.
*
* @since 1.8.2
* @return void
*/
public function screen_options() {} // end screen_options;
/**
* Allow child classes to register widgets, if they need them.
*
* @since 1.8.2
* @return void
*/
public function register_widgets() {
\WP_Ultimo\UI\Simple_Text_Element::get_instance()->as_inline_content(get_current_screen()->id, 'wu_dash_before_metaboxes');
\WP_Ultimo\UI\Checkout_Element::get_instance()->as_inline_content(get_current_screen()->id, 'wu_dash_before_metaboxes', array(
'slug' => 'wu-add-new-site',
'membership_limitations' => array('sites'),
));
} // end register_widgets;
/**
* Returns the title of the page.
*
* @since 2.0.0
* @return string Title of the page.
*/
public function get_title() {
return __('Add New Site', 'wp-ultimo');
} // end get_title;
/**
* 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 __('Add New Site', 'wp-ultimo');
} // end get_menu_title;
/**
* Allows admins to rename the sub-menu (first item) for a top-level page.
*
* @since 2.0.0
* @return string False to use the title menu or string with sub-menu title.
*/
public function get_submenu_title() {
return __('Add New Site', 'wp-ultimo');
} // end get_submenu_title;
/**
* Every child class should implement the output method to display the contents of the page.
*
* @since 1.8.2
* @return void
*/
public function output() {
/*
* Renders the base edit page layout, with the columns and everything else =)
*/
wu_get_template('base/dash', array(
'screen' => get_current_screen(),
'page' => $this,
'has_full_position' => false,
));
} // end output;
} // end class Add_New_Site_Admin_Page;

View File

@ -0,0 +1,191 @@
<?php
/**
* WP Ultimo Customer Checkout Admin Page.
*
* @package WP_Ultimo
* @subpackage Admin_Pages
* @since 2.0.0
*/
namespace WP_Ultimo\Admin_Pages\Customer_Panel;
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* WP Ultimo Dashboard Admin Page.
*/
class Checkout_Admin_Page extends \WP_Ultimo\Admin_Pages\Base_Customer_Facing_Admin_Page {
/**
* Holds the ID for this page, this is also used as the page slug.
*
* @var string
*/
protected $id = 'wu-checkout';
/**
* Is this a top-level menu or a submenu?
*
* @since 1.8.2
* @var string
*/
protected $type = 'submenu';
/**
* 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 = 'account';
/**
* 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;
/**
* 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 = array(
'user_admin_menu' => 'read',
'admin_menu' => 'read',
);
/**
* Should we hide admin notices on this page?
*
* @since 2.0.0
* @var boolean
*/
protected $hide_admin_notices = true;
/**
* Should we force the admin menu into a folded state?
*
* @since 2.0.0
* @var boolean
*/
protected $fold_menu = true;
/**
* Returns the title of the page.
*
* @since 2.0.0
* @return string Title of the page.
*/
public function get_title() {
return sprintf(__('Checkout', 'wp-ultimo'));
} // end get_title;
/**
* 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 __('Checkout', 'wp-ultimo');
} // end get_menu_title;
/**
* Registers the necessary scripts.
*
* @since 2.0.0
* @return void
*/
public function register_scripts() {
do_action('wu_checkout_scripts', null, null);
} // end register_scripts;
/**
* Overrides the page loaded method.
*
* @since 2.0.0
* @return void
*/
public function page_loaded() {
do_action('wu_setup_checkout', null);
parent::page_loaded();
} // end page_loaded;
/**
* Returns the sections for this Wizard.
*
* @since 2.0.0
* @return array
*/
public function get_sections() {
$sections = array(
'plan' => array(
'title' => __('Change Membership', 'wp-ultimo'),
'view' => array($this, 'display_checkout_form'),
),
);
return $sections;
} // end get_sections;
/**
* Displays the content of the activation section.
*
* @since 2.0.0
* @return void
*/
public function output() {
/*
* Renders the base edit page layout, with the columns and everything else =)
*/
wu_get_template('base/centered', array(
'screen' => get_current_screen(),
'page' => $this,
'content' => do_shortcode('[wu_checkout slug="wu-checkout"]'),
));
} // end output;
/**
* Allow child classes to register widgets, if they need them.
*
* @since 1.8.2
* @return void
*/
public function register_widgets() {
\WP_Ultimo\UI\Current_Membership_Element::get_instance()->as_metabox(get_current_screen()->id);
\WP_Ultimo\UI\Simple_Text_Element::get_instance()->as_inline_content(get_current_screen()->id, 'wu_centered_right');
} // end register_widgets;
} // end class Checkout_Admin_Page;

View File

@ -0,0 +1,290 @@
<?php
/**
* WP Ultimo My Sites Admin Page.
*
* @package WP_Ultimo
* @subpackage Admin_Pages
* @since 2.0.0
*/
namespace WP_Ultimo\Admin_Pages\Customer_Panel;
// Exit if accessed directly
defined('ABSPATH') || exit;
use \WP_Ultimo\Admin_Pages\Base_Customer_Facing_Admin_Page;
/**
* WP Ultimo My Sites Admin Page.
*/
class My_Sites_Admin_Page extends Base_Customer_Facing_Admin_Page {
/**
* Holds the ID for this page, this is also used as the page slug.
*
* @var string
*/
protected $id = 'sites';
/**
* Menu position. This is only used for top-level menus
*
* @since 1.8.2
* @var integer
*/
protected $position = 101_010_101;
/**
* Dashicon to be used on the menu item. This is only used on top-level menus
*
* @since 1.8.2
* @var string
*/
protected $menu_icon = 'dashicons-wu-browser';
/**
* 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;
/**
* Should we hide admin notices on this page?
*
* @since 2.0.0
* @var boolean
*/
protected $hide_admin_notices = true;
/**
* 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 = array(
'admin_menu' => 'exist',
'user_admin_menu' => 'exist',
);
/**
* The current customer instance.
*
* @since 2.0.0
* @var \WP_Ultimo\Models\Customer
*/
protected $customer;
/**
* The current site instance.
*
* @since 2.2.0
* @var \WP_Ultimo\Models\Site
*/
public $current_site;
/**
* The current membership instance.
*
* @since 2.2.0
* @var \WP_Ultimo\Models\Membership|false
*/
public $current_membership;
/**
* Checks if we need to add this page.
*
* @since 2.0.0
*/
public function __construct() {
$this->current_site = wu_get_current_site();
$this->current_membership = $this->current_site->get_membership();
$this->register_page_settings();
if ($this->current_site->get_type() === 'customer_owned') {
parent::__construct();
add_action('admin_menu', array($this, 'unset_default_my_sites_menu'));
add_action('admin_bar_menu', array($this, 'change_my_sites_link'), 90);
add_action('current_screen', array($this, 'force_screen_options'));
} // end if;
} // end __construct;
/**
* Loads the current site and membership.
*
* @since 1.8.2
* @return void
*/
public function page_loaded() {
$this->customer = wu_get_current_customer();
} // end page_loaded;
/**
* Allow child classes to add hooks to be run once the page is loaded.
*
* @see https://codex.wordpress.org/Plugin_API/Action_Reference/load-(page)
* @since 1.8.2
* @return void
*/
public function hooks() {} // end hooks;
/**
* Remove the default my sites link.
*
* @since 2.0.0
* @return void
*/
public function unset_default_my_sites_menu() {
global $submenu;
unset($submenu['index.php'][5]);
} // end unset_default_my_sites_menu;
/**
* Update the my sites link on the top-bar.
*
* @since 2.0.0
*
* @param object $wp_admin_bar The admin bar object.
* @return void
*/
public function change_my_sites_link($wp_admin_bar) {
$my_sites = $wp_admin_bar->get_node('my-sites');
if (empty($my_sites)) {
return;
} // end if;
$args = array(
'page' => 'sites',
);
$my_sites->href = add_query_arg($args, admin_url('admin.php'));
$wp_admin_bar->add_node($my_sites);
} // end change_my_sites_link;
/**
* Force the screen options so our customize options show up.
*
* @since 2.0.0
* @return void
*/
public function force_screen_options() {
if (get_current_screen()->id !== 'toplevel_page_sites') {
return;
} // end if;
// Forces Screen options so we can add our links.
add_screen_option('wu_fix', array(
'option' => 'test',
'value' => true,
));
} // end force_screen_options;
/**
* Allow child classes to add screen options; Useful for pages that have list tables.
*
* @since 1.8.2
* @return void
*/
public function screen_options() {} // end screen_options;
/**
* Allow child classes to register widgets, if they need them.
*
* @since 1.8.2
* @return void
*/
public function register_widgets() {
\WP_Ultimo\UI\Login_Form_Element::get_instance()->as_inline_content(get_current_screen()->id, 'wu_dash_before_metaboxes');
\WP_Ultimo\UI\Simple_Text_Element::get_instance()->as_inline_content(get_current_screen()->id, 'wu_dash_before_metaboxes');
\WP_Ultimo\UI\My_Sites_Element::get_instance()->as_inline_content(get_current_screen()->id, 'wu_dash_before_metaboxes');
} // end register_widgets;
/**
* Returns the title of the page.
*
* @since 2.0.0
* @return string Title of the page.
*/
public function get_title() {
return __('My Sites', 'wp-ultimo');
} // end get_title;
/**
* 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 __('My Sites', 'wp-ultimo');
} // end get_menu_title;
/**
* Allows admins to rename the sub-menu (first item) for a top-level page.
*
* @since 2.0.0
* @return string False to use the title menu or string with sub-menu title.
*/
public function get_submenu_title() {
return __('My Sites', 'wp-ultimo');
} // end get_submenu_title;
/**
* Every child class should implement the output method to display the contents of the page.
*
* @since 1.8.2
* @return void
*/
public function output() {
/*
* Renders the base edit page layout, with the columns and everything else =)
*/
wu_get_template('base/dash', array(
'screen' => get_current_screen(),
'page' => $this,
'has_full_position' => false,
));
} // end output;
} // end class My_Sites_Admin_Page;

View File

@ -0,0 +1,181 @@
<?php
/**
* WP Ultimo Switch Template Admin Page.
*
* @package WP_Ultimo
* @subpackage Admin_Pages
* @since 2.0.0
*/
namespace WP_Ultimo\Admin_Pages\Customer_Panel;
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* WP Ultimo Switch Template Admin Page.
*/
class Template_Switching_Admin_Page extends \WP_Ultimo\Admin_Pages\Base_Customer_Facing_Admin_Page {
/**
* Holds the ID for this page, this is also used as the page slug.
*
* @var string
*/
protected $id = 'wu-template-switching';
/**
* Is this a top-level menu or a submenu?
*
* @since 1.8.2
* @var string
*/
protected $type = 'submenu';
/**
* 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 = 'account';
/**
* 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;
/**
* 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 = array(
'user_admin_menu' => 'read',
'admin_menu' => 'read',
);
/**
* Should we hide admin notices on this page?
*
* @since 2.0.0
* @var boolean
*/
protected $hide_admin_notices = true;
/**
* Should we force the admin menu into a folded state?
*
* @since 2.0.0
* @var boolean
*/
protected $fold_menu = true;
/**
* If this customer facing page has menu settings.
*
* @since 2.0.9
* @var boolean
*/
protected $menu_settings = false;
/**
* Returns the title of the page.
*
* @since 2.0.0
* @return string Title of the page.
*/
public function get_title() {
return __('Switch Template', 'wp-ultimo');
} // end get_title;
/**
* 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 __('Switch Template', 'wp-ultimo');
} // end get_menu_title;
/**
* Registers the necessary scripts.
*
* @since 2.0.0
* @return void
*/
public function register_scripts() {
do_action('wu_template_switching_admin_page_scripts', null, null);
} // end register_scripts;
/**
* Overrides the page loaded method.
*
* @since 2.0.0
* @return void
*/
public function page_loaded() {
do_action('wu_template_switching_admin_page', null);
parent::page_loaded();
} // end page_loaded;
/**
* Displays the content of the activation section.
*
* @since 2.0.0
* @return void
*/
public function output() {
/*
* Renders the base edit page layout, with the columns and everything else =)
*/
wu_get_template('base/centered', array(
'screen' => get_current_screen(),
'page' => $this,
'content' => '',
'labels' => array(
'updated_message' => __('Template switched successfully!', 'wp-ultimo')
)
));
} // end output;
/**
* Allow child classes to register widgets, if they need them.
*
* @since 1.8.2
* @return void
*/
public function register_widgets() {
\WP_Ultimo\UI\Template_Switching_Element::get_instance()->as_metabox(get_current_screen()->id);
} // end register_widgets;
} // end class Template_Switching_Admin_Page;

View File

@ -0,0 +1,173 @@
<?php
/**
* WP Ultimo Debug Admin Page.
*
* @package WP_Ultimo
* @subpackage Admin_Pages\Debug
* @since 2.0.0
*/
namespace WP_Ultimo\Admin_Pages\Debug;
// Exit if accessed directly
defined('ABSPATH') || exit;
use WP_Ultimo\Admin_Pages\Base_Admin_Page;
use WP_Ultimo\Debug\Debug;
/**
* WP Ultimo Debug Admin Page.
*/
class Debug_Admin_Page extends Base_Admin_Page {
/**
* Holds the ID for this page, this is also used as the page slug.
*
* @var string
*/
protected $id = 'wp-ultimo-debug-pages';
/**
* Is this a top-level menu or a submenu?
*
* @since 1.8.2
* @var string
*/
protected $type = 'submenu';
/**
* 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-settings';
/**
* 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;
/**
* 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 = array(
'network_admin_menu' => 'capability_here',
);
/**
* Allow child classes to register widgets, if they need them.
*
* @since 1.8.2
* @return void
*/
public function register_widgets() {
add_meta_box(
'wp-ultimo-debug-pages',
__('All Registered Pages', 'wp-ultimo'),
array($this, 'render_debug_pages'),
get_current_screen()->id,
'normal',
null
);
} // end register_widgets;
/**
* Renders the list of WP Ultimo registered pages.
*
* @since 2.0.0
* @return void
*/
public function render_debug_pages() {
$pages = Debug::get_instance()->get_pages();
echo '<ul class="wu-flex wu-flex-wrap wu--mx-1">';
foreach ($pages as $page_id => $url) {
echo sprintf('
<li class="wu-w-1/2 wu-box-border">
<a class="wu-mx-1 wu-block wu-p-2 wu-box-border wu-border wu-border-gray-400 wu-border-solid wu-rounded" href="%s">%s</a>
</li>
', $url, $page_id);
} // end foreach;
echo '</ul>';
} // end render_debug_pages;
/**
* Returns the title of the page.
*
* @since 2.0.0
* @return string Title of the page.
*/
public function get_title() {
return __('Registered Pages', 'wp-ultimo');
} // end get_title;
/**
* 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 __('Registered Pages', 'wp-ultimo');
} // end get_menu_title;
/**
* Allows admins to rename the sub-menu (first item) for a top-level page.
*
* @since 2.0.0
* @return string False to use the title menu or string with sub-menu title.
*/
public function get_submenu_title() {
return __('Registered Pages', 'wp-ultimo');
} // end get_submenu_title;
/**
* Every child class should implement the output method to display the contents of the page.
*
* @since 1.8.2
* @return void
*/
public function output() {
wu_get_template('base/dash', array(
'page' => $this,
'screen' => get_current_screen(),
'has_full_position' => false,
));
} // end output;
} // end class Debug_Admin_Page;

View File

@ -0,0 +1,725 @@
<?php
/**
* The Register API endpoint.
*
* @package WP_Ultimo
* @subpackage API
* @since 2.0.0
*/
namespace WP_Ultimo\API;
use \WP_Ultimo\Checkout\Cart;
use \WP_Ultimo\Database\Sites\Site_Type;
use \WP_Ultimo\Database\Payments\Payment_Status;
use \WP_Ultimo\Database\Memberships\Membership_Status;
use \WP_Ultimo\Objects\Billing_Address;
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* The Register API endpoint.
*
* @since 2.0.0
*/
class Register_Endpoint {
use \WP_Ultimo\Traits\Singleton;
/**
* Loads the initial register route hooks.
*
* @since 2.0.0
* @return void
*/
public function init() {
add_action('wu_register_rest_routes', array($this, 'register_route'));
} // end init;
/**
* Adds a new route to the wu namespace, for the register endpoint.
*
* @since 2.0.0
*
* @param \WP_Ultimo\API $api The API main singleton.
* @return void
*/
public function register_route($api) {
$namespace = $api->get_namespace();
register_rest_route($namespace, '/register', array(
'methods' => \WP_REST_Server::READABLE,
'callback' => array($this, 'handle_get'),
'permission_callback' => \Closure::fromCallable([$api, 'check_authorization']),
));
register_rest_route($namespace, '/register', array(
'methods' => \WP_REST_Server::CREATABLE,
'callback' => array($this, 'handle_endpoint'),
'permission_callback' => \Closure::fromCallable([$api, 'check_authorization']),
'args' => $this->get_rest_args(),
));
} // end register_route;
/**
* Handle the register endpoint get for zapier integration reasons.
*
* @since 2.0.0
*
* @param \WP_REST_Request $request WP Request Object.
* @return array
*/
public function handle_get($request) {
return array(
'registration_status' => wu_get_setting('enable_registration', true) ? 'open' : 'closed',
);
} // end handle_get;
/**
* Handle the register endpoint logic.
*
* @since 2.0.0
*
* @param \WP_REST_Request $request WP Request Object.
* @return array
*/
public function handle_endpoint($request) {
global $wpdb;
$params = json_decode($request->get_body(), true);
if (\WP_Ultimo\API::get_instance()->should_log_api_calls()) {
wu_log_add('api-calls', json_encode($params, JSON_PRETTY_PRINT));
} // end if;
$validation_errors = $this->validate($params);
if (is_wp_error($validation_errors)) {
$validation_errors->add_data(array(
'status' => 400,
));
return $validation_errors;
} // end if;
$wpdb->query('START TRANSACTION');
try {
$customer = $this->maybe_create_customer($params);
if (is_wp_error($customer)) {
return $this->rollback_and_return($customer);
} // end if;
$customer->update_last_login(true, true);
$customer->add_note(array(
'text' => __('Created via REST API', 'wp-ultimo'),
'author_id' => $customer->get_user_id(),
));
/*
* Payment Method defaults
*/
$payment_method = wp_parse_args(wu_get_isset($params, 'payment_method'), array(
'gateway' => '',
'gateway_customer_id' => '',
'gateway_subscription_id' => '',
'gateway_payment_id' => '',
));
/*
* Cart params and creation
*/
$cart_params = $params;
$cart_params = wp_parse_args($cart_params, array(
'type' => 'new',
));
$cart = new Cart($cart_params);
/*
* Validates if the cart is valid.
*/
if ($cart->is_valid() && count($cart->get_line_items()) === 0) {
return new \WP_Error('invalid_cart', __('Products are required.', 'wp-ultimo'), array_merge((array) $cart->done(), array(
'status' => 400,
)));
} // end if;
/*
* Get Membership data
*/
$membership_data = $cart->to_membership_data();
$membership_data = array_merge($membership_data, wu_get_isset($params, 'membership', array(
'status' => Membership_Status::PENDING,
)));
$membership_data['customer_id'] = $customer->get_id();
$membership_data['gateway'] = wu_get_isset($payment_method, 'gateway');
$membership_data['gateway_subscription_id'] = wu_get_isset($payment_method, 'gateway_subscription_id');
$membership_data['gateway_customer_id'] = wu_get_isset($payment_method, 'gateway_customer_id');
$membership_data['auto_renew'] = wu_get_isset($params, 'auto_renew');
/*
* Unset the status because we are going to transition it later.
*/
$membership_status = $membership_data['status'];
unset($membership_data['status']);
$membership = wu_create_membership($membership_data);
if (is_wp_error($membership)) {
return $this->rollback_and_return($membership);
} // end if;
$membership->add_note(array(
'text' => __('Created via REST API', 'wp-ultimo'),
'author_id' => $customer->get_user_id(),
));
$payment_data = $cart->to_payment_data();
$payment_data = array_merge($payment_data, wu_get_isset($params, 'payment', array(
'status' => Payment_Status::PENDING,
)));
/*
* Unset the status because we are going to transition it later.
*/
$payment_status = $payment_data['status'];
unset($payment_data['status']);
$payment_data['customer_id'] = $customer->get_id();
$payment_data['membership_id'] = $membership->get_id();
$payment_data['gateway'] = wu_get_isset($payment_method, 'gateway');
$payment_data['gateway_payment_id'] = wu_get_isset($payment_method, 'gateway_payment_id');
$payment = wu_create_payment($payment_data);
if (is_wp_error($payment)) {
return $this->rollback_and_return($payment);
} // end if;
$payment->add_note(array(
'text' => __('Created via REST API', 'wp-ultimo'),
'author_id' => $customer->get_user_id(),
));
$site = false;
/*
* Site creation.
*/
if (wu_get_isset($params, 'site')) {
$site = $this->maybe_create_site($params, $membership);
if (is_wp_error($site)) {
return $this->rollback_and_return($site);
} // end if;
} // end if;
/*
* Deal with status changes.
*/
if ($membership_status !== $membership->get_status()) {
$membership->set_status($membership_status);
$membership->save();
/*
* The above change might trigger a site publication
* to take place, so we need to try to fetch the site
* again, this time as a WU Site object.
*/
if ($site) {
$wp_site = get_site_by_path($site['domain'], $site['path']);
if ($wp_site) {
$site['id'] = $wp_site->blog_id;
} // end if;
} // end if;
} // end if;
if ($payment_status !== $payment->get_status()) {
$payment->set_status($payment_status);
$payment->save();
} // end if;
} catch (\Throwable $e) {
$wpdb->query('ROLLBACK');
return new \WP_Error('registration_error', $e->getMessage(), array('status' => 500));
} // end try;
$wpdb->query('COMMIT');
/*
* We have everything we need now.
*/
return array(
'membership' => $membership->to_array(),
'customer' => $customer->to_array(),
'payment' => $payment->to_array(),
'site' => $site ? $site : array('id' => 0),
);
} // end handle_endpoint;
/**
* Returns the list of arguments allowed on to the endpoint.
*
* This is also used to build the documentation page for the endpoint.
*
* @since 2.0.0
* @return array
*/
public function get_rest_args() {
/*
* Billing Address Fields
*/
$billing_address_fields = Billing_Address::fields_for_rest(false);
$customer_args = array(
'customer_id' => array(
'description' => __('The customer ID, if the customer already exists. If you also need to create a customer/wp user, use the "customer" property.', 'wp-ultimo'),
'type' => 'integer',
),
'customer' => array(
'description' => __('Customer data. Needs to be present when customer id is not.', 'wp-ultimo'),
'type' => 'object',
'properties' => array(
'user_id' => array(
'description' => __('Existing WordPress user id to attach this customer to. If you also need to create a WordPress user, pass the properties "username", "password", and "email".', 'wp-ultimo'),
'type' => 'integer',
),
'username' => array(
'description' => __('The customer username. This is used to create the WordPress user.', 'wp-ultimo'),
'type' => 'string',
'minLength' => 4,
),
'password' => array(
'description' => __('The customer password. This is used to create the WordPress user. Note that no validation is performed here to enforce strength.', 'wp-ultimo'),
'type' => 'string',
'minLength' => 6,
),
'email' => array(
'description' => __('The customer email address. This is used to create the WordPress user.', 'wp-ultimo'),
'type' => 'string',
'format' => 'email',
),
'billing_address' => array(
'type' => 'object',
'properties' => $billing_address_fields,
)
),
),
);
$membership_args = array(
'membership' => array(
'description' => __('The membership data is automatically generated based on the cart info passed (e.g. products) but can be overridden with this property.', 'wp-ultimo'),
'type' => 'object',
'properties' => array(
'status' => array(
'description' => __('The membership status.', 'wp-ultimo'),
'type' => 'string',
'enum' => array_values(Membership_Status::get_allowed_list()),
'default' => Membership_Status::PENDING,
),
'date_expiration' => array(
'description' => __('The membership expiration date. Must be a valid PHP date format.', 'wp-ultimo'),
'type' => 'string',
'format' => 'date-time',
),
'date_trial_end' => array(
'description' => __('The membership trial end date. Must be a valid PHP date format.', 'wp-ultimo'),
'type' => 'string',
'format' => 'date-time',
),
'date_activated' => array(
'description' => __('The membership activation date. Must be a valid PHP date format.', 'wp-ultimo'),
'type' => 'string',
'format' => 'date-time',
),
'date_renewed' => array(
'description' => __('The membership last renewed date. Must be a valid PHP date format.', 'wp-ultimo'),
'type' => 'string',
'format' => 'date-time',
),
'date_cancellation' => array(
'description' => __('The membership cancellation date. Must be a valid PHP date format.', 'wp-ultimo'),
'type' => 'string',
'format' => 'date-time',
),
'date_payment_plan_completed' => array(
'description' => __('The membership completion date. Used when the membership is limited to a limited number of billing cycles. Must be a valid PHP date format.', 'wp-ultimo'),
'type' => 'string',
'format' => 'date-time',
),
),
),
);
$payment_args = array(
'payment' => array(
'description' => __('The payment data is automatically generated based on the cart info passed (e.g. products) but can be overridden with this property.', 'wp-ultimo'),
'type' => 'object',
'properties' => array(
'status' => array(
'description' => __('The payment status.', 'wp-ultimo'),
'type' => 'string',
'enum' => array_values(Payment_Status::get_allowed_list()),
'default' => Payment_Status::PENDING,
),
),
),
'payment_method' => array(
'description' => __('Payment method information. Useful when using the REST API to integrate other payment methods.', 'wp-ultimo'),
'type' => 'object',
'properties' => array(
'gateway' => array(
'description' => __('The gateway name. E.g. stripe.', 'wp-ultimo'),
'type' => 'string',
),
'gateway_customer_id' => array(
'description' => __('The customer ID on the gateway system.', 'wp-ultimo'),
'type' => 'string',
),
'gateway_subscription_id' => array(
'description' => __('The subscription ID on the gateway system.', 'wp-ultimo'),
'type' => 'string',
),
'gateway_payment_id' => array(
'description' => __('The payment ID on the gateway system.', 'wp-ultimo'),
'type' => 'string',
),
),
),
);
$site_args = array(
'site' => array(
'type' => 'object',
'properties' => array(
'site_url' => array(
'type' => 'string',
'description' => __('The site subdomain or subdirectory (depending on your Multisite install). This would be "test" in "test.your-network.com".', 'wp-ultimo'),
'minLength' => 4,
'required' => true,
),
'site_title' => array(
'type' => 'string',
'description' => __('The site title. E.g. My Amazing Site', 'wp-ultimo'),
'minLength' => 4,
'required' => true,
),
'publish' => array(
'description' => __('If we should publish this site regardless of membership/payment status. Sites are created as pending by default, and are only published when a payment is received or the status of the membership changes to "active". This flag allows you to bypass the pending state.', 'wp-ultimo'),
'type' => 'boolean',
'default' => false,
),
'template_id' => array(
'description' => __('The template ID we should copy when creating this site. If left empty, the value dictated by the products will be used.', 'wp-ultimo'),
'type' => 'integer',
),
'site_meta' => array(
'description' => __('An associative array of key values to be saved as site_meta.', 'wp-ultimo'),
'type' => 'object',
),
'site_option' => array(
'description' => __('An associative array of key values to be saved as site_options. Useful for changing plugin settings and other site configurations.', 'wp-ultimo'),
'type' => 'object',
),
),
),
);
$cart_args = array(
'products' => array(
'description' => __('The products to be added to this membership. Takes an array of product ids or slugs.', 'wp-ultimo'),
'uniqueItems' => true,
'type' => 'array',
),
'duration' => array(
'description' => __('The membership duration.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'duration_unit' => array(
'description' => __('The membership duration unit.', 'wp-ultimo'),
'type' => 'string',
'default' => 'month',
'enum' => array(
'day',
'week',
'month',
'year',
),
),
'discount_code' => array(
'description' => __('A discount code. E.g. PROMO10.', 'wp-ultimo'),
'type' => 'string',
),
'auto_renew' => array(
'description' => __('The membership auto-renew status. Useful when integrating with other payment options via this REST API.', 'wp-ultimo'),
'type' => 'boolean',
'default' => false,
'required' => true,
),
'country' => array(
'description' => __('The customer country. Used to calculate taxes and check if registration is allowed for that country.', 'wp-ultimo'),
'type' => 'string',
'default' => '',
),
'currency' => array(
'description' => __('The currency to be used.', 'wp-ultimo'),
'type' => 'string',
),
);
$args = array_merge($customer_args, $membership_args, $cart_args, $payment_args, $site_args);
return apply_filters('wu_rest_register_endpoint_args', $args, $this);
} // end get_rest_args;
/**
* Maybe create a customer, if needed.
*
* @since 2.0.0
*
* @param array $p The request parameters.
* @return \WP_Ultimo\Models\Customer|\WP_Error
*/
public function maybe_create_customer($p) {
$customer_id = wu_get_isset($p, 'customer_id');
if ($customer_id) {
$customer = wu_get_customer($customer_id);
if (!$customer) {
return new \WP_Error('customer_not_found', __('The customer id sent does not correspond to a valid customer.', 'wp-ultimo'));
} // end if;
} else {
$customer = wu_create_customer($p['customer']);
} // end if;
return $customer;
} // end maybe_create_customer;
/**
* Undocumented function
*
* @since 2.0.0
*
* @param array $p The request parameters.
* @param \WP_Ultimo\Models\Membership $membership The membership created.
* @return array|\WP_Ultimo\Models\Site\|\WP_Error
*/
public function maybe_create_site($p, $membership) {
$site_data = $p['site'];
/*
* Let's get a list of membership sites.
* This list includes pending sites as well.
*/
$sites = $membership->get_sites();
/*
* Decide if we should create a new site or not.
*
* When should we create a new pending site?
* There are a couple of rules:
* - The membership must not have a pending site;
* - The membership must not have an existing site;
*
* The get_sites method already includes pending sites,
* so we can safely rely on it.
*/
if (!empty($sites)) {
/*
* Returns the first site on that list.
* This is not ideal, but since we'll usually only have
* one site here, it's ok. for now.
*/
return current($sites);
} // end if;
$site_url = wu_get_isset($site_data, 'site_url');
$d = wu_get_site_domain_and_path($site_url);
/*
* Validates the site url.
*/
$results = wpmu_validate_blog_signup($site_url, wu_get_isset($site_data, 'site_title'), $membership->get_customer()->get_user());
if ($results['errors']->has_errors()) {
return $results['errors'];
} // end if;
/*
* Get the transient data to save with the site
* that way we can use it when actually registering
* the site on WordPress.
*/
$transient = array_merge(
wu_get_isset($site_data, 'site_meta', array()),
wu_get_isset($site_data, 'site_option', array())
);
$template_id = apply_filters('wu_checkout_template_id', (int) wu_get_isset($site_data, 'template_id'), $membership, $this);
$site_data = array(
'domain' => $d->domain,
'path' => $d->path,
'title' => wu_get_isset($site_data, 'site_title'),
'template_id' => $template_id,
'customer_id' => $membership->get_customer()->get_id(),
'membership_id' => $membership->get_id(),
'transient' => $transient,
'signup_meta' => wu_get_isset($site_data, 'site_meta', array()),
'signup_options' => wu_get_isset($site_data, 'site_option', array()),
'type' => Site_Type::CUSTOMER_OWNED,
);
$membership->create_pending_site($site_data);
$site_data['id'] = 0;
if (wu_get_isset($site_data, 'publish')) {
$membership->publish_pending_site();
$wp_site = get_site_by_path($site_data['domain'], $site_data['path']);
if ($wp_site) {
$site_data['id'] = $wp_site->blog_id;
} // end if;
} // end if;
return $site_data;
} // end maybe_create_site;
/**
* Set the validation rules for this particular model.
*
* To see how to setup rules, check the documentation of the
* validation library we are using: https://github.com/rakit/validation
*
* @since 2.0.0
* @link https://github.com/rakit/validation
* @return array
*/
public function validation_rules() {
return array(
'customer_id' => 'required_without:customer',
'customer' => 'required_without:customer_id',
'customer.username' => 'required_without_all:customer_id,customer.user_id',
'customer.password' => 'required_without_all:customer_id,customer.user_id',
'customer.email' => 'required_without_all:customer_id,customer.user_id',
'customer.user_id' => 'required_without_all:customer_id,customer.username,customer.password,customer.email',
'site.site_url' => 'required_with:site|alpha_num|min:4|lowercase|unique_site',
'site.site_title' => 'required_with:site|min:4',
);
} // end validation_rules;
/**
* Validates the rules and make sure we only save models when necessary.
*
* @since 2.0.0
* @param array $args The params to validate.
* @return mixed[]|\WP_Error
*/
public function validate($args) {
$validator = new \WP_Ultimo\Helpers\Validator;
$validator->validate($args, $this->validation_rules());
if ($validator->fails()) {
return $validator->get_errors();
} // end if;
return true;
} // end validate;
/**
* Rolls back database changes and returns the error passed.
*
* @since 2.0.0
*
* @param \WP_Error $error The error to return.
* @return \WP_Error
*/
protected function rollback_and_return($error) {
global $wpdb;
$wpdb->query('ROLLBACK');
return $error;
} // end rollback_and_return;
} // end class Register_Endpoint;

View File

@ -0,0 +1,93 @@
<?php
/**
* Schema for broadcast@create.
*
* @package WP_Ultimo\API\Schemas
* @since 2.0.11
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Schema for broadcast@create.
*
* @since 2.0.11
* @internal last-generated in 2022-12
* @generated class generated by our build scripts, do not change!
*
* @since 2.0.11
*/
return array(
'migrated_from_id' => array(
'description' => __('The ID of the original 1.X model that was used to generate this item on migration.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'notice_type' => array(
'description' => __('Can be info, success, warning or error.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
'enum' => array(
'info',
'success',
'warning',
'error',
),
),
'name' => array(
'description' => __('This broadcast name, which is used as broadcast title as well.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'type' => array(
'description' => __('The type being set.', 'wp-ultimo'),
'type' => 'string',
'required' => true,
),
'status' => array(
'description' => __('The status being set.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'author_id' => array(
'description' => __('The author ID.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'title' => array(
'description' => __('Post title.', 'wp-ultimo'),
'type' => 'string',
'required' => true,
),
'content' => array(
'description' => __('Post content.', 'wp-ultimo'),
'type' => 'string',
'required' => true,
),
'excerpt' => array(
'description' => __('Post excerpt.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'date_created' => array(
'description' => __('Post creation date.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'date_modified' => array(
'description' => __('Post last modification date.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'slug' => array(
'description' => __('The slug.', 'wp-ultimo'),
'type' => 'mixed',
'required' => false,
),
'skip_validation' => array(
'description' => __('Set true to have field information validation bypassed when saving this event.', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
);

View File

@ -0,0 +1,93 @@
<?php
/**
* Schema for broadcast@update.
*
* @package WP_Ultimo\API\Schemas
* @since 2.0.11
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Schema for broadcast@update.
*
* @since 2.0.11
* @internal last-generated in 2022-12
* @generated class generated by our build scripts, do not change!
*
* @since 2.0.11
*/
return array(
'migrated_from_id' => array(
'description' => __('The ID of the original 1.X model that was used to generate this item on migration.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'notice_type' => array(
'description' => __('Can be info, success, warning or error.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
'enum' => array(
'info',
'success',
'warning',
'error',
),
),
'name' => array(
'description' => __('This broadcast name, which is used as broadcast title as well.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'type' => array(
'description' => __('The type being set.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'status' => array(
'description' => __('The status being set.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'author_id' => array(
'description' => __('The author ID.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'title' => array(
'description' => __('Post title.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'content' => array(
'description' => __('Post content.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'excerpt' => array(
'description' => __('Post excerpt.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'date_created' => array(
'description' => __('Post creation date.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'date_modified' => array(
'description' => __('Post last modification date.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'slug' => array(
'description' => __('The slug.', 'wp-ultimo'),
'type' => 'mixed',
'required' => false,
),
'skip_validation' => array(
'description' => __('Set true to have field information validation bypassed when saving this event.', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
);

View File

@ -0,0 +1,92 @@
<?php
/**
* Schema for checkout@form-create.
*
* @package WP_Ultimo\API\Schemas
* @since 2.0.11
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Schema for checkout@form-create.
*
* @since 2.0.11
* @internal last-generated in 2022-12
* @generated class generated by our build scripts, do not change!
*
* @since 2.0.11
*/
return array(
'slug' => array(
'description' => __('The checkout form slug. It needs to be unique and preferably make it clear what it is about. E.g. my_checkout_form.', 'wp-ultimo'),
'type' => 'string',
'required' => true,
),
'name' => array(
'description' => __('Your checkout form name, which is used as checkout form title as well.', 'wp-ultimo'),
'type' => 'string',
'required' => true,
),
'active' => array(
'description' => __('Set this checkout form as active (true), which means available to be used, or inactive (false).', 'wp-ultimo'),
'type' => 'boolean',
'required' => true,
),
'custom_css' => array(
'description' => __('Custom CSS code for the checkout form.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'settings' => array(
'description' => __('The checkout form settings and configurations.', 'wp-ultimo'),
'type' => 'object',
'required' => false,
),
'allowed_countries' => array(
'description' => __('The allowed countries that can access this checkout.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'thank_you_page_id' => array(
'description' => __('The thank you page ID. This page is shown after a successful purchase.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'conversion_snippets' => array(
'description' => __('Snippets to run on thank you page.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'template' => array(
'description' => __("Template mode. Can be either 'blank', 'single-step' or 'multi-step'.", 'wp-ultimo'),
'type' => 'string',
'required' => false,
'enum' => array(
'blank',
'single-step',
'multi-step',
),
),
'date_created' => array(
'description' => __('Model creation date.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'date_modified' => array(
'description' => __('Model last modification date.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'migrated_from_id' => array(
'description' => __('The ID of the original 1.X model that was used to generate this item on migration.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'skip_validation' => array(
'description' => __('Set true to have field information validation bypassed when saving this event.', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
);

View File

@ -0,0 +1,92 @@
<?php
/**
* Schema for checkout@form-update.
*
* @package WP_Ultimo\API\Schemas
* @since 2.0.11
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Schema for checkout@form-update.
*
* @since 2.0.11
* @internal last-generated in 2022-12
* @generated class generated by our build scripts, do not change!
*
* @since 2.0.11
*/
return array(
'slug' => array(
'description' => __('The checkout form slug. It needs to be unique and preferably make it clear what it is about. E.g. my_checkout_form.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'name' => array(
'description' => __('Your checkout form name, which is used as checkout form title as well.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'active' => array(
'description' => __('Set this checkout form as active (true), which means available to be used, or inactive (false).', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
'custom_css' => array(
'description' => __('Custom CSS code for the checkout form.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'settings' => array(
'description' => __('The checkout form settings and configurations.', 'wp-ultimo'),
'type' => 'array',
'required' => false,
),
'allowed_countries' => array(
'description' => __('The allowed countries that can access this checkout.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'thank_you_page_id' => array(
'description' => __('The thank you page ID. This page is shown after a successful purchase.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'conversion_snippets' => array(
'description' => __('Snippets to run on thank you page.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'template' => array(
'description' => __("Template mode. Can be either 'blank', 'single-step' or 'multi-step'.", 'wp-ultimo'),
'type' => 'string',
'required' => false,
'enum' => array(
'blank',
'single-step',
'multi-step',
),
),
'date_created' => array(
'description' => __('Model creation date.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'date_modified' => array(
'description' => __('Model last modification date.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'migrated_from_id' => array(
'description' => __('The ID of the original 1.X model that was used to generate this item on migration.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'skip_validation' => array(
'description' => __('Set true to have field information validation bypassed when saving this event.', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
);

View File

@ -0,0 +1,100 @@
<?php
/**
* Schema for customer@create.
*
* @package WP_Ultimo\API\Schemas
* @since 2.0.11
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Schema for customer@create.
*
* @since 2.0.11
* @internal last-generated in 2022-12
* @generated class generated by our build scripts, do not change!
*
* @since 2.0.11
*/
return array(
'user_id' => array(
'description' => __('The WordPress user ID attached to this customer.', 'wp-ultimo'),
'type' => 'integer',
'required' => true,
),
'date_registered' => array(
'description' => __('Date when the customer was created.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'email_verification' => array(
'description' => __('Email verification status - either `none`, `pending`, or `verified`.', 'wp-ultimo'),
'type' => 'string',
'required' => true,
'enum' => array(
'verified',
'pending',
'none',
),
),
'last_login' => array(
'description' => __('Date this customer last logged in.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'has_trialed' => array(
'description' => __('Whether or not the customer has trialed before.', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
'vip' => array(
'description' => __('If this customer is a VIP customer or not.', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
'ips' => array(
'description' => __('List of IP addresses used by this customer.', 'wp-ultimo'),
'type' => 'array',
'required' => false,
),
'extra_information' => array(
'description' => __('Any extra information related to this customer.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'type' => array(
'description' => __("The customer type. Can be 'customer'.", 'wp-ultimo'),
'type' => 'string',
'required' => true,
'enum' => array(
'customer',
),
),
'signup_form' => array(
'description' => __('The form used to signup.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'date_created' => array(
'description' => __('Model creation date.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'date_modified' => array(
'description' => __('Model last modification date.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'migrated_from_id' => array(
'description' => __('The ID of the original 1.X model that was used to generate this item on migration.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'skip_validation' => array(
'description' => __('Set true to have field information validation bypassed when saving this event.', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
);

View File

@ -0,0 +1,100 @@
<?php
/**
* Schema for customer@update.
*
* @package WP_Ultimo\API\Schemas
* @since 2.0.11
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Schema for customer@update.
*
* @since 2.0.11
* @internal last-generated in 2022-12
* @generated class generated by our build scripts, do not change!
*
* @since 2.0.11
*/
return array(
'user_id' => array(
'description' => __('The WordPress user ID attached to this customer.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'date_registered' => array(
'description' => __('Date when the customer was created.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'email_verification' => array(
'description' => __('Email verification status - either `none`, `pending`, or `verified`.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
'enum' => array(
'verified',
'pending',
'none',
),
),
'last_login' => array(
'description' => __('Date this customer last logged in.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'has_trialed' => array(
'description' => __('Whether or not the customer has trialed before.', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
'vip' => array(
'description' => __('If this customer is a VIP customer or not.', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
'ips' => array(
'description' => __('List of IP addresses used by this customer.', 'wp-ultimo'),
'type' => 'array',
'required' => false,
),
'extra_information' => array(
'description' => __('Any extra information related to this customer.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'type' => array(
'description' => __("The customer type. Can be 'customer'.", 'wp-ultimo'),
'type' => 'string',
'required' => false,
'enum' => array(
'customer',
),
),
'signup_form' => array(
'description' => __('The form used to signup.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'date_created' => array(
'description' => __('Model creation date.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'date_modified' => array(
'description' => __('Model last modification date.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'migrated_from_id' => array(
'description' => __('The ID of the original 1.X model that was used to generate this item on migration.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'skip_validation' => array(
'description' => __('Set true to have field information validation bypassed when saving this event.', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
);

View File

@ -0,0 +1,125 @@
<?php
/**
* Schema for discount@code-create.
*
* @package WP_Ultimo\API\Schemas
* @since 2.0.11
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Schema for discount@code-create.
*
* @since 2.0.11
* @internal last-generated in 2022-12
* @generated class generated by our build scripts, do not change!
*
* @since 2.0.11
*/
return array(
'name' => array(
'description' => __('Your discount code name, which is used as discount code title as well.', 'wp-ultimo'),
'type' => 'string',
'required' => true,
),
'code' => array(
'description' => __('A unique identification to redeem the discount code. E.g. PROMO10.', 'wp-ultimo'),
'type' => 'string',
'required' => true,
),
'description' => array(
'description' => __('A description for the discount code, usually a short text.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'uses' => array(
'description' => __('Number of times this discount was applied.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'max_uses' => array(
'description' => __('The number of times this discount can be used before becoming inactive.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'apply_to_renewals' => array(
'description' => __('Wether or not we should apply the discount to membership renewals.', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
'type' => array(
'description' => __("The type of the discount code. Can be 'percentage' (e.g. 10%% OFF), 'absolute' (e.g. $10 OFF).", 'wp-ultimo'),
'type' => 'string',
'required' => false,
'enum' => array(
'percentage',
'absolute',
),
),
'value' => array(
'description' => __('Amount discounted in cents.', 'wp-ultimo'),
'type' => 'integer',
'required' => true,
),
'setup_fee_type' => array(
'description' => __('Type of the discount for the setup fee value. Can be a percentage or absolute.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
'enum' => array(
'percentage',
'absolute',
),
),
'setup_fee_value' => array(
'description' => __('Amount discounted for setup fees in cents.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'active' => array(
'description' => __('Set this discount code as active (true), which means available to be used, or inactive (false).', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
'date_start' => array(
'description' => __('Start date for the coupon code to be considered valid.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'date_expiration' => array(
'description' => __('Expiration date for the coupon code.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'date_created' => array(
'description' => __('Date when this discount code was created.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'allowed_products' => array(
'description' => __('The list of products that allows this discount code to be used. If empty, all products will accept this code.', 'wp-ultimo'),
'type' => 'array',
'required' => false,
),
'limit_products' => array(
'description' => __('This discount code will be limited to be used in certain products? If set to true, you must define a list of allowed products.', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
'date_modified' => array(
'description' => __('Model last modification date.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'migrated_from_id' => array(
'description' => __('The ID of the original 1.X model that was used to generate this item on migration.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'skip_validation' => array(
'description' => __('Set true to have field information validation bypassed when saving this event.', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
);

View File

@ -0,0 +1,125 @@
<?php
/**
* Schema for discount@code-update.
*
* @package WP_Ultimo\API\Schemas
* @since 2.0.11
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Schema for discount@code-update.
*
* @since 2.0.11
* @internal last-generated in 2022-12
* @generated class generated by our build scripts, do not change!
*
* @since 2.0.11
*/
return array(
'name' => array(
'description' => __('Your discount code name, which is used as discount code title as well.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'code' => array(
'description' => __('A unique identification to redeem the discount code. E.g. PROMO10.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'description' => array(
'description' => __('A description for the discount code, usually a short text.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'uses' => array(
'description' => __('Number of times this discount was applied.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'max_uses' => array(
'description' => __('The number of times this discount can be used before becoming inactive.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'apply_to_renewals' => array(
'description' => __('Wether or not we should apply the discount to membership renewals.', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
'type' => array(
'description' => __("The type of the discount code. Can be 'percentage' (e.g. 10%% OFF), 'absolute' (e.g. $10 OFF).", 'wp-ultimo'),
'type' => 'string',
'required' => false,
'enum' => array(
'percentage',
'absolute',
),
),
'value' => array(
'description' => __('Amount discounted in cents.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'setup_fee_type' => array(
'description' => __('Type of the discount for the setup fee value. Can be a percentage or absolute.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
'enum' => array(
'percentage',
'absolute',
),
),
'setup_fee_value' => array(
'description' => __('Amount discounted for setup fees in cents.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'active' => array(
'description' => __('Set this discount code as active (true), which means available to be used, or inactive (false).', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
'date_start' => array(
'description' => __('Start date for the coupon code to be considered valid.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'date_expiration' => array(
'description' => __('Expiration date for the coupon code.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'date_created' => array(
'description' => __('Date when this discount code was created.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'allowed_products' => array(
'description' => __('The list of products that allows this discount code to be used. If empty, all products will accept this code.', 'wp-ultimo'),
'type' => 'array',
'required' => false,
),
'limit_products' => array(
'description' => __('This discount code will be limited to be used in certain products? If set to true, you must define a list of allowed products.', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
'date_modified' => array(
'description' => __('Model last modification date.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'migrated_from_id' => array(
'description' => __('The ID of the original 1.X model that was used to generate this item on migration.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'skip_validation' => array(
'description' => __('Set true to have field information validation bypassed when saving this event.', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
);

View File

@ -0,0 +1,79 @@
<?php
/**
* Schema for domain@create.
*
* @package WP_Ultimo\API\Schemas
* @since 2.0.11
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Schema for domain@create.
*
* @since 2.0.11
* @internal last-generated in 2022-12
* @generated class generated by our build scripts, do not change!
*
* @since 2.0.11
*/
return array(
'domain' => array(
'description' => __("Your Domain name. You don't need to put http or https in front of your domain in this field. e.g: example.com.", 'wp-ultimo'),
'type' => 'string',
'required' => true,
),
'blog_id' => array(
'description' => __('The blog ID attached to this domain.', 'wp-ultimo'),
'type' => 'integer',
'required' => true,
),
'active' => array(
'description' => __('Set this domain as active (true), which means available to be used, or inactive (false).', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
'primary_domain' => array(
'description' => __("Define true to set this as primary domain of a site, meaning it's the main url, or set false.", 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
'secure' => array(
'description' => __('If this domain has some SSL security or not.', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
'stage' => array(
'description' => __('The state of the domain model object. Can be one of this options: checking-dns, checking-ssl-cert, done-without-ssl, done and failed.', 'wp-ultimo'),
'type' => 'string',
'required' => true,
'enum' => array(
'checking-dns',
'checking-ssl-cert',
'done-without-ssl',
'done',
'failed',
),
),
'date_created' => array(
'description' => __('Date when the domain was created. If no date is set, the current date and time will be used.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'date_modified' => array(
'description' => __('Model last modification date.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'migrated_from_id' => array(
'description' => __('The ID of the original 1.X model that was used to generate this item on migration.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'skip_validation' => array(
'description' => __('Set true to have field information validation bypassed when saving this event.', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
);

View File

@ -0,0 +1,79 @@
<?php
/**
* Schema for domain@update.
*
* @package WP_Ultimo\API\Schemas
* @since 2.0.11
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Schema for domain@update.
*
* @since 2.0.11
* @internal last-generated in 2022-12
* @generated class generated by our build scripts, do not change!
*
* @since 2.0.11
*/
return array(
'domain' => array(
'description' => __("Your Domain name. You don't need to put http or https in front of your domain in this field. e.g: example.com.", 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'blog_id' => array(
'description' => __('The blog ID attached to this domain.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'active' => array(
'description' => __('Set this domain as active (true), which means available to be used, or inactive (false).', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
'primary_domain' => array(
'description' => __("Define true to set this as primary domain of a site, meaning it's the main url, or set false.", 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
'secure' => array(
'description' => __('If this domain has some SSL security or not.', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
'stage' => array(
'description' => __('The state of the domain model object. Can be one of this options: checking-dns, checking-ssl-cert, done-without-ssl, done and failed.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
'enum' => array(
'checking-dns',
'checking-ssl-cert',
'done-without-ssl',
'done',
'failed',
),
),
'date_created' => array(
'description' => __('Date when the domain was created. If no date is set, the current date and time will be used.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'date_modified' => array(
'description' => __('Model last modification date.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'migrated_from_id' => array(
'description' => __('The ID of the original 1.X model that was used to generate this item on migration.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'skip_validation' => array(
'description' => __('Set true to have field information validation bypassed when saving this event.', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
);

View File

@ -0,0 +1,144 @@
<?php
/**
* Schema for email@create.
*
* @package WP_Ultimo\API\Schemas
* @since 2.0.11
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Schema for email@create.
*
* @since 2.0.11
* @internal last-generated in 2022-12
* @generated class generated by our build scripts, do not change!
*
* @since 2.0.11
*/
return array(
'style' => array(
'description' => __("The email style. Can be 'html' or 'plain-text'.", 'wp-ultimo'),
'type' => 'string',
'required' => false,
'enum' => array(
'html',
'plain-text',
),
),
'schedule' => array(
'description' => __('Whether or not this is a scheduled email.', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
'type' => array(
'description' => __('The type being set.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'event' => array(
'description' => __('The event that needs to be fired for this email to be sent.', 'wp-ultimo'),
'type' => 'string',
'required' => true,
),
'send_hours' => array(
'description' => __('The amount of hours that the email will wait before is sent.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'send_days' => array(
'description' => __('The amount of days that the email will wait before is sent.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'schedule_type' => array(
'description' => __("The type of schedule. Can be 'days' or 'hours'.", 'wp-ultimo'),
'type' => 'string',
'required' => false,
'enum' => array(
'days',
'hours',
),
),
'name' => array(
'description' => __('The name being set as title.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'custom_sender' => array(
'description' => __('If has a custom sender.', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
'custom_sender_name' => array(
'description' => __('The name of the custom sender. E.g. From: John Doe.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'custom_sender_email' => array(
'description' => __('The email of the custom sender. E.g. From: johndoe@gmail.com.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'target' => array(
'description' => __("If we should send this to a customer or to the network admin. Can be 'customer' or 'admin'.", 'wp-ultimo'),
'type' => 'string',
'required' => true,
'enum' => array(
'customer',
'admin',
),
),
'send_copy_to_admin' => array(
'description' => __('Checks if we should send a copy of the email to the admin.', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
'active' => array(
'description' => __('Set this email as active (true), which means available will fire when the event occur, or inactive (false).', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
'legacy' => array(
'description' => __('Whether or not this is a legacy email.', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
'title' => array(
'description' => __('Post title.', 'wp-ultimo'),
'type' => 'string',
'required' => true,
),
'content' => array(
'description' => __('Post content.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'excerpt' => array(
'description' => __('Post excerpt.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'date_created' => array(
'description' => __('Post creation date.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'date_modified' => array(
'description' => __('Post last modification date.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'migrated_from_id' => array(
'description' => __('The ID of the original 1.X model that was used to generate this item on migration.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'skip_validation' => array(
'description' => __('Set true to have field information validation bypassed when saving this event.', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
);

View File

@ -0,0 +1,144 @@
<?php
/**
* Schema for email@update.
*
* @package WP_Ultimo\API\Schemas
* @since 2.0.11
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Schema for email@update.
*
* @since 2.0.11
* @internal last-generated in 2022-12
* @generated class generated by our build scripts, do not change!
*
* @since 2.0.11
*/
return array(
'style' => array(
'description' => __("The email style. Can be 'html' or 'plain-text'.", 'wp-ultimo'),
'type' => 'string',
'required' => false,
'enum' => array(
'html',
'plain-text',
),
),
'schedule' => array(
'description' => __('Whether or not this is a scheduled email.', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
'type' => array(
'description' => __('The type being set.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'event' => array(
'description' => __('The event that needs to be fired for this email to be sent.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'send_hours' => array(
'description' => __('The amount of hours that the email will wait before is sent.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'send_days' => array(
'description' => __('The amount of days that the email will wait before is sent.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'schedule_type' => array(
'description' => __("The type of schedule. Can be 'days' or 'hours'.", 'wp-ultimo'),
'type' => 'string',
'required' => false,
'enum' => array(
'days',
'hours',
),
),
'name' => array(
'description' => __('The name being set as title.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'custom_sender' => array(
'description' => __('If has a custom sender.', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
'custom_sender_name' => array(
'description' => __('The name of the custom sender. E.g. From: John Doe.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'custom_sender_email' => array(
'description' => __('The email of the custom sender. E.g. From: johndoe@gmail.com.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'target' => array(
'description' => __("If we should send this to a customer or to the network admin. Can be 'customer' or 'admin'.", 'wp-ultimo'),
'type' => 'string',
'required' => false,
'enum' => array(
'customer',
'admin',
),
),
'send_copy_to_admin' => array(
'description' => __('Checks if we should send a copy of the email to the admin.', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
'active' => array(
'description' => __('Set this email as active (true), which means available will fire when the event occur, or inactive (false).', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
'legacy' => array(
'description' => __('Whether or not this is a legacy email.', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
'title' => array(
'description' => __('Post title.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'content' => array(
'description' => __('Post content.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'excerpt' => array(
'description' => __('Post excerpt.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'date_created' => array(
'description' => __('Post creation date.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'date_modified' => array(
'description' => __('Post last modification date.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'migrated_from_id' => array(
'description' => __('The ID of the original 1.X model that was used to generate this item on migration.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'skip_validation' => array(
'description' => __('Set true to have field information validation bypassed when saving this event.', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
);

View File

@ -0,0 +1,76 @@
<?php
/**
* Schema for event@create.
*
* @package WP_Ultimo\API\Schemas
* @since 2.0.11
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Schema for event@create.
*
* @since 2.0.11
* @internal last-generated in 2022-12
* @generated class generated by our build scripts, do not change!
*
* @since 2.0.11
*/
return array(
'severity' => array(
'description' => __('Severity of the problem.', 'wp-ultimo'),
'type' => 'integer',
'required' => true,
),
'date_created' => array(
'description' => __('Date when the event was created.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'payload' => array(
'description' => __('Payload of the event.', 'wp-ultimo'),
'type' => 'object',
'required' => true,
),
'initiator' => array(
'description' => __('The type of user responsible for initiating the event. There are two options: Manual and System. By default, the event is saved as manual.', 'wp-ultimo'),
'type' => 'string',
'required' => true,
'enum' => array(
'system',
'manual',
),
),
'object_type' => array(
'description' => __("The type of object related to this event. It's usually the model name.", 'wp-ultimo'),
'type' => 'string',
'required' => true,
),
'slug' => array(
'description' => __('The event slug. It needs to be unique and preferably make it clear what it is about. Example: account_created is about creating an account.', 'wp-ultimo'),
'type' => 'string',
'required' => true,
),
'object_id' => array(
'description' => __('The ID of the related objects.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'date_modified' => array(
'description' => __('Model last modification date.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'migrated_from_id' => array(
'description' => __('The ID of the original 1.X model that was used to generate this item on migration.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'skip_validation' => array(
'description' => __('Set true to have field information validation bypassed when saving this event.', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
);

View File

@ -0,0 +1,76 @@
<?php
/**
* Schema for event@update.
*
* @package WP_Ultimo\API\Schemas
* @since 2.0.11
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Schema for event@update.
*
* @since 2.0.11
* @internal last-generated in 2022-12
* @generated class generated by our build scripts, do not change!
*
* @since 2.0.11
*/
return array(
'severity' => array(
'description' => __('Severity of the problem.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'date_created' => array(
'description' => __('Date when the event was created.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'payload' => array(
'description' => __('Payload of the event.', 'wp-ultimo'),
'type' => 'object',
'required' => false,
),
'initiator' => array(
'description' => __('The type of user responsible for initiating the event. There are two options: Manual and System. By default, the event is saved as manual.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
'enum' => array(
'system',
'manual',
),
),
'object_type' => array(
'description' => __("The type of object related to this event. It's usually the model name.", 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'slug' => array(
'description' => __('The event slug. It needs to be unique and preferably make it clear what it is about. Example: account_created is about creating an account.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'object_id' => array(
'description' => __('The ID of the related objects.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'date_modified' => array(
'description' => __('Model last modification date.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'migrated_from_id' => array(
'description' => __('The ID of the original 1.X model that was used to generate this item on migration.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'skip_validation' => array(
'description' => __('Set true to have field information validation bypassed when saving this event.', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
);

View File

@ -0,0 +1,181 @@
<?php
/**
* Schema for membership@create.
*
* @package WP_Ultimo\API\Schemas
* @since 2.0.11
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
use WP_Ultimo\Database\Memberships\Membership_Status;
/**
* Schema for membership@create.
*
* @since 2.0.11
* @internal last-generated in 2022-12
* @generated class generated by our build scripts, do not change!
*
* @since 2.0.11
*/
return array(
'customer_id' => array(
'description' => __('The ID of the customer attached to this membership.', 'wp-ultimo'),
'type' => 'integer',
'required' => true,
),
'user_id' => array(
'description' => __('The user ID attached to this membership.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'plan_id' => array(
'description' => __('The plan ID associated with the membership.', 'wp-ultimo'),
'type' => 'integer',
'required' => true,
),
'addon_products' => array(
'description' => __('Additional products related to this membership. Services, Packages or other types of products.', 'wp-ultimo'),
'type' => 'mixed',
'required' => false,
),
'currency' => array(
'description' => __("The currency that this membership. It's a 3-letter code. E.g. 'USD'.", 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'duration' => array(
'description' => __('The interval period between a charge. Only the interval amount, the unit will be defined in another property.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'duration_unit' => array(
'description' => __("The duration amount type. Can be 'day', 'week', 'month' or 'year'.", 'wp-ultimo'),
'type' => 'string',
'required' => false,
'enum' => array(
'day',
'month',
'week',
'year',
),
),
'amount' => array(
'description' => __('The product amount.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'initial_amount' => array(
'description' => __('The initial amount charged for this membership, including the setup fee.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'date_created' => array(
'description' => __('Date of creation of this membership.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'date_activated' => array(
'description' => __('Date when this membership was activated.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'date_trial_end' => array(
'description' => __('Date when the trial period ends, if this membership has or had a trial period.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'date_renewed' => array(
'description' => __('Date when the membership was cancelled.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'date_cancellation' => array(
'description' => __('Date when the membership was cancelled.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'date_expiration' => array(
'description' => __('Date when the membership will expiry.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'date_payment_plan_completed' => array(
'description' => __('Change of the payment completion for the plan value.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'auto_renew' => array(
'description' => __('If this membership should auto-renewal.', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
'times_billed' => array(
'description' => __('Amount of times this membership got billed.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'billing_cycles' => array(
'description' => __('Maximum times we should charge this membership.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'status' => array(
'description' => __("The membership status. Can be 'pending', 'active', 'on-hold', 'expired', 'cancelled' or other values added by third-party add-ons.", 'wp-ultimo'),
'type' => 'string',
'required' => false,
'enum' => Membership_Status::get_allowed_list(),
),
'gateway_customer_id' => array(
'description' => __('The ID of the customer on the payment gateway database.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'gateway_subscription_id' => array(
'description' => __('The ID of the subscription on the payment gateway database.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'gateway' => array(
'description' => __('ID of the gateway being used on this subscription.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'signup_method' => array(
'description' => __('Signup method used to create this membership.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'upgraded_from' => array(
'description' => __('Plan that this membership upgraded from.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'date_modified' => array(
'description' => __('Date this membership was last modified.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'disabled' => array(
'description' => __('If this membership is a disabled one.', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
'recurring' => array(
'description' => __('If this membership is recurring (true), which means the customer paid a defined amount each period of time, or not recurring (false).', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
'migrated_from_id' => array(
'description' => __('The ID of the original 1.X model that was used to generate this item on migration.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'skip_validation' => array(
'description' => __('Set true to have field information validation bypassed when saving this event.', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
);

View File

@ -0,0 +1,181 @@
<?php
/**
* Schema for membership@update.
*
* @package WP_Ultimo\API\Schemas
* @since 2.0.11
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
use WP_Ultimo\Database\Memberships\Membership_Status;
/**
* Schema for membership@update.
*
* @since 2.0.11
* @internal last-generated in 2022-12
* @generated class generated by our build scripts, do not change!
*
* @since 2.0.11
*/
return array(
'customer_id' => array(
'description' => __('The ID of the customer attached to this membership.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'user_id' => array(
'description' => __('The user ID attached to this membership.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'plan_id' => array(
'description' => __('The plan ID associated with the membership.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'addon_products' => array(
'description' => __('Additional products related to this membership. Services, Packages or other types of products.', 'wp-ultimo'),
'type' => 'mixed',
'required' => false,
),
'currency' => array(
'description' => __("The currency that this membership. It's a 3-letter code. E.g. 'USD'.", 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'duration' => array(
'description' => __('The interval period between a charge. Only the interval amount, the unit will be defined in another property.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'duration_unit' => array(
'description' => __("The duration amount type. Can be 'day', 'week', 'month' or 'year'.", 'wp-ultimo'),
'type' => 'string',
'required' => false,
'enum' => array(
'day',
'month',
'week',
'year',
),
),
'amount' => array(
'description' => __('The product amount.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'initial_amount' => array(
'description' => __('The initial amount charged for this membership, including the setup fee.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'date_created' => array(
'description' => __('Date of creation of this membership.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'date_activated' => array(
'description' => __('Date when this membership was activated.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'date_trial_end' => array(
'description' => __('Date when the trial period ends, if this membership has or had a trial period.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'date_renewed' => array(
'description' => __('Date when the membership was cancelled.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'date_cancellation' => array(
'description' => __('Date when the membership was cancelled.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'date_expiration' => array(
'description' => __('Date when the membership will expiry.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'date_payment_plan_completed' => array(
'description' => __('Change of the payment completion for the plan value.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'auto_renew' => array(
'description' => __('If this membership should auto-renewal.', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
'times_billed' => array(
'description' => __('Amount of times this membership got billed.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'billing_cycles' => array(
'description' => __('Maximum times we should charge this membership.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'status' => array(
'description' => __("The membership status. Can be 'pending', 'active', 'on-hold', 'expired', 'cancelled' or other values added by third-party add-ons.", 'wp-ultimo'),
'type' => 'string',
'required' => false,
'enum' => Membership_Status::get_allowed_list(),
),
'gateway_customer_id' => array(
'description' => __('The ID of the customer on the payment gateway database.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'gateway_subscription_id' => array(
'description' => __('The ID of the subscription on the payment gateway database.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'gateway' => array(
'description' => __('ID of the gateway being used on this subscription.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'signup_method' => array(
'description' => __('Signup method used to create this membership.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'upgraded_from' => array(
'description' => __('Plan that this membership upgraded from.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'date_modified' => array(
'description' => __('Date this membership was last modified.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'disabled' => array(
'description' => __('If this membership is a disabled one.', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
'recurring' => array(
'description' => __('If this membership is recurring (true), which means the customer paid a defined amount each period of time, or not recurring (false).', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
'migrated_from_id' => array(
'description' => __('The ID of the original 1.X model that was used to generate this item on migration.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'skip_validation' => array(
'description' => __('Set true to have field information validation bypassed when saving this event.', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
);

View File

@ -0,0 +1,125 @@
<?php
/**
* Schema for payment@create.
*
* @package WP_Ultimo\API\Schemas
* @since 2.0.11
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
use WP_Ultimo\Database\Payments\Payment_Status;
/**
* Schema for payment@create.
*
* @since 2.0.11
* @internal last-generated in 2022-12
* @generated class generated by our build scripts, do not change!
*
* @since 2.0.11
*/
return array(
'customer_id' => array(
'description' => __('The ID of the customer attached to this payment.', 'wp-ultimo'),
'type' => 'integer',
'required' => true,
),
'membership_id' => array(
'description' => __('The ID of the membership attached to this payment.', 'wp-ultimo'),
'type' => 'integer',
'required' => true,
),
'parent_id' => array(
'description' => __('The ID from another payment that this payment is related to.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'currency' => array(
'description' => __("The currency of this payment. It's a 3-letter code. E.g. 'USD'.", 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'subtotal' => array(
'description' => __('Value before taxes, discounts, fees and other changes.', 'wp-ultimo'),
'type' => 'number',
'required' => true,
),
'refund_total' => array(
'description' => __('Total amount refunded.', 'wp-ultimo'),
'type' => 'number',
'required' => false,
),
'tax_total' => array(
'description' => __('The amount, in currency, of the tax.', 'wp-ultimo'),
'type' => 'number',
'required' => false,
),
'discount_code' => array(
'description' => __('Discount code used.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'total' => array(
'description' => __('This takes into account fees, discounts and credits.', 'wp-ultimo'),
'type' => 'number',
'required' => true,
),
'status' => array(
'description' => __("The payment status: Can be 'pending', 'completed', 'refunded', 'partially-refunded', 'partially-paid', 'failed', 'cancelled' or other values added by third-party add-ons.", 'wp-ultimo'),
'type' => 'string',
'required' => true,
'enum' => Payment_Status::get_allowed_list(),
),
'gateway' => array(
'description' => __('ID of the gateway being used on this payment.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'product_id' => array(
'description' => __('The ID of the product of this payment.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'gateway_payment_id' => array(
'description' => __('The ID of the payment on the gateway, if it exists.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'discount_total' => array(
'description' => __('The total value of the discounts applied to this payment.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'invoice_number' => array(
'description' => __('Sequential invoice number assigned to this payment.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'cancel_membership_on_refund' => array(
'description' => __('Holds if we need to cancel the membership on refund.', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
'date_created' => array(
'description' => __('Model creation date.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'date_modified' => array(
'description' => __('Model last modification date.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'migrated_from_id' => array(
'description' => __('The ID of the original 1.X model that was used to generate this item on migration.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'skip_validation' => array(
'description' => __('Set true to have field information validation bypassed when saving this event.', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
);

View File

@ -0,0 +1,125 @@
<?php
/**
* Schema for payment@update.
*
* @package WP_Ultimo\API\Schemas
* @since 2.0.11
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
use WP_Ultimo\Database\Payments\Payment_Status;
/**
* Schema for payment@update.
*
* @since 2.0.11
* @internal last-generated in 2022-12
* @generated class generated by our build scripts, do not change!
*
* @since 2.0.11
*/
return array(
'customer_id' => array(
'description' => __('The ID of the customer attached to this payment.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'membership_id' => array(
'description' => __('The ID of the membership attached to this payment.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'parent_id' => array(
'description' => __('The ID from another payment that this payment is related to.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'currency' => array(
'description' => __("The currency of this payment. It's a 3-letter code. E.g. 'USD'.", 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'subtotal' => array(
'description' => __('Value before taxes, discounts, fees and other changes.', 'wp-ultimo'),
'type' => 'number',
'required' => false,
),
'refund_total' => array(
'description' => __('Total amount refunded.', 'wp-ultimo'),
'type' => 'number',
'required' => false,
),
'tax_total' => array(
'description' => __('The amount, in currency, of the tax.', 'wp-ultimo'),
'type' => 'number',
'required' => false,
),
'discount_code' => array(
'description' => __('Discount code used.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'total' => array(
'description' => __('This takes into account fees, discounts and credits.', 'wp-ultimo'),
'type' => 'number',
'required' => false,
),
'status' => array(
'description' => __("The payment status: Can be 'pending', 'completed', 'refunded', 'partially-refunded', 'partially-paid', 'failed', 'cancelled' or other values added by third-party add-ons.", 'wp-ultimo'),
'type' => 'string',
'required' => false,
'enum' => Payment_Status::get_allowed_list(),
),
'gateway' => array(
'description' => __('ID of the gateway being used on this payment.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'product_id' => array(
'description' => __('The ID of the product of this payment.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'gateway_payment_id' => array(
'description' => __('The ID of the payment on the gateway, if it exists.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'discount_total' => array(
'description' => __('The total value of the discounts applied to this payment.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'invoice_number' => array(
'description' => __('Sequential invoice number assigned to this payment.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'cancel_membership_on_refund' => array(
'description' => __('Holds if we need to cancel the membership on refund.', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
'date_created' => array(
'description' => __('Model creation date.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'date_modified' => array(
'description' => __('Model last modification date.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'migrated_from_id' => array(
'description' => __('The ID of the original 1.X model that was used to generate this item on migration.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'skip_validation' => array(
'description' => __('Set true to have field information validation bypassed when saving this event.', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
);

View File

@ -0,0 +1,199 @@
<?php
/**
* Schema for product@create.
*
* @package WP_Ultimo\API\Schemas
* @since 2.0.11
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Schema for product@create.
*
* @since 2.0.11
* @internal last-generated in 2022-12
* @generated class generated by our build scripts, do not change!
*
* @since 2.0.11
*/
return array(
'featured_image_id' => array(
'description' => __('The ID of the feature image of the product.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'slug' => array(
'description' => __('The product slug. It needs to be unique and preferably make it clear what it is about. Example: my_new_product.', 'wp-ultimo'),
'type' => 'string',
'required' => true,
),
'name' => array(
'description' => __('Your product name, which is used as product title as well.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'description' => array(
'description' => __('A description for the product, usually a short text.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'currency' => array(
'description' => __("The currency that this product accepts. It's a 3-letter code. E.g. 'USD'.", 'wp-ultimo'),
'type' => 'string',
'required' => true,
),
'pricing_type' => array(
'description' => __("The pricing type can be 'free', 'paid' or 'contact_us'.", 'wp-ultimo'),
'type' => 'string',
'required' => true,
'enum' => array(
'free',
'paid',
'contact_us',
),
),
'trial_duration' => array(
'description' => __('The duration of the trial period of this product, if the product has one.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'trial_duration_unit' => array(
'description' => __('The unit of the trial duration amount. Can be day, week, month or year.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
'enum' => array(
'day',
'week',
'month',
'year',
),
),
'duration' => array(
'description' => __('Time interval between charges.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'duration_unit' => array(
'description' => __('Time interval unit between charges.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
'enum' => array(
'day',
'month',
'week',
'year',
),
),
'amount' => array(
'description' => __('The value of this product. E.g. 19.99.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'setup_fee' => array(
'description' => __('The setup fee value, if the product has one. E.g. 159.99.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'active' => array(
'description' => __('Set this product as active (true), which means available to be used, or inactive (false).', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
'type' => array(
'description' => __("The default product types are 'product', 'service' and 'package'. More types can be add using the product type filter.", 'wp-ultimo'),
'type' => 'string',
'required' => true,
'enum' => array(
'plan',
'service',
'package',
),
),
'parent_id' => array(
'description' => __('The ID from another Product that this product is related to.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'recurring' => array(
'description' => __('Set this product as a recurring one (true), which means the customer paid a defined amount each period of time, or not recurring (false).', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
'billing_cycles' => array(
'description' => __('The number of times we should charge this product.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'date_created' => array(
'description' => __('Date when this was created.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'date_modified' => array(
'description' => __('Date when this was last modified.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'taxable' => array(
'description' => __('Set this product as a taxable one (true), which means tax rules are applied to, or not taxable (false).', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
'tax_category' => array(
'description' => __('Category of taxes applied to this product. You need to set this if taxable is set to true.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'contact_us_label' => array(
'description' => __("If the product is the 'contact_us' type, it will need a label for the contact us button.", 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'contact_us_link' => array(
'description' => __('The url where the contact us button will lead to.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'feature_list' => array(
'description' => __('A list (array) of features of the product.', 'wp-ultimo'),
'type' => 'array',
'required' => false,
),
'customer_role' => array(
'description' => __('The customer role of this product.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'available_addons' => array(
'description' => __('The available addons of this product.', 'wp-ultimo'),
'type' => 'array',
'required' => false,
),
'group' => array(
'description' => __('The group of this product, if has any.', 'wp-ultimo'),
'type' => 'array',
'required' => false,
),
'legacy_options' => array(
'description' => __('If the legacy options are enabled.', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
'migrated_from_id' => array(
'description' => __('The ID of the original 1.X model that was used to generate this item on migration.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'skip_validation' => array(
'description' => __('Set true to have field information validation bypassed when saving this event.', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
'featured_plan' => array(
'description' => __('Feature list for pricing tables.', 'wp-ultimo'),
'type' => 'array',
'required' => false,
),
);

View File

@ -0,0 +1,199 @@
<?php
/**
* Schema for product@update.
*
* @package WP_Ultimo\API\Schemas
* @since 2.0.11
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Schema for product@update.
*
* @since 2.0.11
* @internal last-generated in 2022-12
* @generated class generated by our build scripts, do not change!
*
* @since 2.0.11
*/
return array(
'featured_image_id' => array(
'description' => __('The ID of the feature image of the product.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'slug' => array(
'description' => __('The product slug. It needs to be unique and preferably make it clear what it is about. Example: my_new_product.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'name' => array(
'description' => __('Your product name, which is used as product title as well.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'description' => array(
'description' => __('A description for the product, usually a short text.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'currency' => array(
'description' => __("The currency that this product accepts. It's a 3-letter code. E.g. 'USD'.", 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'pricing_type' => array(
'description' => __("The pricing type can be 'free', 'paid' or 'contact_us'.", 'wp-ultimo'),
'type' => 'string',
'required' => false,
'enum' => array(
'free',
'paid',
'contact_us',
),
),
'trial_duration' => array(
'description' => __('The duration of the trial period of this product, if the product has one.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'trial_duration_unit' => array(
'description' => __('The unit of the trial duration amount. Can be day, week, month or year.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
'enum' => array(
'day',
'week',
'month',
'year',
),
),
'duration' => array(
'description' => __('Time interval between charges.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'duration_unit' => array(
'description' => __('Time interval unit between charges.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
'enum' => array(
'day',
'month',
'week',
'year',
),
),
'amount' => array(
'description' => __('The value of this product. E.g. 19.99.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'setup_fee' => array(
'description' => __('The setup fee value, if the product has one. E.g. 159.99.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'active' => array(
'description' => __('Set this product as active (true), which means available to be used, or inactive (false).', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
'type' => array(
'description' => __("The default product types are 'product', 'service' and 'package'. More types can be add using the product type filter.", 'wp-ultimo'),
'type' => 'string',
'required' => false,
'enum' => array(
'plan',
'service',
'package',
),
),
'parent_id' => array(
'description' => __('The ID from another Product that this product is related to.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'recurring' => array(
'description' => __('Set this product as a recurring one (true), which means the customer paid a defined amount each period of time, or not recurring (false).', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
'billing_cycles' => array(
'description' => __('The number of times we should charge this product.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'date_created' => array(
'description' => __('Date when this was created.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'date_modified' => array(
'description' => __('Date when this was last modified.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'taxable' => array(
'description' => __('Set this product as a taxable one (true), which means tax rules are applied to, or not taxable (false).', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
'tax_category' => array(
'description' => __('Category of taxes applied to this product. You need to set this if taxable is set to true.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'contact_us_label' => array(
'description' => __("If the product is the 'contact_us' type, it will need a label for the contact us button.", 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'contact_us_link' => array(
'description' => __('The url where the contact us button will lead to.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'feature_list' => array(
'description' => __('A list (array) of features of the product.', 'wp-ultimo'),
'type' => 'array',
'required' => false,
),
'customer_role' => array(
'description' => __('The customer role of this product.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'available_addons' => array(
'description' => __('The available addons of this product.', 'wp-ultimo'),
'type' => 'array',
'required' => false,
),
'group' => array(
'description' => __('The group of this product, if has any.', 'wp-ultimo'),
'type' => 'array',
'required' => false,
),
'legacy_options' => array(
'description' => __('If the legacy options are enabled.', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
'migrated_from_id' => array(
'description' => __('The ID of the original 1.X model that was used to generate this item on migration.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'skip_validation' => array(
'description' => __('Set true to have field information validation bypassed when saving this event.', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
'featured_plan' => array(
'description' => __('Feature list for pricing tables.', 'wp-ultimo'),
'type' => 'array',
'required' => false,
),
);

View File

@ -0,0 +1,165 @@
<?php
/**
* Schema for site@create.
*
* @package WP_Ultimo\API\Schemas
* @since 2.0.11
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Schema for site@create.
*
* @since 2.0.11
* @internal last-generated in 2022-12
* @generated class generated by our build scripts, do not change!
*
* @since 2.0.11
*/
return array(
'categories' => array(
'description' => __('The categories this site belongs to.', 'wp-ultimo'),
'type' => 'array',
'required' => false,
),
'featured_image_id' => array(
'description' => __('The ID of the feature image of the site.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'site_id' => array(
'description' => __('The network ID for this site.', 'wp-ultimo'),
'type' => 'integer',
'required' => true,
),
'title' => array(
'description' => __('The site title.', 'wp-ultimo'),
'type' => 'string',
'required' => true,
),
'name' => array(
'description' => __('The site name.', 'wp-ultimo'),
'type' => 'string',
'required' => true,
),
'description' => array(
'description' => __('A description for the site, usually a short text.', 'wp-ultimo'),
'type' => 'string',
'required' => true,
),
'domain' => array(
'description' => __("The site domain. You don't need to put http or https in front of your domain in this field. e.g: example.com.", 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'path' => array(
'description' => __('Path of the site. Used when in sub-directory mode.', 'wp-ultimo'),
'type' => 'string',
'required' => true,
),
'registered' => array(
'description' => __('Date when the site was registered.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'last_updated' => array(
'description' => __('Date of the last update on this site.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'active' => array(
'description' => __('Holds the ID of the customer that owns this site.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'public' => array(
'description' => __('Set true if this site is a public one, false if not.', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
'archived' => array(
'description' => __('Is this an archived site.', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
'mature' => array(
'description' => __('Is this a site with mature content.', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
'spam' => array(
'description' => __('Is this an spam site.', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
'deleted' => array(
'description' => __('Is this site deleted.', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
'lang_id' => array(
'description' => __('The ID of the language being used on this site.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'customer_id' => array(
'description' => __('The ID of the customer that owns this site.', 'wp-ultimo'),
'type' => 'integer',
'required' => true,
),
'membership_id' => array(
'description' => __('The ID of the membership associated with this site, if any.', 'wp-ultimo'),
'type' => 'integer',
'required' => true,
),
'template_id' => array(
'description' => __('The ID of the templated used to create this site.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'type' => array(
'description' => __('The type of this particular site. Can be default, site_template, customer_owned, pending, external, main or other values added by third-party add-ons.', 'wp-ultimo'),
'type' => 'string',
'required' => true,
'enum' => array(
'default',
'site_template',
'customer_owned',
'pending',
'external',
'main',
),
),
'signup_options' => array(
'description' => __('Keeps signup options for the site.', 'wp-ultimo'),
'type' => 'array',
'required' => false,
),
'signup_meta' => array(
'description' => __('Keeps signup meta for the site.', 'wp-ultimo'),
'type' => 'array',
'required' => false,
),
'date_created' => array(
'description' => __('Model creation date.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'date_modified' => array(
'description' => __('Model last modification date.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'migrated_from_id' => array(
'description' => __('The ID of the original 1.X model that was used to generate this item on migration.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'skip_validation' => array(
'description' => __('Set true to have field information validation bypassed when saving this event.', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
);

View File

@ -0,0 +1,165 @@
<?php
/**
* Schema for site@update.
*
* @package WP_Ultimo\API\Schemas
* @since 2.0.11
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Schema for site@update.
*
* @since 2.0.11
* @internal last-generated in 2022-12
* @generated class generated by our build scripts, do not change!
*
* @since 2.0.11
*/
return array(
'categories' => array(
'description' => __('The categories this site belongs to.', 'wp-ultimo'),
'type' => 'array',
'required' => false,
),
'featured_image_id' => array(
'description' => __('The ID of the feature image of the site.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'site_id' => array(
'description' => __('The network ID for this site.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'title' => array(
'description' => __('The site title.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'name' => array(
'description' => __('The site name.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'description' => array(
'description' => __('A description for the site, usually a short text.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'domain' => array(
'description' => __("The site domain. You don't need to put http or https in front of your domain in this field. e.g: example.com.", 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'path' => array(
'description' => __('Path of the site. Used when in sub-directory mode.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'registered' => array(
'description' => __('Date when the site was registered.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'last_updated' => array(
'description' => __('Date of the last update on this site.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'active' => array(
'description' => __('Holds the ID of the customer that owns this site.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'public' => array(
'description' => __('Set true if this site is a public one, false if not.', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
'archived' => array(
'description' => __('Is this an archived site.', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
'mature' => array(
'description' => __('Is this a site with mature content.', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
'spam' => array(
'description' => __('Is this an spam site.', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
'deleted' => array(
'description' => __('Is this site deleted.', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
'lang_id' => array(
'description' => __('The ID of the language being used on this site.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'customer_id' => array(
'description' => __('The ID of the customer that owns this site.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'membership_id' => array(
'description' => __('The ID of the membership associated with this site, if any.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'template_id' => array(
'description' => __('The ID of the templated used to create this site.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'type' => array(
'description' => __('The type of this particular site. Can be default, site_template, customer_owned, pending, external, main or other values added by third-party add-ons.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
'enum' => array(
'default',
'site_template',
'customer_owned',
'pending',
'external',
'main',
),
),
'signup_options' => array(
'description' => __('Keeps signup options for the site.', 'wp-ultimo'),
'type' => 'array',
'required' => false,
),
'signup_meta' => array(
'description' => __('Keeps signup meta for the site.', 'wp-ultimo'),
'type' => 'array',
'required' => false,
),
'date_created' => array(
'description' => __('Model creation date.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'date_modified' => array(
'description' => __('Model last modification date.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'migrated_from_id' => array(
'description' => __('The ID of the original 1.X model that was used to generate this item on migration.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'skip_validation' => array(
'description' => __('Set true to have field information validation bypassed when saving this event.', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
);

View File

@ -0,0 +1,82 @@
<?php
/**
* Schema for webhook@create.
*
* @package WP_Ultimo\API\Schemas
* @since 2.0.11
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Schema for webhook@create.
*
* @since 2.0.11
* @internal last-generated in 2022-12
* @generated class generated by our build scripts, do not change!
*
* @since 2.0.11
*/
return array(
'name' => array(
'description' => __('Webhook name, which is used as product title as well.', 'wp-ultimo'),
'type' => 'string',
'required' => true,
),
'webhook_url' => array(
'description' => __('The URL used for the webhook call.', 'wp-ultimo'),
'type' => 'string',
'required' => true,
),
'event' => array(
'description' => __('The event that needs to be fired for this webhook to be sent.', 'wp-ultimo'),
'type' => 'string',
'required' => true,
),
'event_count' => array(
'description' => __('How many times this webhook was sent.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'active' => array(
'description' => __('Set this webhook as active (true), which means available will fire when the event occur, or inactive (false).', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
'hidden' => array(
'description' => __('Is this webhook hidden.', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
'date_created' => array(
'description' => __('Date when this was created.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'integration' => array(
'description' => __('The integration that created this webhook.', 'wp-ultimo'),
'type' => 'string',
'required' => true,
),
'date_last_failed' => array(
'description' => __('The date when this webhook last fail.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'date_modified' => array(
'description' => __('Model last modification date.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'migrated_from_id' => array(
'description' => __('The ID of the original 1.X model that was used to generate this item on migration.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'skip_validation' => array(
'description' => __('Set true to have field information validation bypassed when saving this event.', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
);

View File

@ -0,0 +1,82 @@
<?php
/**
* Schema for webhook@update.
*
* @package WP_Ultimo\API\Schemas
* @since 2.0.11
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Schema for webhook@update.
*
* @since 2.0.11
* @internal last-generated in 2022-12
* @generated class generated by our build scripts, do not change!
*
* @since 2.0.11
*/
return array(
'name' => array(
'description' => __('Webhook name, which is used as product title as well.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'webhook_url' => array(
'description' => __('The URL used for the webhook call.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'event' => array(
'description' => __('The event that needs to be fired for this webhook to be sent.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'event_count' => array(
'description' => __('How many times this webhook was sent.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'active' => array(
'description' => __('Set this webhook as active (true), which means available will fire when the event occur, or inactive (false).', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
'hidden' => array(
'description' => __('Is this webhook hidden.', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
'date_created' => array(
'description' => __('Date when this was created.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'integration' => array(
'description' => __('The integration that created this webhook.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'date_last_failed' => array(
'description' => __('The date when this webhook last fail.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'date_modified' => array(
'description' => __('Model last modification date.', 'wp-ultimo'),
'type' => 'string',
'required' => false,
),
'migrated_from_id' => array(
'description' => __('The ID of the original 1.X model that was used to generate this item on migration.', 'wp-ultimo'),
'type' => 'integer',
'required' => false,
),
'skip_validation' => array(
'description' => __('Set true to have field information validation bypassed when saving this event.', 'wp-ultimo'),
'type' => 'boolean',
'required' => false,
),
);

697
inc/api/trait-rest-api.php Normal file
View File

@ -0,0 +1,697 @@
<?php
/**
* A trait to be included in entities to enable REST API endpoints.
*
* @package WP_Ultimo
* @subpackage Apis
* @since 2.0.0
*/
namespace WP_Ultimo\Apis;
/**
* REST API trait.
*/
trait Rest_Api {
/**
* The base used in the route right after the namespace: <namespace>/<rest_base>.
*
* @since 2.0.0
* @var string
*/
protected $rest_base = '';
/**
* REST endpoints enabled for this entity.
*
* @since 2.0.0
* @var array
*/
protected $enabled_rest_endpoints = array(
'get_item',
'get_items',
'create_item',
'update_item',
'delete_item',
);
/**
* Returns the base used right after the namespace.
* Uses the `rest_base` attribute if set, `slug` otherwise.
*
* @since 2.0.0
* @return string
*/
public function get_rest_base() {
return (!empty($this->rest_base)) ? $this->rest_base : $this->slug;
} // end get_rest_base;
/**
* Registers the routes. Should be called by the entity
* to actually enable the REST API.
*
* @since 2.0.0
*/
public function enable_rest_api() {
$is_enabled = \WP_Ultimo\API::get_instance()->is_api_enabled();
if ($is_enabled) {
add_action('rest_api_init', array($this, 'register_routes_general'));
add_action('rest_api_init', array($this, 'register_routes_with_id'));
} // end if;
} // end enable_rest_api;
/**
* Register the endpoints that don't need an ID,
* like creation and lists.
*
* @since 2.0.0
*/
public function register_routes_general() {
$routes = array();
if (in_array('get_items', $this->enabled_rest_endpoints, true)) {
$routes = array(
array(
'methods' => \WP_REST_Server::READABLE,
'callback' => array($this, 'get_items_rest'),
'permission_callback' => array($this, 'get_items_permissions_check'),
),
);
} // end if;
if (in_array('create_item', $this->enabled_rest_endpoints, true)) {
$routes[] = array(
'methods' => \WP_REST_Server::CREATABLE,
'callback' => array($this, 'create_item_rest'),
'permission_callback' => array($this, 'create_item_permissions_check'),
'args' => $this->get_arguments_schema()
);
} // end if;
if (!empty($routes)) {
register_rest_route(
\WP_Ultimo\API::get_instance()->get_namespace(),
'/' . $this->get_rest_base(),
$routes,
true
);
} // end if;
do_action('wu_rest_register_routes_general', $routes, $this->get_rest_base(), 'create', $this);
} // end register_routes_general;
/**
* Register the endpoints that need an ID,
* like get, update and delete of a single element.
*
* @since 2.0.0
*/
public function register_routes_with_id() {
$routes = array();
if (in_array('get_item', $this->enabled_rest_endpoints, true)) {
$routes[] = array(
'methods' => \WP_REST_Server::READABLE,
'callback' => array($this, 'get_item_rest'),
'permission_callback' => array($this, 'get_item_permissions_check'),
);
} // end if;
if (in_array('update_item', $this->enabled_rest_endpoints, true)) {
$routes[] = array(
'methods' => \WP_REST_Server::EDITABLE,
'callback' => array($this, 'update_item_rest'),
'permission_callback' => array($this, 'update_item_permissions_check'),
'args' => $this->get_arguments_schema(true)
);
} // end if;
if (in_array('delete_item', $this->enabled_rest_endpoints, true)) {
$routes[] = array(
'methods' => \WP_REST_Server::DELETABLE,
'callback' => array($this, 'delete_item_rest'),
'permission_callback' => array($this, 'delete_item_permissions_check'),
);
} // end if;
if (!empty($routes)) {
register_rest_route(
\WP_Ultimo\API::get_instance()->get_namespace(),
'/' . $this->get_rest_base() . '/(?P<id>[\d]+)',
$routes,
true
);
} // end if;
do_action('wu_rest_register_routes_with_id', $routes, $this->get_rest_base(), 'update', $this);
} // end register_routes_with_id;
/**
* Returns a specific item.
*
* @since 2.0.0
*
* @param WP_REST_Request $request The request sent.
* @return \WP_REST_Response|\WP_Error
*/
public function get_item_rest($request) {
$item = $this->model_class::get_by_id($request['id']);
if (empty($item)) {
return new \WP_Error("wu_rest_{$this->slug}_invalid_id", __('Item not found.', 'wp-ultimo'), array('status' => 404));
} // end if;
return rest_ensure_response($item);
} // end get_item_rest;
/**
* Returns a list of items.
*
* @since 2.0.0
*
* @param WP_REST_Request $request The request sent.
* @return \WP_REST_Response|\WP_Error
*/
public function get_items_rest($request) {
$items = $this->model_class::query($request->get_params());
return rest_ensure_response($items);
} // end get_items_rest;
/**
* Creates an item.
*
* @since 2.0.0
*
* @param WP_REST_Request $request The request sent.
* @return \WP_REST_Response|\WP_Error
*/
public function create_item_rest($request) {
$body = json_decode($request->get_body(), true);
$model_name = (new $this->model_class(array()))->model;
$saver_function = "wu_create_{$model_name}";
if (function_exists($saver_function)) {
$item = call_user_func($saver_function, $body);
$saved = is_wp_error($item) ? $item : true;
} else {
$item = new $this->model_class($body);
$saved = $item->save();
} // end if;
if (is_wp_error($saved)) {
return rest_ensure_response($saved);
} // end if;
if (!$saved) {
return new \WP_Error("wu_rest_{$this->slug}", __('Something went wrong (Code 1).', 'wp-ultimo'), array('status' => 400));
} // end if;
return rest_ensure_response($item);
} // end create_item_rest;
/**
* Updates an item.
*
* @since 2.0.0
*
* @param WP_REST_Request $request The request sent.
* @return \WP_REST_Response|\WP_Error
*/
public function update_item_rest($request) {
$id = wu_get_isset($request->get_url_params(), 'id');
$item = $this->model_class::get_by_id($id);
if (empty($item)) {
return new \WP_Error("wu_rest_{$this->slug}_invalid_id", __('Item not found.', 'wp-ultimo'), array('status' => 404));
} // end if;
$params = array_filter(
json_decode($request->get_body(), true),
array($this, 'is_not_credential_key'),
ARRAY_FILTER_USE_KEY
);
foreach ($params as $param => $value) {
$set_method = "set_{$param}";
if ($param === 'meta') {
$item->update_meta_batch($value);
} elseif (method_exists($item, $set_method)) {
call_user_func(array($item, $set_method), $value);
} else {
$error_message = sprintf(
/* translators: 1. Object class name; 2. Set method name */
__('The %1$s object does not have a %2$s method', 'wp-ultimo'),
get_class($item),
$set_method
);
return new \WP_Error(
"wu_rest_{$this->slug}_invalid_set_method",
$error_message,
array('status' => 400)
);
} // end if;
} // end foreach;
$saved = $item->save();
if (is_wp_error($saved)) {
return rest_ensure_response($saved);
} // end if;
if (!$saved) {
return new \WP_Error("wu_rest_{$this->slug}", __('Something went wrong (Code 2).', 'wp-ultimo'));
} // end if;
return rest_ensure_response($item);
} // end update_item_rest;
/**
* Deletes an item.
*
* @since 2.0.0
*
* @param WP_REST_Request $request The request sent.
* @return \WP_REST_Response|\WP_Error
*/
public function delete_item_rest($request) {
$item = $this->model_class::get_by_id($request['id']);
if (empty($item)) {
return new \WP_Error("wu_rest_{$this->slug}_invalid_id", __('Item not found.', 'wp-ultimo'), array('status' => 404));
} // end if;
$result = $item->delete();
return rest_ensure_response($result);
} // end delete_item_rest;
/**
* Check permissions to list items.
*
* @since 2.0.0
*
* @param WP_REST_Request $request The request sent.
* @return bool
*/
public function get_items_permissions_check($request) {
if (!\WP_Ultimo\API::get_instance()->check_authorization($request)) {
return false;
} // end if;
/**
* Filters if it is allowed to proceed with the request or not.
*
* @since 2.0.0
*
* @param bool $allowed Initial return value.
* @param array $rest_base Entity slug.
* @param Base_Manager $this The object instance.
*/
return apply_filters('wu_rest_get_items', true, $this->get_rest_base(), $this);
} // end get_items_permissions_check;
/**
* Check permissions to create an item.
*
* @since 2.0.0
*
* @param WP_REST_Request $request The request sent.
* @return bool
*/
public function create_item_permissions_check($request) {
if (!\WP_Ultimo\API::get_instance()->check_authorization($request)) {
return false;
} // end if;
/**
* Filters if it is allowed to proceed with the request or not.
*
* @since 2.0.0
*
* @param bool $allowed Initial return value.
* @param array $rest_base Entity slug.
* @param Base_Manager $this The object instance.
*/
return apply_filters('wu_rest_create_item', true, $this->get_rest_base(), $this);
} // end create_item_permissions_check;
/**
* Check permissions to get an item.
*
* @since 2.0.0
*
* @param WP_REST_Request $request The request sent.
* @return bool
*/
public function get_item_permissions_check($request) {
if (!\WP_Ultimo\API::get_instance()->check_authorization($request)) {
return false;
} // end if;
/**
* Filters if it is allowed to proceed with the request or not.
*
* @since 2.0.0
*
* @param bool $allowed Initial return value.
* @param array $rest_base Entity slug.
* @param Base_Manager $this The object instance.
*/
return apply_filters('wu_rest_get_item', true, $this->get_rest_base(), $this);
} // end get_item_permissions_check;
/**
* Check permissions to update an item.
*
* @since 2.0.0
*
* @param WP_REST_Request $request The request sent.
* @return bool
*/
public function update_item_permissions_check($request) {
if (!\WP_Ultimo\API::get_instance()->check_authorization($request)) {
return false;
} // end if;
/**
* Filters if it is allowed to proceed with the request or not.
*
* @since 2.0.0
*
* @param bool $allowed Initial return value.
* @param array $rest_base Entity slug.
* @param Base_Manager $this The object instance.
*/
return apply_filters('wu_rest_update_item', true, $this->get_rest_base(), $this);
} // end update_item_permissions_check;
/**
* Check permissions to delete an item.
*
* @since 2.0.0
*
* @param WP_REST_Request $request The request sent.
* @return bool
*/
public function delete_item_permissions_check($request) {
if (!\WP_Ultimo\API::get_instance()->check_authorization($request)) {
return false;
} // end if;
/**
* Filters if it is allowed to proceed with the request or not.
*
* @since 2.0.0
*
* @param bool $allowed Initial return value.
* @param array $rest_base Entity slug.
* @param Base_Manager $this The object instance.
*/
return apply_filters('wu_rest_delete_item', true, $this->get_rest_base(), $this);
} // end delete_item_permissions_check;
/**
* Checks if a value is not a credential key.
*
* @since 2.0.0
*
* @param string $value The value that will be checked.
* @return bool
*/
private function is_not_credential_key($value) {
$credentials_keys = array(
'api_key',
'api_secret',
'api-key',
'api-secret',
);
return !in_array($value, $credentials_keys, true);
} // end is_not_credential_key;
/**
* Checks if a value is not equal to "id".
*
* @since 2.0.0
*
* @param string $value The value that will be checked.
* @return bool
*/
private function is_not_id_key($value) {
$arr = array(
'id',
);
if ($this->slug === 'site') {
$arr = array(
'id',
'blog_id',
);
} // end if;
return !in_array($value, $arr, true);
} // end is_not_id_key;
/**
* Get the arguments for an endpoint
*
* @since 2.0.0
*
* @param bool $edit Context. In edit, some fields, like ids, are not mandatory.
* @return array
*/
public function get_arguments_schema($edit = false) {
$schema = wu_rest_get_endpoint_schema($this->model_class, $edit ? 'update' : 'create', true);
$args = array_filter($schema, array($this, 'is_not_id_key'), ARRAY_FILTER_USE_KEY);
return $this->filter_schema_arguments($args);
} // end get_arguments_schema;
/**
* Remove some properties from the API schema.
*
* @since 2.0.0
*
* @param array $args Schema array.
* @return array
*/
public function filter_schema_arguments($args) {
/**
* Filter the original api arguments.
*
* @since 2.0.0
*
* @param array $args API Arguments for this manager.
* @param object $this This manager.
*/
apply_filters('wu_before_' . $this->slug . '_api_arguments', $args, $this);
if ($this->slug !== 'broadcast' && isset($args['author_id'])) {
unset($args['author_id']);
} // end if;
if (isset($args['list_order'])) {
unset($args['list_order']);
} // end if;
$remove_status = apply_filters("wu_api_{$this->slug}_remove_status", array(
'broadcast',
'membership',
'product',
'payment',
));
if (!in_array($this->slug, $remove_status, true) && isset($args['status'])) {
unset($args['status']);
} // end if;
$remove_slug = apply_filters("wu_api_{$this->slug}_remove_slug", array(
'broadcast',
'product',
'checkout_form',
'event',
));
if (!in_array($this->slug, $remove_slug, true) && isset($args['slug'])) {
unset($args['slug']);
} // end if;
if ($this->slug === 'product' && isset($args['price_variations'])) {
unset($args['price_variations']);
} // end if;
if ($this->slug === 'payment' && isset($args['line_items'])) {
unset($args['line_items']);
} // end if;
if ($this->slug === 'site') {
if (isset($args['duplication_arguments'])) {
unset($args['duplication_arguments']);
} // end if;
if (isset($args['transient'])) {
unset($args['transient']);
} // end if;
} // end if;
if ($this->slug === 'email') {
if (isset($args['status'])) {
unset($args['status']);
} // end if;
if (isset($args['email_schedule'])) {
unset($args['email_schedule']);
} // end if;
} // end if;
if ($this->slug === 'broadcast') {
if (isset($args['message_targets'])) {
unset($args['message_targets']);
} // end if;
} // end if;
if (isset($args['billing_address'])) {
unset($args['billing_address']);
} // end if;
/**
* Filter after being changed.
*
* @since 2.0.0
*
* @param array $args API Arguments for this manager.
* @param object $this This manager.
*/
apply_filters('wu_after_' . $this->slug . '_api_arguments', $args, $this);
return $args;
} // end filter_schema_arguments;
} // end trait Rest_Api;

448
inc/api/trait-wp-cli.php Normal file
View File

@ -0,0 +1,448 @@
<?php
/**
* A trait to be included in entities to enable WP CLI commands.
*
* @package WP_Ultimo
* @subpackage Apis
* @since 2.0.0
*/
namespace WP_Ultimo\Apis;
/**
* WP CLI trait.
*/
trait WP_CLI {
/**
* The base used in the command right after the root: `wp <root> <command_base> <sub_command>`.
*
* @since 2.0.0
* @var string
*/
protected $wp_cli_command_base = '';
/**
* WP-CLI Sub_command enabled for this entity.
*
* @since 2.0.0
* @var array
*/
protected $wp_cli_enabled_sub_commands = array();
/**
* Returns the base used right after the root.
* Uses the `wp_cli_command_base` attribute if set, `slug` otherwise.
*
* @since 2.0.0
* @return string
*/
public function get_wp_cli_command_base() {
return (!empty($this->wp_cli_command_base)) ? $this->wp_cli_command_base : $this->slug;
} // end get_wp_cli_command_base;
/**
* Registers the routes. Should be called by the entity
* to actually enable the REST API.
*
* @since 2.0.0
*/
public function enable_wp_cli() {
if (!defined('WP_CLI')) {
return;
} // end if;
$wp_cli_root = 'wu';
$this->set_wp_cli_enabled_sub_commands();
foreach ($this->wp_cli_enabled_sub_commands as $sub_command => $sub_command_data) {
\WP_CLI::add_command(
"{$wp_cli_root} {$this->get_wp_cli_command_base()} {$sub_command}",
$sub_command_data['callback'],
array(
'synopsis' => $sub_command_data['synopsis'],
)
);
} // end foreach;
} // end enable_wp_cli;
/**
* Set wP-CLI Sub-command enabled for this entity.
*/
public function set_wp_cli_enabled_sub_commands() {
$sub_commands = array(
'get' => array(
'callback' => array($this, 'wp_cli_get_item'),
),
'list' => array(
'callback' => array($this, 'wp_cli_get_items'),
),
'create' => array(
'callback' => array($this, 'wp_cli_create_item'),
),
'update' => array(
'callback' => array($this, 'wp_cli_update_item'),
),
'delete' => array(
'callback' => array($this, 'wp_cli_delete_item'),
),
);
$params = array_merge($this->wp_cli_get_fields(), $this->wp_cli_extra_parameters());
$params = array_unique($params);
/**
* Unset undesired Params.
*/
$params_to_remove = apply_filters('wu_cli_params_to_remove', array(
'id',
'model',
));
$params = array_filter($params, fn($param) => !in_array($param, $params_to_remove, true));
foreach ($sub_commands as $sub_command => &$sub_command_data) {
$sub_command_data['synopsis'] = array();
if (in_array($sub_command, array('get', 'update', 'delete'), true)) {
$sub_command_data['synopsis'][] = array(
'name' => 'id',
'type' => 'positional',
'description' => __('The id for the resource.', 'wp-ultimo'),
'optional' => false,
);
} // end if;
if (in_array($sub_command, array('list', 'update', 'create'), true)) {
$explanation_list = wu_rest_get_endpoint_schema($this->model_class, 'update');
foreach ($params as $name) {
$explanation = wu_get_isset($explanation_list, $name, array());
$type = wu_get_isset($explanation, 'type', 'assoc');
$field = array(
'name' => $name,
'description' => wu_get_isset($explanation, 'description', __('No description found.', 'wp-ultimo')),
'optional' => !wu_get_isset($explanation, 'required'),
'type' => 'assoc',
);
$options = wu_get_isset($explanation, 'options', array());
if ($options) {
$field['options'] = $options;
} // end if;
$sub_command_data['synopsis'][] = $field;
} // end foreach;
} // end if;
if (in_array($sub_command, array('create', 'update'), true)) {
$sub_command_data['synopsis'][] = array(
'name' => 'porcelain',
'type' => 'flag',
'description' => __('Output just the id when the operation is successful.', 'wp-ultimo'),
'optional' => true,
);
} // end if;
if (in_array($sub_command, array('list', 'get'), true)) {
$sub_command_data['synopsis'][] = array(
'name' => 'format',
'type' => 'assoc',
'description' => __('Render response in a particular format.', 'wp-ultimo'),
'optional' => true,
'default' => 'table',
'options' => array(
'table',
'json',
'csv',
'ids',
'yaml',
'count',
),
);
$sub_command_data['synopsis'][] = array(
'name' => 'fields',
'type' => 'assoc',
'description' => __('Limit response to specific fields. Defaults to id, name', 'wp-ultimo'),
'optional' => true,
'options' => array_merge(array('id'), $params),
);
} // end if;
} // end foreach;
$this->wp_cli_enabled_sub_commands = $sub_commands;
/**
* Filters which sub_commands are enabled for this entity.
*
* @since 2.0.0
*
* @param array $sub_commands Default sub_commands.
* @param string $command_base The base used in the command right after the root.
* @param Base_Manager $this The object instance.
*/
$this->wp_cli_enabled_sub_commands = apply_filters(
'wu_wp_cli_enabled_sub_commands',
$this->wp_cli_enabled_sub_commands,
$this->get_wp_cli_command_base(),
$this
);
} // end set_wp_cli_enabled_sub_commands;
/**
* Allows the additional of additional parameters.
*
* @since 2.0.0
*/
public function wp_cli_extra_parameters(): array {
$model = new $this->model_class();
return array_keys($model->to_array());
} // end wp_cli_extra_parameters;
/**
* Returns the list of default fields, based on the table schema.
*
* @since 2.0.0
* @return array List of the schema columns.
*/
public function wp_cli_get_fields(): array {
$schema = $this->model_class::get_schema();
return array_column($schema, 'name');
} // end wp_cli_get_fields;
/**
* Returns a specific item.
*
* @since 2.0.0
*
* @param array $args Positional arguments passed. ID expected.
* @param array $array_assoc Assoc arguments passed.
*/
public function wp_cli_get_item($args, $array_assoc) {
$item = $this->model_class::get_by_id($args[0]);
if (empty($item)) {
\WP_CLI::error('Invalid ID.');
} // end if;
$fields = (!empty($array_assoc['fields'])) ? $array_assoc['fields'] : $this->wp_cli_get_fields();
$formatter = new \WP_CLI\Formatter($array_assoc, $fields);
$formatter->display_item($item->to_array());
} // end wp_cli_get_item;
/**
* Returns a list of items.
*
* @since 2.0.0
*
* @param array $args Positional arguments passed. ID expected.
* @param array $array_assoc Assoc arguments passed.
*/
public function wp_cli_get_items($args, $array_assoc) {
$fields = (!empty($array_assoc['fields'])) ? $array_assoc['fields'] : $this->wp_cli_get_fields();
unset($array_assoc['fields']);
$items = $this->model_class::query($array_assoc);
$items = array_map(fn($item) => $item->to_array(), $items);
\WP_CLI\Utils\format_items($array_assoc['format'], $items, $fields);
} // end wp_cli_get_items;
/**
* Creates an item.
*
* @since 2.0.0
*
* @param array $args Positional arguments passed. ID expected.
* @param array $array_assoc Assoc arguments passed.
*/
public function wp_cli_create_item($args, $array_assoc) {
$item = new $this->model_class($array_assoc);
$success = $item->save();
if ($success === true) {
$item_id = $item->get_id();
if (!empty($array_assoc['porcelain'])) {
\WP_CLI::line($item_id);
} else {
$message = sprintf('Item created with ID %d', $item_id);
\WP_CLI::success($message);
} // end if;
} else {
\WP_CLI::error($success);
} // end if;
} // end wp_cli_create_item;
/**
* Updates an item.
*
* @since 2.0.0
*
* @param array $args Positional arguments passed. ID expected.
* @param array $array_assoc Assoc arguments passed.
*/
public function wp_cli_update_item($args, $array_assoc) {
$item = $this->model_class::get_by_id($args[0]);
if (empty($item)) {
\WP_CLI::error('Invalid ID.');
} // end if;
$porcelain = false;
if (!empty($array_assoc['porcelain'])) {
$porcelain = true;
unset($array_assoc['porcelain']);
} // end if;
$params = $array_assoc;
foreach ($params as $param => $value) {
$set_method = "set_{$param}";
if ($param === 'meta') {
$item->update_meta_batch($value);
} elseif (method_exists($item, $set_method)) {
call_user_func(array($item, $set_method), $value);
} else {
$error_message = sprintf(
/* translators: 1. Object class name; 2. Set method name */
__('The %1$s object does not have a %2$s method', 'wp-ultimo'),
get_class($item),
$set_method
);
\WP_CLI::error($error_message);
} // end if;
} // end foreach;
$success = $item->save();
if ($success) {
$item_id = $item->get_id();
if ($porcelain) {
\WP_CLI::line($item_id);
} else {
$message = sprintf('Item updated with ID %d', $item_id);
\WP_CLI::success($message);
} // end if;
} else {
\WP_CLI::error('Unexpected error. The item was not updated.');
} // end if;
} // end wp_cli_update_item;
/**
* Deletes an item.
*
* @since 2.0.0
*
* @param array $args Positional arguments passed. ID expected.
*/
public function wp_cli_delete_item($args) {
$item = $this->model_class::get_by_id($args[0]);
if (empty($item)) {
\WP_CLI::error('Invalid ID.');
} // end if;
$success = $item->delete();
if (is_wp_error($success) || !$success) {
\WP_CLI::error('Unexpected error. The item was not deleted.');
} else {
\WP_CLI::success('Item deleted.');
} // end if;
} // end wp_cli_delete_item;
} // end trait WP_CLI;

View File

@ -0,0 +1,279 @@
(function(blocks, element, components, wu_blocks, _) {
const el = element.createElement,
registerBlockType = blocks.registerBlockType,
ServerSideRender = wp.serverSideRender,
PanelBody = wp.components.PanelBody,
TextControl = wp.components.TextControl,
NumberControl = wp.components.__experimentalNumberControl,
RangeControl = wp.components.RangeControl,
ToggleControl = wp.components.ToggleControl,
TextareaControl = wp.components.TextareaControl,
Notice = wp.components.Notice,
SelectControl = wp.components.SelectControl,
InspectorControls = wp.blockEditor.InspectorControls;
_.each(wu_blocks, function(block, index) {
registerBlockType(block.id, {
icon: wu_badge(),
category: 'wp-ultimo',
title: block.title,
description: block.description,
keywords: block.keywords,
supports: {
multiple: false,
html: false,
},
edit(props) {
return [
el(ServerSideRender, {
key: block.id + index,
block: block.id,
attributes: props.attributes,
}),
wu_fields_to_block_options(block.fields, props),
];
},
save() {
return null;
},
});
}); // end each;
function wu_fields_to_block_options(fields, props) {
const gt_panels = [];
let gt_fields = [];
let current_panel = null;
let current_panel_slug = null;
let new_panel = false;
let first_panel = true;
_.each(fields, function(field, field_slug) {
if (field.type === 'group') {
const sub_fields = field.fields;
field = _.first(_.values(sub_fields));
field.desc = '';
field_slug = _.first(_.keys(sub_fields));
} // end if;
const component = wu_get_field_component(field.type, field);
if (! _.isObject(field.required)) {
field.required = {};
} // end if;
let should_display = true;
_.each(field.required, function(value, key) {
// eslint-disable-next-line eqeqeq
should_display = props.attributes[key] == value;
});
if (should_display) {
gt_fields.push(el(component, {
key: field_slug,
label: field.title,
help: field.desc,
value: props.attributes[field_slug],
checked: props.attributes[field_slug],
options: wu_format_options(field.options),
min: field.min,
max: field.max,
onChange(value) {
const obj = {};
obj[field_slug] = value;
props.setAttributes(obj);
},
}));
} // end if;
/*
* Handle header types differently
*/
if (field.type === 'header') {
gt_fields.pop();
if (current_panel !== null) {
new_panel = true;
} // end if;
if (new_panel) {
gt_panels.push(
el(PanelBody, {
key: current_panel_slug,
title: current_panel.title,
description: current_panel.desc,
initialOpen: first_panel,
}, gt_fields)
);
first_panel = false;
} // end if;
current_panel = field;
current_panel_slug = field_slug;
gt_fields = [];
} // end if;
});
gt_panels.push(
el(PanelBody, {
key: current_panel_slug,
title: current_panel.title,
help: current_panel.desc,
initialOpen: first_panel,
}, gt_fields)
);
return el(InspectorControls, { key: 'wp-ultimo' }, gt_panels);
} // end wu_fields_to_block_options;
function wu_format_options(options) {
const formatted_options = [];
_.each(options, function(label, value) {
formatted_options.push({
label,
value,
});
});
return formatted_options;
}
function wu_get_field_component(field_type, field) {
let component = TextControl;
switch (field_type) {
case 'toggle':
component = ToggleControl;
break;
case 'number':
if (field.max && field.min) {
component = RangeControl;
} else {
component = NumberControl;
} // end if;
break;
case 'textarea':
component = TextareaControl;
break;
case 'select':
component = SelectControl;
break;
case 'note':
component = Notice;
break;
default:
component = TextControl;
break;
} // end switch;
return component;
}
/* eslint-disable */
function wu_badge() {
return el('svg', {
width: '116px',
height: '116px',
viewBox: '0 0 116 116',
version: '1.1',
xmlnsXlink: 'http://www.w3.org/1999/xlink',
}, el('g', {
transform: 'translate(24.000000, 0.000000)',
fill: '#000',
stroke: 'none',
strokeWidth: 1,
fillRule: 'evenodd',
}, el('g', {
transform: 'translate(7.555556, 0.000000)',
}, el('polygon', {
points: '19.5185185 51.1370873 53.4139809 1.0658141e-14 30.1083134 54.9623572',
}), el('polygon', {
transform: 'translate(16.947731, 88.302800) scale(-1, -1) translate(-16.947731, -88.302800) ',
points: '-1.55687808e-13 111.958709 33.8954624 60.8216216 10.5897949 115.783979',
}), el('polygon', {
points: '19.5185185 51.4162162 23.300226 60.62179 33.9358783 64.4738951 30.0960764 55.2115998',
})), el('path', {
d: 'M15.401 86.662C6.127 80.616 0 70.177 0 58.314c0-18.7 15.222-33.86 34-33.86 2.012 0 3.984.174 5.9.508l-5.802 9.002c-13.569.154-24.52 11.155-24.52 24.704 0 7.837 3.663 14.821 9.378 19.347l-3.555 8.647zm12.932 5.043l5.26-8.343c.263.008.528.012.793.012 13.701 0 24.808-11.061 24.808-24.706 0-8.207-4.018-15.48-10.203-19.973l3.58-8.748C61.861 35.99 68 46.438 68 58.314c0 18.7-15.222 33.859-34 33.859-1.93 0-3.824-.16-5.667-.468z',
})));
}
/* eslint-enable */
}(
window.wp.blocks,
window.wp.element,
window.wp.components,
window.wu_blocks,
window._
));

View File

@ -0,0 +1 @@
!function(e,t,n,o,i){const l=t.createElement,s=e.registerBlockType,r=wp.serverSideRender,c=wp.components.PanelBody,p=wp.components.TextControl,a=wp.components.__experimentalNumberControl,u=wp.components.RangeControl,d=wp.components.ToggleControl,w=wp.components.TextareaControl,m=wp.components.Notice,k=wp.components.SelectControl,h=wp.blockEditor.InspectorControls;function b(e,t){const n=[];let o=[],s=null,r=null,b=!1,g=!0;return i.each(e,(function(e,h){if("group"===e.type){const t=e.fields;(e=i.first(i.values(t))).desc="",h=i.first(i.keys(t))}const y=function(e,t){let n=p;switch(e){case"toggle":n=d;break;case"number":n=t.max&&t.min?u:a;break;case"textarea":n=w;break;case"select":n=k;break;case"note":n=m;break;default:n=p}return n}(e.type,e);i.isObject(e.required)||(e.required={});let x=!0;i.each(e.required,(function(e,n){x=t.attributes[n]==e})),x&&o.push(l(y,{key:h,label:e.title,help:e.desc,value:t.attributes[h],checked:t.attributes[h],options:f(e.options),min:e.min,max:e.max,onChange(e){const n={};n[h]=e,t.setAttributes(n)}})),"header"===e.type&&(o.pop(),null!==s&&(b=!0),b&&(n.push(l(c,{key:r,title:s.title,description:s.desc,initialOpen:g},o)),g=!1),s=e,r=h,o=[])})),n.push(l(c,{key:r,title:s.title,help:s.desc,initialOpen:g},o)),l(h,{key:"wp-ultimo"},n)}function f(e){const t=[];return i.each(e,(function(e,n){t.push({label:e,value:n})})),t}i.each(o,(function(e,t){s(e.id,{icon:l("svg",{width:"116px",height:"116px",viewBox:"0 0 116 116",version:"1.1",xmlnsXlink:"http://www.w3.org/1999/xlink"},l("g",{transform:"translate(24.000000, 0.000000)",fill:"#000",stroke:"none",strokeWidth:1,fillRule:"evenodd"},l("g",{transform:"translate(7.555556, 0.000000)"},l("polygon",{points:"19.5185185 51.1370873 53.4139809 1.0658141e-14 30.1083134 54.9623572"}),l("polygon",{transform:"translate(16.947731, 88.302800) scale(-1, -1) translate(-16.947731, -88.302800) ",points:"-1.55687808e-13 111.958709 33.8954624 60.8216216 10.5897949 115.783979"}),l("polygon",{points:"19.5185185 51.4162162 23.300226 60.62179 33.9358783 64.4738951 30.0960764 55.2115998"})),l("path",{d:"M15.401 86.662C6.127 80.616 0 70.177 0 58.314c0-18.7 15.222-33.86 34-33.86 2.012 0 3.984.174 5.9.508l-5.802 9.002c-13.569.154-24.52 11.155-24.52 24.704 0 7.837 3.663 14.821 9.378 19.347l-3.555 8.647zm12.932 5.043l5.26-8.343c.263.008.528.012.793.012 13.701 0 24.808-11.061 24.808-24.706 0-8.207-4.018-15.48-10.203-19.973l3.58-8.748C61.861 35.99 68 46.438 68 58.314c0 18.7-15.222 33.859-34 33.859-1.93 0-3.824-.16-5.667-.468z"}))),category:"wp-ultimo",title:e.title,description:e.description,keywords:e.keywords,supports:{multiple:!1,html:!1},edit:n=>[l(r,{key:e.id+t,block:e.id,attributes:n.attributes}),b(e.fields,n)],save:()=>null})}))}(window.wp.blocks,window.wp.element,window.wp.components,window.wu_blocks,window._);

View File

@ -0,0 +1,269 @@
<?php
/**
* Handles Block Editor Widget Support.
*
* @package WP_Ultimo\Builders
* @subpackage Block_Editor
* @since 2.0.0
*/
namespace WP_Ultimo\Builders\Block_Editor;
// Exit if accessed directly
defined('ABSPATH') || exit;
use \WP_Ultimo\Database\Sites\Site_Type;
/**
* Handles Block Editor Widget Support.
*
* @since 2.0.0
*/
class Block_Editor_Widget_Manager {
use \WP_Ultimo\Traits\Singleton;
/**
* Runs when Block_Editor element support is first loaded.
*
* @since 2.0.0
* @return void
*/
public function init() {
if (\WP_Ultimo\Compat\Gutenberg_Support::get_instance()->should_load()) {
add_action('wu_element_loaded', array($this, 'handle_element'));
add_action('init', array($this, 'register_scripts'));
add_action('wu_element_is_preview', array($this, 'is_block_preview'));
} // end if;
} // end init;
/**
* Adds the required scripts.
*
* @since 2.0.0
* @return void
*/
public function register_scripts() {
\WP_Ultimo\Scripts::get_instance()->register_script('wu-blocks', wu_get_asset('blocks.js', 'js', 'inc/builders/block-editor/assets'), array('underscore', 'wp-blocks', 'wp-element', 'wp-components', 'wp-editor', 'wu-functions', 'wp-i18n', 'wp-polyfill'));
$blocks = apply_filters('wu_blocks', array());
wp_localize_script('wu-blocks', 'wu_blocks', $blocks);
} // end register_scripts;
/**
* Checks if we are inside a block preview render.
*
* @since 2.0.0
* @param boolean $is_preview The previous preview status from the filter.
* @return boolean
*/
public function is_block_preview($is_preview) {
if (defined('REST_REQUEST') && true === REST_REQUEST && 'edit' === filter_input(INPUT_GET, 'context', FILTER_SANITIZE_STRING)) {
$is_preview = true;
} // end if;
return $is_preview;
} // end is_block_preview;
/**
* Gets called when a new element is registered
*
* @since 2.0.0
*
* @param \WP_Ultimo\UI\Base_Element $element The element being registered.
* @return void
*/
public function handle_element($element) {
if (wu_get_current_site()->get_type() === Site_Type::CUSTOMER_OWNED) {
return;
} // end if;
$this->register_block($element);
add_filter('wu_blocks', fn($blocks) => $this->load_block_settings($blocks, $element));
} // end handle_element;
/**
* Registers block with WordPress.
*
* @since 2.0.0
*
* @param \WP_Ultimo\UI\Base_Element $element The element being registered.
* @return void
*/
public function register_block($element) {
if (\WP_Block_Type_Registry::get_instance()->is_registered($element->get_id())) {
return;
} // end if;
$attributes = $this->get_attributes_from_fields($element);
register_block_type($element->get_id(), array(
'attributes' => $attributes,
'editor_script' => 'wu-blocks',
'render_callback' => \Closure::fromCallable([$element, 'display']),
));
} // end register_block;
/**
* Consolidate field attributes that are callables for blocks.
*
* @since 2.0.9
*
* @param array $fields The list of fields.
* @return array
*/
protected function consolidate_callables($fields) {
$callable_keys = array(
'options',
'value',
);
$fields_to_ignore = array(
'note',
);
foreach ($fields as $field_slug => &$field) {
/*
* Discard fields that are notes and start with _
*/
if (in_array($field['type'], $fields_to_ignore, true) && strncmp($field_slug, '_', strlen('_')) === 0) {
unset($fields[$field_slug]);
} // end if;
/*
* Deal with the group type.
* On those, we need to loop the sub-fields.
*/
if ($field['type'] === 'group') {
foreach ($field['fields'] as &$sub_field) {
foreach ($sub_field as $sub_item => &$sub_value) {
if (in_array($sub_item, $callable_keys, true) && is_callable($sub_value)) {
$sub_value = call_user_func($sub_value);
} // end if;
} // end foreach;
} // end foreach;
} // end if;
/*
* Deal with the regular field types and its
* callables.
*/
foreach ($field as $item => &$value) {
if (in_array($item, $callable_keys, true) && is_callable($value)) {
$value = call_user_func($value);
} // end if;
} // end foreach;
} // end foreach;
return $fields;
} // end consolidate_callables;
/**
* Registers the block so WP Ultimo can add it on the JS side.
*
* @since 2.0.0
*
* @param array $blocks List of blocks registered.
* @param \WP_Ultimo\UI\Base_Element $element The element being registered.
* @return array
*/
public function load_block_settings($blocks, $element) {
$fields = $this->consolidate_callables($element->fields());
$blocks[] = array(
'id' => $element->get_id(),
'title' => $element->get_title(),
'description' => $element->get_description(),
'fields' => $fields,
'keywords' => $element->keywords(),
);
return $blocks;
} // end load_block_settings;
/**
* Generates the list of attributes supported based on the fields.
*
* @since 2.0.0
* @param \WP_Ultimo\UI\Base_Element $element The element being registered.
* @return array
*/
public function get_attributes_from_fields($element) {
$fields = $element->fields();
$defaults = $element->defaults();
$_fields = array();
foreach ($fields as $field_id => $field) {
$type = 'string';
if ($field['type'] === 'toggle') {
$type = 'boolean';
} // end if;
if ($field['type'] === 'number') {
$type = 'integer';
} // end if;
$default_value = wu_get_isset($defaults, $field_id, '');
$_fields[$field_id] = array(
'default' => wu_get_isset($field, 'value', $default_value),
'type' => $type,
);
} // end foreach;
return $_fields;
} // end get_attributes_from_fields;
} // end class Block_Editor_Widget_Manager;

2995
inc/checkout/class-cart.php Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,750 @@
<?php
/**
* Handles registration pages and such.
*
* @package WP_Ultimo
* @subpackage Checkout
* @since 2.0.0
*/
namespace WP_Ultimo\Checkout;
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Handles registration pages and such.
*
* @since 2.0.0
*/
class Checkout_Pages {
use \WP_Ultimo\Traits\Singleton;
/**
* Initializes the Checkout_Pages singleton and adds hooks.
*
* @since 2.0.0
* @return void
*/
public function init() {
add_filter('display_post_states', array($this, 'add_wp_ultimo_status_annotation'), 10, 2);
add_action('wu_thank_you_site_block', array($this, 'add_verify_email_notice'), 10, 3);
add_shortcode('wu_confirmation', array($this, 'render_confirmation_page'));
add_filter('lostpassword_redirect', array($this, 'filter_lost_password_redirect'));
if (is_main_site()) {
add_action('before_signup_header', array($this, 'redirect_to_registration_page'));
$use_custom_login = wu_get_setting('enable_custom_login_page', false);
if (!$use_custom_login) {
return;
} // end if;
add_filter('login_url', array($this, 'filter_login_url'), 10, 3);
add_filter('lostpassword_url', array($this, 'filter_login_url'), 10, 3);
add_filter('retrieve_password_message', array($this, 'replace_reset_password_link'), 10, 4);
add_filter('network_site_url', array($this, 'maybe_change_wp_login_on_urls'));
add_action('login_init', array($this, 'maybe_obfuscate_login_url'), 9);
add_action('template_redirect', array($this, 'maybe_redirect_to_admin_panel'));
add_action('after_password_reset', array($this, 'maybe_redirect_to_confirm_screen'));
add_action('lost_password', array($this, 'maybe_handle_password_reset_errors'));
add_action('validate_password_reset', array($this, 'maybe_handle_password_reset_errors'));
/**
* Adds the force elements controls.
*/
add_action('post_submitbox_misc_actions', array($this, 'render_compat_mode_setting'));
add_action('save_post', array($this, 'handle_compat_mode_setting'));
} // end if;
} // end init;
/**
* Filters the lost password redirect URL.
*
* @param string $redirect_to The redirect URL.
*/
public function filter_lost_password_redirect(string $redirect_to): string {
if (!empty($redirect_to)) {
return $redirect_to;
} // end if;
$redirect_to = add_query_arg('checkemail', 'confirm', wp_login_url());
return $redirect_to;
} // end filter_lost_password_redirect;
/**
* Renders the compat mode option for pages and posts.
*
* @since 2.0.0
* @return void
*/
public function render_compat_mode_setting() {
$post_id = get_the_ID();
$value = get_post_meta($post_id, '_wu_force_elements_loading', true);
wp_nonce_field('_wu_force_compat_' . $post_id, '_wu_force_compat');
// phpcs:disable
?>
<div class="misc-pub-section misc-pub-section-last" style="margin-top: 12px; margin-bottom: 6px; display: flex; align-items: center;">
<label for="wu-compat-mode">
<span style="display: block; font-weight: 600; margin-bottom: 3px;"><?php _e('WP Ultimo Compatibility Mode', 'wp-ultimo'); ?></span>
<small style="display: block; line-height: 1.8em;"><?php _e('Toggle this option on if WP Ultimo elements are not loading correctly or at all.', 'wp-ultimo'); ?></small>
</label>
<div style="margin-left: 6px;">
<input id="wu-compat-mode" type="checkbox" value="1" <?php checked($value, true, true); ?> name="_wu_force_elements_loading" />
</div>
</div>
<?php
// phpcs:enable
} // end render_compat_mode_setting;
/**
* Handles saving the compat mode switch on posts.
*
* @since 2.0.0
*
* @param int $post_id The id of the post being saved.
* @return void
*/
public function handle_compat_mode_setting($post_id) {
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
return;
} // end if;
if (!isset($_POST['_wu_force_compat']) || !wp_verify_nonce($_POST['_wu_force_compat'], '_wu_force_compat_' . $post_id)) {
return;
} // end if;
if (!current_user_can('edit_post', $post_id)) {
return;
} // end if;
if (isset($_POST['_wu_force_elements_loading'])) {
update_post_meta($post_id, '_wu_force_elements_loading', $_POST['_wu_force_elements_loading']);
} else {
delete_post_meta($post_id, '_wu_force_elements_loading');
} // end if;
} // end handle_compat_mode_setting;
/**
* Replace wp-login.php in email URLs.
*
* @since 2.0.0
*
* @param string $url The URL to filter.
* @return string
*/
public function maybe_change_wp_login_on_urls($url) {
/*
* Only perform computational-heavy tasks if the URL has
* wp-login.php in it to begin with.
*/
if (strpos($url, 'wp-login.php') === false) {
return $url;
} // end if;
$post_id = wu_get_setting('default_login_page', 0);
$post = get_post($post_id);
if ($post) {
$url = str_replace('wp-login.php', $post->post_name, $url);
} // end if;
return $url;
} // end maybe_change_wp_login_on_urls;
/**
* Get an error message.
*
* @since 2.0.0
*
* @param string $error_code The error code.
* @param string $username The username.
* @return string
*/
public function get_error_message($error_code, $username = '') {
$messages = array(
'incorrect_password' => sprintf(__( '<strong>Error:</strong> The password you entered is incorrect.', 'wp-ultimo')),
// From here we are using the same messages as WordPress core.
'expired' => __('Your session has expired. Please log in to continue where you left off.'),
'confirm' => sprintf(__('Check your email for the confirmation link, then visit the <a href="%s">login page</a>.'), wp_login_url()),
'registered' => sprintf(__( 'Registration complete. Please check your email, then visit the <a href="%s">login page</a>.' ), wp_login_url()),
'loggedout' => __('You are now logged out.'),
'registerdisabled' => __('<strong>Error:</strong> User registration is currently not allowed.'),
'empty_username' => __('<strong>Error:</strong> The username field is empty.'),
'empty_password' => __('<strong>Error:</strong> The password field is empty.'),
'invalid_email' => __('Unknown email address. Check again or try your username.'),
'invalid_username' => sprintf(__('<strong>Error:</strong> The username <strong>%s</strong> is not registered on this site. If you are unsure of your username, try your email address instead.'), $username),
'invalidcombo' => __('<strong>Error:</strong> There is no account with that username or email address.'),
'password_reset_empty_space' => __('The password cannot be a space or all spaces.'),
'password_reset_mismatch' => __('<strong>Error:</strong> The passwords do not match.'),
'invalidkey' => __('<strong>Error:</strong> Your password reset link appears to be invalid. Please request a new link below.'),
'expiredkey' => __('<strong>Error:</strong> Your password reset link has expired. Please request a new link below.'),
);
/**
* Filter the error messages.
*
* @since 2.1.1
* @param array $messages The error messages.
* @return array
*/
$messages = apply_filters('wu_checkout_pages_error_messages', $messages);
return wu_get_isset($messages, $error_code, __('Something went wrong', 'wp-ultimo'));
} // end get_error_message;
/**
* Handle password reset errors.
*
* We redirect users to our custom login URL,
* so we can add an error message.
*
* @since 2.0.0
*
* @param \WP_Error $errors The error object.
* @return void
*/
public function maybe_handle_password_reset_errors($errors) {
if ($errors->has_errors()) {
$url = add_query_arg(array(
'action' => wu_request('action', ''),
'user_login' => wu_request('user_login', ''),
'error' => $errors->get_error_code(),
), wp_login_url());
wp_redirect($url);
exit;
} // end if;
} // end maybe_handle_password_reset_errors;
/**
* Maybe redirects users to the confirm screen.
*
* If we are successful in resetting a password,
* we need to prevent the user from reaching the empty
* wp-login.php message, so we redirect them to the passed
* redirect_to query argument.
*
* @since 2.0.0
* @return void
*/
public function maybe_redirect_to_confirm_screen() {
if (wu_request('redirect_to')) {
wp_redirect(wu_request('redirect_to'));
exit;
} // end if;
} // end maybe_redirect_to_confirm_screen;
/**
* Replace the reset password link, if necessary.
*
* @since 2.0.0
*
* @param string $message The email message.
* @param string $key The reset key.
* @param string $user_login The user login.
* @param array $user_data The user data array.
* @return string
*/
public function replace_reset_password_link($message, $key, $user_login, $user_data) {
if (!is_main_site()) {
return $message;
} // end if;
$results = array();
preg_match_all('/.*\/wp-login\.php.*/', $message, $results);
$switched_locale = false;
if (isset($results[0][0])) {
// Localize password reset message content for user.
$locale = get_user_locale($user_data);
$switched_locale = switch_to_locale($locale);
$new_url = add_query_arg(array(
'action' => 'rp',
'key' => $key,
'login' => rawurlencode($user_login),
'wp_lang' => $locale
), wp_login_url());
$new_url = set_url_scheme($new_url, null);
$message = str_replace($results[0], $new_url, $message);
} // end if;
if ($switched_locale) {
restore_previous_locale();
} // end if;
return $message;
} // end replace_reset_password_link;
/**
* Redirect logged users when they reach the login page.
*
* @since 2.0.0
* @return void
*/
public function maybe_redirect_to_admin_panel() {
global $post;
if (!is_user_logged_in()) {
return;
} // end if;
$custom_login_page = $this->get_signup_page('login');
if (empty($custom_login_page) || empty($post)) {
return;
} // end if;
if ($custom_login_page->ID !== $post->ID) {
return;
} // end if;
/**
* Create an exclusion list of parameters that prevent the auto-redirect.
*
* This is needed because otherwise page builder won't be able to
* edit the login page once it is defined.
*
* @since 2.0.4
* @return array
*/
$exclusion_list = apply_filters('wu_maybe_redirect_to_admin_panel_exclusion_list', array(
'preview', // WordPress Preview
'ct_builder', // Oxygen Builder
'fl_builder', // Beaver Builder
'elementor-preview', // Elementor
'brizy-edit', // Brizy
'brizy-edit-iframe', // Brizy
), $custom_login_page, $post, $this);
foreach ($exclusion_list as $exclusion_param) {
if (wu_request($exclusion_param, null) !== null) {
return;
} // end if;
} // end foreach;
$user = wp_get_current_user();
$active_blog = get_active_blog_for_user($user->ID);
$redirect_to = $active_blog ? get_admin_url($active_blog->blog_id) : false;
if (isset($_GET['redirect_to'])) {
$redirect_to = $_GET['redirect_to'];
} elseif (is_multisite() && !get_active_blog_for_user($user->ID) && !is_super_admin($user->ID)) {
$redirect_to = user_admin_url();
} elseif (is_multisite() && !$user->has_cap('read')) {
$redirect_to = get_dashboard_url($user->ID);
} elseif (!$user->has_cap('edit_posts')) {
$redirect_to = $user->has_cap('read') ? admin_url('profile.php') : home_url();
} // end if;
if (!$redirect_to) {
return;
} // end if;
wp_redirect($redirect_to);
exit;
} // end maybe_redirect_to_admin_panel;
/**
* Adds the unverified email account error message.
*
* @since 2.0.0
*
* @param \WP_Ultimo\Models\Payment $payment The current payment.
* @param \WP_Ultimo\Models\Membership $membership the current membership.
* @param \WP_Ultimo\Models\Customer $customer the current customer.
* @return void
*/
public function add_verify_email_notice($payment, $membership, $customer) {
if ($payment->get_total() == 0 && $customer->get_email_verification() === 'pending') {
$html = '<div class="wu-p-4 wu-bg-yellow-200 wu-mb-2 wu-text-yellow-700 wu-rounded">%s</div>';
$message = __('Your email address is not yet verified. Your site <strong>will only be activated</strong> after your email address is verified. Check your inbox and verify your email address.', 'wp-ultimo');
$message .= sprintf('<br><a href="#" class="wu-resend-verification-email wu-text-gray-700">%s</a>', __('Resend verification email &rarr;', 'wp-ultimo'));
printf($html, $message);
} // end if;
} // end add_verify_email_notice;
/**
* Check if we should obfuscate the login URL.
*
* @since 2.0.0
* @return void
*/
public function maybe_obfuscate_login_url() {
$use_custom_login = wu_get_setting('enable_custom_login_page', false);
if (!$use_custom_login) {
return;
} // end if;
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
return;
} // end if;
if (wu_request('interim-login')) {
return;
} // end if;
if (wu_request('action') === 'logout') {
return;
} // end if;
$new_login_url = $this->get_page_url('login');
if (!$new_login_url) {
return;
} // end if;
$should_obfuscate = wu_get_setting('obfuscate_original_login_url', 1);
$bypass_obfuscation = wu_request('wu_bypass_obfuscation');
if ($should_obfuscate && !$bypass_obfuscation) {
status_header(404);
nocache_headers();
global $wp_query;
$wp_query->set_404();
include(get_404_template());
die;
} else {
wp_redirect($new_login_url);
exit;
} // end if;
} // end maybe_obfuscate_login_url;
/**
* Redirects the customers to the registration page, when one is used.
*
* @since 2.0.0
* @return void
*/
public function redirect_to_registration_page() {
$registration_url = $this->get_page_url('register');
if ($registration_url) {
wp_redirect($registration_url);
exit;
} // end if;
} // end redirect_to_registration_page;
/**
* Filters the login URL if necessary.
*
* @since 2.0.0
*
* @param string $login_url Original login URL.
* @param string $redirect URL to redirect to after login.
* @param bool $force_reauth If we need to force reauth.
* @return string
*/
public function filter_login_url($login_url, $redirect, $force_reauth = false) {
/**
* Fix incompatibility with UIPress, making sure we only filter after wp_loaded ran.
*/
if (!did_action('wp_loaded')) {
return $login_url;
} // end if;
$function_caller = wu_get_function_caller(5);
if ($function_caller === 'wp_auth_check_html') {
return $login_url;
} // end if;
$params = array();
$old_url_params = wp_parse_url($login_url, PHP_URL_QUERY);
wp_parse_str($old_url_params, $params);
$new_login_url = $this->get_page_url('login');
if (!$new_login_url) {
return $login_url;
} // end if;
if ($params) {
$new_login_url = add_query_arg($params, $new_login_url);
} // end if;
if ($redirect) {
$new_login_url = add_query_arg('redirect_to', urlencode( $redirect ), $new_login_url);
} // end if;
if ($force_reauth) {
$new_login_url = add_query_arg('reauth', 1, $new_login_url);
} // end if;
return $new_login_url;
} // end filter_login_url;
/**
* Returns the ID of the pages being used for each WP Ultimo purpose.
*
* @since 2.0.0
* @return array
*/
public function get_signup_pages() {
return array(
'register' => wu_guess_registration_page(),
'update' => wu_get_setting('default_update_page', false),
'login' => wu_get_setting('default_login_page', false),
'block_frontend' => wu_get_setting('default_block_frontend_page', false),
'new_site' => wu_get_setting('default_new_site_page', false),
);
} // end get_signup_pages;
/**
* Returns the WP_Post object for one of the pages.
*
* @since 2.0.0
*
* @param string $page The slug of the page to retrieve.
* @return \WP_Post|false
*/
public function get_signup_page($page) {
$pages = $this->get_signup_pages();
$page_id = wu_get_isset($pages, $page);
if (!$page_id) {
return false;
} // end if;
return get_blog_post(wu_get_main_site_id(), $page_id);
} // end get_signup_page;
/**
* Returns the URL for a particular page type.
*
* @since 2.0.0
*
* @param string $page_slug The signup page to get.
* @return string|false
*/
public function get_page_url($page_slug = 'login') {
$page = $this->get_signup_page($page_slug);
if (!$page) {
return false;
} // end if;
return wu_switch_blog_and_run(fn() => get_the_permalink($page));
} // end get_page_url;
/**
* Tags the WP Ultimo pages on the main site.
*
* @since 2.0.0
*
* @param array $states The previous states of that page.
* @param \WP_Post $post The current post.
* @return array
*/
public function add_wp_ultimo_status_annotation($states, $post) {
if (!is_main_site()) {
return $states;
} // end if;
$labels = array(
'register' => __('WP Ultimo - Register Page', 'wp-ultimo'),
'login' => __('WP Ultimo - Login Page', 'wp-ultimo'),
'block_frontend' => __('WP Ultimo - Site Blocked Page', 'wp-ultimo'),
'update' => __('WP Ultimo - Membership Update Page', 'wp-ultimo'),
'new_site' => __('WP Ultimo - New Site Page', 'wp-ultimo'),
);
$pages = array_map('absint', $this->get_signup_pages());
if (in_array($post->ID, $pages, true)) {
$key = array_search($post->ID, $pages, true);
$states['wp_ultimo_page'] = wu_get_isset($labels, $key);
} // end if;
return $states;
} // end add_wp_ultimo_status_annotation;
/**
* Renders the confirmation page.
*
* @since 2.0.0
*
* @param array $atts Shortcode attributes.
* @param null|string $content The post content.
* @return string
*/
public function render_confirmation_page($atts, $content = null) {
return wu_get_template_contents('checkout/confirmation', array(
'errors' => Checkout::get_instance()->errors,
'membership' => wu_get_membership_by_hash(wu_request('membership')),
));
} // end render_confirmation_page;
} // end class Checkout_Pages;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,614 @@
<?php
/**
* Creates a cart with the parameters of the purchase being placed.
*
* @package WP_Ultimo
* @subpackage Order
* @since 2.0.0
*/
namespace WP_Ultimo\Checkout\Signup_Fields;
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Creates an cart with the parameters of the purchase being placed.
*
* @package WP_Ultimo
* @subpackage Checkout
* @since 2.0.0
*/
abstract class Base_Signup_Field {
/**
* Holds the field attributes.
*
* @since 2.0.0
* @var array
*/
protected $attributes;
/**
* Returns the type of the field.
*
* @since 2.0.0
* @return string
*/
abstract public function get_type();
/**
* Returns if this field should be present on the checkout flow or not.
*
* @since 2.0.0
* @return boolean
*/
abstract public function is_required();
/**
* Requires the title of the field/element type.
*
* This is used on the Field/Element selection screen.
*
* @since 2.0.0
* @return string
*/
abstract public function get_title();
/**
* Returns the description of the field/element.
*
* This is used as the title attribute of the selector.
*
* @since 2.0.0
* @return string
*/
abstract public function get_description();
/**
* Returns the tooltip of the field/element.
*
* This is used as the tooltip attribute of the selector.
*
* @since 2.0.0
* @return string
*/
abstract function get_tooltip();
/**
* Returns the icon to be used on the selector.
*
* Can be either a dashicon class or a wu-dashicon class.
*
* @since 2.0.0
* @return string
*/
abstract public function get_icon();
/**
* Returns the list of additional fields specific to this type.
*
* @since 2.0.0
* @return array
*/
abstract public function get_fields();
/**
* Returns the field/element actual field array to be used on the checkout form.
*
* @since 2.0.0
*
* @param array $attributes Attributes saved on the editor form.
* @return array An array of fields, not the field itself.
*/
abstract public function to_fields_array($attributes);
/**
* Set's if a field should not be available on the form creation.
*
* @since 2.0.0
* @return boolean
*/
public function is_hidden() {
return false;
} // end is_hidden;
/**
* Defines if this field/element is related to site creation or not.
*
* @since 2.0.0
* @return boolean
*/
public function is_site_field() {
return false;
} // end is_site_field;
/**
* Defines if this field/element is related to user/customer creation or not.
*
* @since 2.0.0
* @return boolean
*/
public function is_user_field() {
return false;
} // end is_user_field;
/**
* Returns the field as an array that the form builder can understand.
*
* @since 2.0.0
* @return array
*/
public function get_field_as_type_option() {
return array(
'title' => $this->get_title(),
'desc' => $this->get_description(),
'tooltip' => $this->get_tooltip(),
'type' => $this->get_type(),
'icon' => $this->get_icon(),
'required' => $this->is_required(),
'default_fields' => $this->default_fields(),
'force_attributes' => $this->force_attributes(),
'all_attributes' => $this->get_all_attributes(),
'fields' => array($this, 'get_editor_fields'),
);
} // end get_field_as_type_option;
/**
* Modifies the HTML attr array before sending it over to the form.
*
* @since 2.0.0
*
* @param array $html_attr The current attributes.
* @param string $field_name Field name.
* @return array
*/
public function get_editor_fields_html_attr($html_attr, $field_name) {
return $html_attr;
} // end get_editor_fields_html_attr;
/**
* Get the tabs available for this field.
*
* @since 2.0.0
* @return array
*/
public function get_tabs() {
return array(
'content',
'style',
);
} // end get_tabs;
/**
* Gets the pre-filled value for the field.
*
* @since 2.0.0
* @return mixed
*/
public function get_value() {
$value = wu_get_isset($this->attributes, 'default_value', '');
$session = wu_get_session('signup');
$value_session = wu_get_isset($session->get('signup'), $this->attributes['id']);
if ($value_session) {
$value = $value_session;
} // end if;
if (wu_get_isset($this->attributes, 'from_request') && wu_get_isset($this->attributes, 'id')) {
$value = wu_request($this->attributes['id'], '');
} // end if;
return $value;
} // end get_value;
/**
* Calculate the style attributes for the field.
*
* @since 2.0.4
* @return string
*/
public function calculate_style_attr() {
$styles = array();
$width = (int) wu_get_isset($this->attributes, 'width');
if ($width) {
if ($width !== 100) {
$styles[] = 'float: left';
$styles[] = sprintf('width: %s%%', $width);
} // end if;
} else {
$styles[] = 'clear: both';
} // end if;
return implode('; ', $styles);
} // end calculate_style_attr;
/**
* Sets the config values for the current field.
*
* @since 2.0.0
*
* @param array $attributes Array containing settings for the field.
* @return void
*/
public function set_attributes($attributes) {
$this->attributes = $attributes;
} // end set_attributes;
/**
* If you want to force a particular attribute to a value, declare it here.
*
* @since 2.0.0
* @return array
*/
public function force_attributes() {
return array();
} // end force_attributes;
/**
* Default values for the editor fields.
*
* @since 2.0.0
* @return array
*/
public function defaults() {
return array();
} // end defaults;
/**
* List of keys of the default fields we want to display on the builder.
*
* @since 2.0.0
* @return array
*/
public function default_fields() {
return array(
'id',
'name',
'placeholder',
'tooltip',
'default',
'required',
);
} // end default_fields;
/**
* Returns the editor fields.
*
* @since 2.0.0
*
* @param array $attributes The list of attributes of the field.
* @return array
*/
public function get_editor_fields($attributes = array()) {
$final_field_list = $this->get_fields();
/*
* Checks if this is a site field
*/
if ($this->is_site_field()) {
$final_field_list['_site_notice_field_' . uniqid()] = array(
'type' => 'note',
'classes' => 'wu--mt-px',
'desc' => sprintf('<div class="wu-p-4 wu--m-4 wu-bg-blue-100 wu-text-blue-600 wu-border-t wu-border-l-0 wu-border-r-0 wu-border-b-0 wu-border-gray-300 wu-border-solid">%s</div>', __('This is a site-related field. For that reason, this field will not show up when no plans are present on the shopping cart.', 'wp-ultimo')),
'order' => 98.5,
);
} // end if;
/*
* Checks if this is a user field
*/
if ($this->is_user_field()) {
$final_field_list['_user_notice_field_' . uniqid()] = array(
'type' => 'note',
'classes' => 'wu--mt-px',
'desc' => sprintf('<div class="wu-p-4 wu--m-4 wu-bg-blue-100 wu-text-blue-600 wu-border-t wu-border-l-0 wu-border-r-0 wu-border-b-0 wu-border-gray-300 wu-border-solid">%s</div>', __('This is a customer-related field. For that reason, this field will not show up when the user is logged and already has a customer on file.', 'wp-ultimo')),
'order' => 98.5,
);
} // end if;
foreach ($final_field_list as $key => &$field) {
$field['html_attr'] = wu_get_isset($field, 'html_attr', array());
$value = wu_get_isset($attributes, $key, null);
$field['default'] = wu_get_isset($this->defaults(), $key, '');
if ($value === null) {
$value = $field['default'];
} // end if;
if (wu_get_isset($field['html_attr'], 'data-model')) {
$model_name = wu_get_isset($field['html_attr'], 'data-model', 'product');
$models = explode(',', (string) $value);
$func_name = "wu_get_{$model_name}";
if (function_exists($func_name)) {
$selected = array_map(function($id) use ($func_name) {
$model = call_user_func($func_name, absint($id));
if (!$model) {
return false;
} // end if;
return $model->to_search_results();
}, $models);
$selected = array_filter($selected);
$field['html_attr']['data-selected'] = json_encode($selected);
} // end if;
} // end if;
if (!is_null($value)) {
$field['value'] = $value;
} // end if;
$field['html_attr'] = $this->get_editor_fields_html_attr($field['html_attr'], $field['type']);
/**
* Default v-show
*/
$show_reqs = false;
if (isset($field['wrapper_html_attr'])) {
$show_reqs = wu_get_isset($field['wrapper_html_attr'], 'v-show');
} // end if;
$tab = wu_get_isset($field, 'tab', 'content');
$field['wrapper_html_attr'] = array_merge(wu_get_isset($field, 'wrapper_html_attr', array()), array(
'v-cloak' => 1,
'v-show' => sprintf('require("type", "%s") && require("tab", "%s")', $this->get_type(), $tab) . ($show_reqs ? " && $show_reqs" : ''),
));
} // end foreach;
return $final_field_list;
} // end get_editor_fields;
/**
* Returns a list of all the attributes.
*
* @since 2.0.0
* @return array
*/
public function get_all_attributes() {
$styles = array(
'wrapper_element_classes',
'element_classes',
'element_id',
'from_request',
'width',
'logged',
);
$field_keys = array_keys($this->get_fields());
return array_merge($this->default_fields(), $field_keys, $styles);
} // end get_all_attributes;
/**
* Treat the attributes array to avoid reaching the input var limits.
*
* @since 2.0.0
*
* @param array $attributes The attributes.
* @return array
*/
public function reduce_attributes($attributes) {
return $attributes;
} // end reduce_attributes;
/**
* List of all the default fields available.
*
* @since 2.0.0
* @return array
*/
public static function fields_list() {
$fields = array();
$fields['id'] = array(
'type' => 'text',
'title' => __('Field ID', 'wp-ultimo'),
'placeholder' => __('e.g. info-name', 'wp-ultimo'),
'tooltip' => __('Only alpha-numeric and hyphens allowed.', 'wp-ultimo'),
'desc' => __('The ID of the field. This is used to reference the field.', 'wp-ultimo'),
'value' => wu_request('id', ''),
'html_attr' => array(
'v-on:input' => 'id = $event.target.value.toLowerCase().replace(/[^a-z0-9-_]+/g, "")',
'v-bind:value' => 'id',
),
);
$fields['name'] = array(
'type' => 'text',
'title' => __('Field Label', 'wp-ultimo'),
'placeholder' => __('e.g. Your Name', 'wp-ultimo'),
'desc' => __('This is what your customer see as the field title.', 'wp-ultimo'),
'tooltip' => __('Leave blank to hide the field label. You can also set a placeholder value and tip in the "Additional Settings" tab.', 'wp-ultimo'),
'value' => '',
'html_attr' => array(
'v-model' => 'name',
),
);
$fields['placeholder'] = array(
'type' => 'text',
'title' => __('Field Placeholder', 'wp-ultimo'),
'placeholder' => __('e.g. Placeholder value', 'wp-ultimo'),
'desc' => __('This value appears inside the field, as an example of how to fill it.', 'wp-ultimo'),
'tooltip' => '',
'value' => '',
'tab' => 'advanced',
'html_attr' => array(
'v-model' => 'placeholder',
),
);
$fields['tooltip'] = array(
'type' => 'textarea',
'title' => __('Field Tooltip', 'wp-ultimo'),
'placeholder' => __('e.g. This field is great, be sure to fill it.', 'wp-ultimo'),
// translators: %is is the icon for a question mark.
'desc' => sprintf(__('Any text entered here will be shown when the customer hovers the %s icon next to the field label.', 'wp-ultimo'), wu_tooltip(__('Just like this!', 'wp-ultimo'))),
'tooltip' => '',
'value' => '',
'tab' => 'advanced',
'html_attr' => array(
'v-model' => 'tooltip',
'rows' => 4,
),
);
$fields['default_value'] = array(
'type' => 'text',
'title' => __('Default Value', 'wp-ultimo'),
'placeholder' => __('e.g. None', 'wp-ultimo'),
'value' => '',
'html_attr' => array(
'v-model' => 'default_value',
),
);
$fields['note'] = array(
'type' => 'textarea',
'title' => __('Content', 'wp-ultimo'),
'placeholder' => '',
'tooltip' => '',
'value' => '',
'html_attr' => array(
'v-model' => 'content',
),
);
$fields['limits'] = array(
'type' => 'group',
'title' => __('Field Length', 'wp-ultimo'),
'tooltip' => '',
'fields' => array(
'min' => array(
'type' => 'number',
'value' => '',
'placeholder' => __('Min', 'wp-ultimo'),
'wrapper_classes' => 'wu-w-1/2',
'html_attr' => array(
'v-model' => 'min',
),
),
'max' => array(
'type' => 'number',
'value' => '',
'placeholder' => __('Max', 'wp-ultimo'),
'wrapper_classes' => 'wu-ml-2 wu-w-1/2',
'html_attr' => array(
'v-model' => 'max',
),
),
),
);
$fields['save_as'] = array(
'type' => 'select',
'title' => __('Save As', 'wp-ultimo'),
'desc' => __('Select how you want to save this piece of meta data. You can attach it to the customer or the site as site meta or as site option.', 'wp-ultimo'),
'placeholder' => '',
'tooltip' => '',
'value' => 'customer_meta',
'order' => 99.5,
'options' => array(
'customer_meta' => __('Customer Meta', 'wp-ultimo'),
'user_meta' => __('User Meta', 'wp-ultimo'),
'site_meta' => __('Site Meta', 'wp-ultimo'),
'site_option' => __('Site Option', 'wp-ultimo'),
'nothing' => __('Do not save', 'wp-ultimo'),
),
'html_attr' => array(
'v-model' => 'save_as',
),
);
$fields['required'] = array(
'type' => 'toggle',
'title' => __('Required', 'wp-ultimo'),
'desc' => __('Mark this field as required. The checkout will not proceed unless this field is filled.', 'wp-ultimo'),
'value' => 0,
'order' => 98,
'html_attr' => array(
'v-model' => 'required',
),
);
return $fields;
} // end fields_list;
} // end class Base_Signup_Field;

View File

@ -0,0 +1,303 @@
<?php
/**
* Creates a cart with the parameters of the purchase being placed.
*
* @package WP_Ultimo
* @subpackage Order
* @since 2.0.0
*/
namespace WP_Ultimo\Checkout\Signup_Fields;
use \WP_Ultimo\Checkout\Signup_Fields\Base_Signup_Field;
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Creates an cart with the parameters of the purchase being placed.
*
* @package WP_Ultimo
* @subpackage Checkout
* @since 2.0.0
*/
class Signup_Field_Billing_Address extends Base_Signup_Field {
/**
* Returns the type of the field.
*
* @since 2.0.0
* @return string
*/
public function get_type() {
return 'billing_address';
} // end get_type;
/**
* Returns if this field should be present on the checkout flow or not.
*
* @since 2.0.0
* @return boolean
*/
public function is_required() {
return false;
} // end is_required;
/**
* Is this a user-related field?
*
* If this is set to true, this field will be hidden
* when the user is already logged in.
*
* @since 2.0.0
* @return boolean
*/
public function is_user_field() {
return true;
} // end is_user_field;
/**
* Requires the title of the field/element type.
*
* This is used on the Field/Element selection screen.
*
* @since 2.0.0
* @return string
*/
public function get_title() {
return __('Address', 'wp-ultimo');
} // end get_title;
/**
* Returns the description of the field/element.
*
* This is used as the title attribute of the selector.
*
* @since 2.0.0
* @return string
*/
public function get_description() {
return __('Adds billing address fields such as country, zip code.', 'wp-ultimo');
} // end get_description;
/**
* Returns the tooltip of the field/element.
*
* This is used as the tooltip attribute of the selector.
*
* @since 2.0.0
* @return string
*/
public function get_tooltip() {
return __('Adds billing address fields such as country, zip code.', 'wp-ultimo');
} // end get_tooltip;
/**
* Returns the icon to be used on the selector.
*
* Can be either a dashicon class or a wu-dashicon class.
*
* @since 2.0.0
* @return string
*/
public function get_icon() {
return 'dashicons-wu-map1';
} // end get_icon;
/**
* Returns the default values for the field-elements.
*
* This is passed through a wp_parse_args before we send the values
* to the method that returns the actual fields for the checkout form.
*
* @since 2.0.0
* @return array
*/
public function defaults() {
return array(
'zip_and_country' => true,
);
} // end defaults;
/**
* List of keys of the default fields we want to display on the builder.
*
* @since 2.0.0
* @return array
*/
public function default_fields() {
return array(
'name',
);
} // end default_fields;
/**
* If you want to force a particular attribute to a value, declare it here.
*
* @since 2.0.0
* @return array
*/
public function force_attributes() {
return array(
'id' => 'billing_address',
'required' => true,
);
} // end force_attributes;
/**
* Returns the list of additional fields specific to this type.
*
* @since 2.0.0
* @return array
*/
public function get_fields() {
return array(
'zip_and_country' => array(
'type' => 'toggle',
'title' => __('Display only ZIP and Country?', 'wp-ultimo'),
'desc' => __('Checking this option will only add the ZIP and country fields, instead of all the normal billing address fields.', 'wp-ultimo'),
'value' => true,
),
);
} // end get_fields;
/**
* Build a filed alternative.
*
* @since 2.0.11
*
* @param array $base_field The base field.
* @param string $data_key_name The data key name.
* @param string $label_key_field The field label name.
* @return array
*/
public function build_select_alternative(&$base_field, $data_key_name, $label_key_field) {
$base_field['wrapper_html_attr']['v-if'] = "!{$data_key_name}.length";
$field = $base_field;
$option_template = sprintf('<option v-for="item in %s" :value="item.code">
{{ item.name }}
</option>', $data_key_name);
$field['type'] = 'select';
$field['options_template'] = $option_template;
$field['options'] = array();
$field['required'] = true;
$field['wrapper_html_attr']['v-if'] = "{$data_key_name}.length";
$field['html_attr']['required'] = 'required';
$field['html_attr']['required'] = 'required';
$field['html_attr']['v-bind:name'] = "'billing_" . str_replace('_list', '', $data_key_name) . "'";
$field['title'] = sprintf('<span v-html="%s">%s</span>', "labels.$label_key_field", $field['title']);
return $field;
} // end build_select_alternative;
/**
* Returns the field/element actual field array to be used on the checkout form.
*
* @since 2.0.0
*
* @param array $attributes Attributes saved on the editor form.
* @return array An array of fields, not the field itself.
*/
public function to_fields_array($attributes) {
$zip_only = wu_string_to_bool($attributes['zip_and_country']);
$customer = wu_get_current_customer();
/*
* Checks for an existing customer
*/
if ($customer) {
$fields = $customer->get_billing_address()->get_fields($zip_only);
} else {
$checkout_form = \WP_Ultimo\Checkout\Checkout::get_instance()->checkout_form;
$fields = \WP_Ultimo\Objects\Billing_Address::fields($zip_only, $checkout_form);
} // end if;
if (isset($fields['billing_country'])) {
$fields['billing_country']['html_attr'] = array(
'v-model' => 'country',
);
} // end if;
if (!$zip_only) {
if (isset($fields['billing_state'])) {
$fields['billing_state']['html_attr'] = array(
'v-model.lazy' => 'state',
);
/**
* Format the state field accordingly.
*
* @since 2.0.11
*/
$fields['billing_state_select'] = $this->build_select_alternative($fields['billing_state'], 'state_list', 'state_field');
} // end if;
if (isset($fields['billing_city'])) {
$fields['billing_city']['html_attr'] = array(
'v-model.lazy' => 'city',
);
/**
* Format the city field accordingly.
*
* @since 2.0.11
*/
$fields['billing_city_select'] = $this->build_select_alternative($fields['billing_city'], 'city_list', 'city_field');
} // end if;
} // end if;
foreach ($fields as &$field) {
$field['wrapper_classes'] = trim(wu_get_isset($field, 'wrapper_classes', '') . ' ' . $attributes['element_classes']);
} // end foreach;
uasort($fields, 'wu_sort_by_order');
return $fields;
} // end to_fields_array;
} // end class Signup_Field_Billing_Address;

View File

@ -0,0 +1,227 @@
<?php
/**
* Creates a cart with the parameters of the purchase being placed.
*
* @package WP_Ultimo
* @subpackage Order
* @since 2.0.0
*/
namespace WP_Ultimo\Checkout\Signup_Fields;
use \WP_Ultimo\Checkout\Signup_Fields\Base_Signup_Field;
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Creates an cart with the parameters of the purchase being placed.
*
* @package WP_Ultimo
* @subpackage Checkout
* @since 2.0.0
*/
class Signup_Field_Checkbox extends Base_Signup_Field {
/**
* Returns the type of the field.
*
* @since 2.0.0
* @return string
*/
public function get_type() {
return 'checkbox';
} // end get_type;
/**
* Returns if this field should be present on the checkout flow or not.
*
* @since 2.0.0
* @return boolean
*/
public function is_required() {
return false;
} // end is_required;
/**
* Is this a user-related field?
*
* If this is set to true, this field will be hidden
* when the user is already logged in.
*
* @since 2.0.0
* @return boolean
*/
public function is_user_field() {
return false;
} // end is_user_field;
/**
* Requires the title of the field/element type.
*
* This is used on the Field/Element selection screen.
*
* @since 2.0.0
* @return string
*/
public function get_title() {
return __('Checkbox', 'wp-ultimo');
} // end get_title;
/**
* Returns the description of the field/element.
*
* This is used as the title attribute of the selector.
*
* @since 2.0.0
* @return string
*/
public function get_description() {
return __('Adds a checkout box that can be checked by the customer.', 'wp-ultimo');
} // end get_description;
/**
* Returns the tooltip of the field/element.
*
* This is used as the tooltip attribute of the selector.
*
* @since 2.0.0
* @return string
*/
public function get_tooltip() {
return __('Adds a checkout box that can be checked by the customer.', 'wp-ultimo');
} // end get_tooltip;
/**
* Returns the icon to be used on the selector.
*
* Can be either a dashicon class or a wu-dashicon class.
*
* @since 2.0.0
* @return string
*/
public function get_icon() {
return 'dashicons-wu-check-square';
} // end get_icon;
/**
* Returns the default values for the field-elements.
*
* This is passed through a wp_parse_args before we send the values
* to the method that returns the actual fields for the checkout form.
*
* @since 2.0.0
* @return array
*/
public function defaults() {
return array(
''
);
} // end defaults;
/**
* List of keys of the default fields we want to display on the builder.
*
* @since 2.0.0
* @return array
*/
public function default_fields() {
return array(
'id',
'name',
'tooltip',
'save_as',
'required',
);
} // end default_fields;
/**
* If you want to force a particular attribute to a value, declare it here.
*
* @since 2.0.0
* @return array
*/
public function force_attributes() {
return array();
} // end force_attributes;
/**
* Returns the list of additional fields specific to this type.
*
* @since 2.0.0
* @return array
*/
public function get_fields() {
return array(
'default_state' => array(
'type' => 'toggle',
'title' => __('Default State', 'wp-ultimo'),
'desc' => __('Use the toggle to the set the default state of the checkbox.', 'wp-ultimo'),
'value' => 0,
'order' => 12,
),
);
} // end get_fields;
/**
* Returns the field/element actual field array to be used on the checkout form.
*
* @since 2.0.0
*
* @param array $attributes Attributes saved on the editor form.
* @return array An array of fields, not the field itself.
*/
public function to_fields_array($attributes) {
$checkout_fields = array();
$checkout_fields[$attributes['id']] = array(
'type' => 'checkbox',
'id' => $attributes['id'],
'name' => $attributes['name'],
'tooltip' => $attributes['tooltip'],
'required' => $attributes['required'],
'wrapper_classes' => $attributes['element_classes'],
);
if ($attributes['default_state']) {
$checkout_fields[$attributes['id']]['html_attr']['checked'] = 'checked';
} // end if;
$value = $this->get_value();
if ($value !== '' && (bool) $value === true) {
$checkout_fields[$attributes['id']]['html_attr']['checked'] = 'checked';
} // end if;
return $checkout_fields;
} // end to_fields_array;
} // end class Signup_Field_Checkbox;

View File

@ -0,0 +1,203 @@
<?php
/**
* Creates a cart with the parameters of the purchase being placed.
*
* @package WP_Ultimo
* @subpackage Order
* @since 2.0.0
*/
namespace WP_Ultimo\Checkout\Signup_Fields;
use \WP_Ultimo\Checkout\Signup_Fields\Base_Signup_Field;
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Creates an cart with the parameters of the purchase being placed.
*
* @package WP_Ultimo
* @subpackage Checkout
* @since 2.0.0
*/
class Signup_Field_Color extends Base_Signup_Field {
/**
* Returns the type of the field.
*
* @since 2.0.0
* @return string
*/
public function get_type() {
return 'color_picker';
} // end get_type;
/**
* Returns if this field should be present on the checkout flow or not.
*
* @since 2.0.0
* @return boolean
*/
public function is_required() {
return false;
} // end is_required;
/**
* Requires the title of the field/element type.
*
* This is used on the Field/Element selection screen.
*
* @since 2.0.0
* @return string
*/
public function get_title() {
return __('Color', 'wp-ultimo');
} // end get_title;
/**
* Returns the description of the field/element.
*
* This is used as the title attribute of the selector.
*
* @since 2.0.0
* @return string
*/
public function get_description() {
return __('Adds a color picker field.', 'wp-ultimo');
} // end get_description;
/**
* Returns the tooltip of the field/element.
*
* This is used as the tooltip attribute of the selector.
*
* @since 2.0.0
* @return string
*/
public function get_tooltip() {
return __('Adds a color picker field.', 'wp-ultimo');
} // end get_tooltip;
/**
* Returns the icon to be used on the selector.
*
* Can be either a dashicon class or a wu-dashicon class.
*
* @since 2.0.0
* @return string
*/
public function get_icon() {
return 'dashicons-wu-droplet';
} // end get_icon;
/**
* Returns the default values for the field-elements.
*
* This is passed through a wp_parse_args before we send the values
* to the method that returns the actual fields for the checkout form.
*
* @since 2.0.0
* @return array
*/
public function defaults() {
return array(
''
);
} // end defaults;
/**
* List of keys of the default fields we want to display on the builder.
*
* @since 2.0.0
* @return array
*/
public function default_fields() {
return array(
'id',
'name',
'placeholder',
'tooltip',
'required',
'save_as',
);
} // end default_fields;
/**
* If you want to force a particular attribute to a value, declare it here.
*
* @since 2.0.0
* @return array
*/
public function force_attributes() {
return array();
} // end force_attributes;
/**
* Returns the list of additional fields specific to this type.
*
* @since 2.0.0
* @return array
*/
public function get_fields() {
return array(
'default_value' => array(
'type' => 'color-picker',
'order' => 12,
'title' => __('Default Color', 'wp-ultimo'),
'desc' => __('Set the default value for this color field.', 'wp-ultimo'),
),
);
} // end get_fields;
/**
* Returns the field/element actual field array to be used on the checkout form.
*
* @since 2.0.0
*
* @param array $attributes Attributes saved on the editor form.
* @return array An array of fields, not the field itself.
*/
public function to_fields_array($attributes) {
return array(
$attributes['id'] => array(
'type' => 'color',
'id' => $attributes['id'],
'name' => $attributes['name'],
'placeholder' => $attributes['placeholder'],
'tooltip' => $attributes['tooltip'],
'default' => $attributes['default_value'],
'required' => $attributes['required'],
'wrapper_classes' => $attributes['element_classes'],
'classes' => 'wu-rounded',
'value' => $this->get_value(),
'html_attr' => array(
'style' => 'width: 50px !important',
),
),
);
} // end to_fields_array;
} // end class Signup_Field_Color;

View File

@ -0,0 +1,212 @@
<?php
/**
* Creates a cart with the parameters of the purchase being placed.
*
* @package WP_Ultimo
* @subpackage Order
* @since 2.0.0
*/
namespace WP_Ultimo\Checkout\Signup_Fields;
use \WP_Ultimo\Checkout\Signup_Fields\Base_Signup_Field;
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Creates an cart with the parameters of the purchase being placed.
*
* @package WP_Ultimo
* @subpackage Checkout
* @since 2.0.0
*/
class Signup_Field_Discount_Code extends Base_Signup_Field {
/**
* Returns the type of the field.
*
* @since 2.0.0
* @return string
*/
public function get_type() {
return 'discount_code';
} // end get_type;
/**
* Returns if this field should be present on the checkout flow or not.
*
* @since 2.0.0
* @return boolean
*/
public function is_required() {
return false;
} // end is_required;
/**
* Requires the title of the field/element type.
*
* This is used on the Field/Element selection screen.
*
* @since 2.0.0
* @return string
*/
public function get_title() {
return __('Coupon Code', 'wp-ultimo');
} // end get_title;
/**
* Returns the description of the field/element.
*
* This is used as the title attribute of the selector.
*
* @since 2.0.0
* @return string
*/
public function get_description() {
return __('Adds an additional field to apply a discount code.', 'wp-ultimo');
} // end get_description;
/**
* Returns the tooltip of the field/element.
*
* This is used as the tooltip attribute of the selector.
*
* @since 2.0.0
* @return string
*/
public function get_tooltip() {
return __('Adds an additional field to apply a discount code.', 'wp-ultimo');
} // end get_tooltip;
/**
* Returns the icon to be used on the selector.
*
* Can be either a dashicon class or a wu-dashicon class.
*
* @since 2.0.0
* @return string
*/
public function get_icon() {
return 'dashicons-wu-tag1';
} // end get_icon;
/**
* Returns the default values for the field-elements.
*
* This is passed through a wp_parse_args before we send the values
* to the method that returns the actual fields for the checkout form.
*
* @since 2.0.0
* @return array
*/
public function defaults() {
return array(
'placeholder' => '',
'default' => '',
);
} // end defaults;
/**
* List of keys of the default fields we want to display on the builder.
*
* @since 2.0.0
* @return array
*/
public function default_fields() {
return array(
'name',
'placeholder',
'tooltip',
);
} // end default_fields;
/**
* If you want to force a particular attribute to a value, declare it here.
*
* @since 2.0.0
* @return array
*/
public function force_attributes() {
return array(
'id' => 'discount_code',
);
} // end force_attributes;
/**
* Returns the list of additional fields specific to this type.
*
* @since 2.0.0
* @return array
*/
public function get_fields() {
return array();
} // end get_fields;
/**
* Returns the field/element actual field array to be used on the checkout form.
*
* @since 2.0.0
*
* @param array $attributes Attributes saved on the editor form.
* @return array An array of fields, not the field itself.
*/
public function to_fields_array($attributes) {
$checkout_fields = array();
$checkout_fields['discount_code_checkbox'] = array(
'id' => 'discount_code',
'type' => 'toggle',
'name' => __('Have a coupon code?', 'wp-ultimo'),
'class' => 'wu-w-auto',
'html_attr' => array(
'v-model' => 'toggle_discount_code',
),
);
$checkout_fields['discount_code'] = array(
'type' => 'text',
'id' => 'discount_code',
'name' => $attributes['name'],
'placeholder' => $attributes['placeholder'],
'tooltip' => $attributes['tooltip'],
'default' => $attributes['default'],
'wrapper_classes' => wu_get_isset($attributes, 'wrapper_element_classes', ''),
'classes' => wu_get_isset($attributes, 'element_classes', ''),
'wrapper_html_attr' => array(
'v-show' => 'toggle_discount_code',
'style' => $this->calculate_style_attr(),
),
'html_attr' => array(
'v-model.lazy' => 'discount_code',
'v-init:discount_code' => "'{$this->get_value()}'",
'v-init:toggle_discount_code' => !empty($this->get_value()),
),
);
return $checkout_fields;
} // end to_fields_array;
} // end class Signup_Field_Discount_Code;

View File

@ -0,0 +1,308 @@
<?php
/**
* Creates a cart with the parameters of the purchase being placed.
*
* @package WP_Ultimo
* @subpackage Order
* @since 2.0.0
*/
namespace WP_Ultimo\Checkout\Signup_Fields;
use \WP_Ultimo\Checkout\Signup_Fields\Base_Signup_Field;
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Creates an cart with the parameters of the purchase being placed.
*
* @package WP_Ultimo
* @subpackage Checkout
* @since 2.0.0
*/
class Signup_Field_Email extends Base_Signup_Field {
/**
* Returns the type of the field.
*
* @since 2.0.0
*/
public function get_type(): string {
return 'email';
} // end get_type;
/**
* Returns if this field should be present on the checkout flow or not.
*
* @since 2.0.0
*/
public function is_required(): bool {
return true;
} // end is_required;
/**
* Is this a user-related field?
*
* If this is set to true, this field will be hidden
* when the user is already logged in.
*
* @since 2.0.0
*/
public function is_user_field(): bool {
return false;
} // end is_user_field;
/**
* Requires the title of the field/element type.
*
* This is used on the Field/Element selection screen.
*
* @since 2.0.0
* @return string
*/
public function get_title() {
return __('Email', 'wp-ultimo');
} // end get_title;
/**
* Returns the description of the field/element.
*
* This is used as the title attribute of the selector.
*
* @since 2.0.0
* @return string
*/
public function get_description() {
return __('Adds a email address field. This email address will be used to create the WordPress user.', 'wp-ultimo');
} // end get_description;
/**
* Returns the tooltip of the field/element.
*
* This is used as the tooltip attribute of the selector.
*
* @since 2.0.0
* @return string
*/
public function get_tooltip() {
return __('Adds a email address field. This email address will be used to create the WordPress user.', 'wp-ultimo');
} // end get_tooltip;
/**
* Returns the icon to be used on the selector.
*
* Can be either a dashicon class or a wu-dashicon class.
*
* @since 2.0.0
*/
public function get_icon(): string {
return 'dashicons-wu-at-sign';
} // end get_icon;
/**
* Returns the default values for the field-elements.
*
* This is passed through a wp_parse_args before we send the values
* to the method that returns the actual fields for the checkout form.
*
* @since 2.0.0
* @return array
*/
public function defaults() {
return array(
'display_notices' => true,
);
} // end defaults;
/**
* List of keys of the default fields we want to display on the builder.
*
* @since 2.0.0
* @return array
*/
public function default_fields() {
return array(
'name',
'placeholder',
'tooltip',
);
} // end default_fields;
/**
* If you want to force a particular attribute to a value, declare it here.
*
* @since 2.0.0
* @return array
*/
public function force_attributes() {
return array(
'id' => 'email_address',
'required' => true,
);
} // end force_attributes;
/**
* Returns the list of additional fields specific to this type.
*
* @since 2.0.0
* @return array
*/
public function get_fields() {
return array(
'display_notices' => array(
'type' => 'toggle',
'title' => __('Display Notices', 'wp-ultimo'),
'desc' => __('When the customer is already logged in, a box with the customer\'s username and a link to logout is displayed instead of the email field. Disable this option if you do not want that box to show up.', 'wp-ultimo'),
'tooltip' => '',
'value' => 1,
'html_attr' => array(
'v-model' => 'display_notices',
),
),
);
} // end get_fields;
/**
* Returns the field/element actual field array to be used on the checkout form.
*
* @since 2.0.0
*
* @param array $attributes Attributes saved on the editor form.
* @return array An array of fields, not the field itself.
*/
public function to_fields_array($attributes) {
$checkout_fields = array();
if (is_user_logged_in()) {
if ($attributes['display_notices']) {
$checkout_fields['login_note'] = array(
'type' => 'note',
'title' => __('Not you?', 'wp-ultimo'),
'desc' => array($this, 'render_not_you_customer_message'),
'wrapper_classes' => wu_get_isset($attributes, 'wrapper_element_classes', ''),
'wrapper_html_attr' => array(
'style' => $this->calculate_style_attr(),
),
);
} // end if;
} else {
if ($attributes['display_notices']) {
$checkout_fields['login_note'] = array(
'type' => 'note',
'title' => __('Existing customer?', 'wp-ultimo'),
'desc' => array($this, 'render_existing_customer_message'),
'wrapper_classes' => wu_get_isset($attributes, 'wrapper_element_classes', ''),
'wrapper_html_attr' => array(
'style' => $this->calculate_style_attr(),
),
);
} // end if;
$checkout_fields['email_address'] = array(
'type' => 'text',
'id' => 'email_address',
'name' => $attributes['name'],
'placeholder' => $attributes['placeholder'],
'tooltip' => $attributes['tooltip'],
'value' => $this->get_value(),
'required' => true,
'wrapper_classes' => wu_get_isset($attributes, 'wrapper_element_classes', ''),
'classes' => wu_get_isset($attributes, 'element_classes', ''),
'wrapper_html_attr' => array(
'style' => $this->calculate_style_attr(),
),
);
} // end if;
return $checkout_fields;
} // end to_fields_array;
/**
* Renders the login message for users that are not logged in.
*
* @since 2.0.0
* @return string
*/
public function render_existing_customer_message() {
$login_url = wp_login_url(add_query_arg('logged', '1'));
ob_start(); ?>
<div class="wu-p-4 wu-bg-yellow-200">
<?php // phpcs:disable
// translators: %s is the login URL.
printf(__('<a href="%s">Log in</a> to renew or change an existing membership.', 'wp-ultimo'), $login_url);
?>
</div>
<?php // phpcs:enable
return ob_get_clean();
} // end render_existing_customer_message;
/**
* Renders the login message for users that are not logged in.
*
* @since 2.0.0
* @return string
*/
public function render_not_you_customer_message() {
$login_url = wp_login_url(add_query_arg('logged', '1'), true);
ob_start();
?>
<p class="wu-p-4 wu-bg-yellow-200">
<?php
// translators: 1$s is the display name of the user currently logged in.
printf(__('Not %1$s? <a href="%2$s">Log in</a> using your account.', 'wp-ultimo'), wp_get_current_user()->display_name, $login_url);
?>
</p>
<?php
return ob_get_clean();
} // end render_not_you_customer_message;
} // end class Signup_Field_Email;

View File

@ -0,0 +1,213 @@
<?php
/**
* Creates a cart with the parameters of the purchase being placed.
*
* @package WP_Ultimo
* @subpackage Order
* @since 2.0.0
*/
namespace WP_Ultimo\Checkout\Signup_Fields;
use \WP_Ultimo\Checkout\Signup_Fields\Base_Signup_Field;
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Creates an cart with the parameters of the purchase being placed.
*
* @package WP_Ultimo
* @subpackage Checkout
* @since 2.0.0
*/
class Signup_Field_Hidden extends Base_Signup_Field {
/**
* Returns the type of the field.
*
* @since 2.0.0
* @return string
*/
public function get_type() {
return 'hidden';
} // end get_type;
/**
* Returns if this field should be present on the checkout flow or not.
*
* @since 2.0.0
* @return boolean
*/
public function is_required() {
return false;
} // end is_required;
/**
* Requires the title of the field/element type.
*
* This is used on the Field/Element selection screen.
*
* @since 2.0.0
* @return string
*/
public function get_title() {
return __('Hidden Field', 'wp-ultimo');
} // end get_title;
/**
* Returns the description of the field/element.
*
* This is used as the title attribute of the selector.
*
* @since 2.0.0
* @return string
*/
public function get_description() {
return __('Adds a hidden field. This is useful when coupled with the "Fill from the Request" option, to load values from the URL, for example.', 'wp-ultimo');
} // end get_description;
/**
* Returns the tooltip of the field/element.
*
* This is used as the tooltip attribute of the selector.
*
* @since 2.0.0
* @return string
*/
public function get_tooltip() {
return __('Adds a hidden field. This is useful when coupled with the "Fill from the Request" option, to load values from the URL, for example.', 'wp-ultimo');
} // end get_tooltip;
/**
* Returns the icon to be used on the selector.
*
* Can be either a dashicon class or a wu-dashicon class.
*
* @since 2.0.0
* @return string
*/
public function get_icon() {
return 'dashicons-wu-eye-off';
} // end get_icon;
/**
* Returns the default values for the field-elements.
*
* This is passed through a wp_parse_args before we send the values
* to the method that returns the actual fields for the checkout form.
*
* @since 2.0.0
* @return array
*/
public function defaults() {
return array(
'from_request' => true,
);
} // end defaults;
/**
* List of keys of the default fields we want to display on the builder.
*
* @since 2.0.0
* @return array
*/
public function default_fields() {
return array(
'id',
'save_as',
);
} // end default_fields;
/**
* If you want to force a particular attribute to a value, declare it here.
*
* @since 2.0.0
* @return array
*/
public function force_attributes() {
return array();
} // end force_attributes;
/**
* Returns the list of additional fields specific to this type.
*
* @since 2.0.0
* @return array
*/
public function get_fields() {
return array(
'fixed_value' => array(
'order' => 12,
'type' => 'text',
'title' => __('Pre-filled Value', 'wp-ultimo'),
'desc' => __('The field will be populated with this value. Can be overridden if the pre-fill from request option is enabled.', 'wp-ultimo'),
'placeholder' => __('e.g. blue', 'wp-ultimo'),
'tooltip' => '',
'value' => '',
),
);
} // end get_fields;
/**
* Gets the pre-filled value for the field.
*
* @since 2.0.0
* @return mixed
*/
public function get_value() {
$value = parent::get_value();
if (empty($value)) {
$value = $this->attributes['fixed_value'];
} // end if;
return $value;
} // end get_value;
/**
* Returns the field/element actual field array to be used on the checkout form.
*
* @since 2.0.0
*
* @param array $attributes Attributes saved on the editor form.
* @return array An array of fields, not the field itself.
*/
public function to_fields_array($attributes) {
return array(
$attributes['id'] => array(
'type' => 'hidden',
'id' => $attributes['id'],
'wrapper_classes' => $attributes['element_classes'],
'value' => $this->get_value(),
),
);
} // end to_fields_array;
} // end class Signup_Field_Hidden;

View File

@ -0,0 +1,275 @@
<?php
/**
* Creates a cart with the parameters of the purchase being placed.
*
* @package WP_Ultimo
* @subpackage Order
* @since 2.0.0
*/
namespace WP_Ultimo\Checkout\Signup_Fields;
use \WP_Ultimo\Checkout\Signup_Fields\Base_Signup_Field;
use \WP_Ultimo\Managers\Field_Templates_Manager;
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Creates an cart with the parameters of the purchase being placed.
*
* @package WP_Ultimo
* @subpackage Checkout
* @since 2.0.0
*/
class Signup_Field_Order_Bump extends Base_Signup_Field {
/**
* Returns the type of the field.
*
* @since 2.0.0
* @return string
*/
public function get_type() {
return 'order_bump';
} // end get_type;
/**
* Returns if this field should be present on the checkout flow or not.
*
* @since 2.0.0
* @return boolean
*/
public function is_required() {
return false;
} // end is_required;
/**
* Requires the title of the field/element type.
*
* This is used on the Field/Element selection screen.
*
* @since 2.0.0
* @return string
*/
public function get_title() {
return __('Order Bump', 'wp-ultimo');
} // end get_title;
/**
* Returns the description of the field/element.
*
* This is used as the title attribute of the selector.
*
* @since 2.0.0
* @return string
*/
public function get_description() {
return __('Adds a product offer that the customer can click to add to the current cart.', 'wp-ultimo');
} // end get_description;
/**
* Returns the tooltip of the field/element.
*
* This is used as the tooltip attribute of the selector.
*
* @since 2.0.0
* @return string
*/
public function get_tooltip() {
return __('Adds a product offer that the customer can click to add to the current cart.', 'wp-ultimo');
} // end get_tooltip;
/**
* Returns the icon to be used on the selector.
*
* Can be either a dashicon class or a wu-dashicon class.
*
* @since 2.0.0
* @return string
*/
public function get_icon() {
return 'dashicons-wu-gift';
} // end get_icon;
/**
* Returns the default values for the field-elements.
*
* This is passed through a wp_parse_args before we send the values
* to the method that returns the actual fields for the checkout form.
*
* @since 2.0.0
* @return array
*/
public function defaults() {
return array(
'order_bump_template' => 'simple',
'display_product_description' => 0,
);
} // end defaults;
/**
* List of keys of the default fields we want to display on the builder.
*
* @since 2.0.0
* @return array
*/
public function default_fields() {
return array(
// 'id',
'name',
);
} // end default_fields;
/**
* If you want to force a particular attribute to a value, declare it here.
*
* @since 2.0.0
* @return array
*/
public function force_attributes() {
return array(
'order_bump_template' => 'simple',
);
} // end force_attributes;
/**
* Returns the list of available pricing table templates.
*
* @since 2.0.0
* @return array
*/
public function get_templates() {
$available_templates = Field_Templates_Manager::get_instance()->get_templates_as_options('order_bump');
return $available_templates;
} // end get_templates;
/**
* Returns the list of additional fields specific to this type.
*
* @since 2.0.0
* @return array
*/
public function get_fields() {
$editor_fields = array(
'product' => array(
'type' => 'model',
'title' => __('Product', 'wp-ultimo'),
'placeholder' => __('e.g. Premium', 'wp-ultimo'),
'desc' => __('Select the product that will be presented to the customer as an add-on option.', 'wp-ultimo'),
'tooltip' => '',
'order' => 12,
'html_attr' => array(
'data-model' => 'product',
'data-value-field' => 'id',
'data-label-field' => 'name',
'data-search-field' => 'name',
'data-max-items' => 1,
),
),
'display_product_description' => array(
'order' => 13,
'type' => 'toggle',
'title' => __('Display Product Description', 'wp-ultimo'),
'desc' => __('Toggle to display the product description as well, if one is available.', 'wp-ultimo'),
'value' => 0,
),
'display_product_image' => array(
'order' => 14,
'type' => 'toggle',
'title' => __('Display Product Image', 'wp-ultimo'),
'desc' => __('Toggle to display the product image as well, if one is available.', 'wp-ultimo'),
'value' => 1,
),
);
// $editor_fields['order_bump_template'] = array(
// 'type' => 'group',
// 'desc' => Field_Templates_Manager::get_instance()->render_preview_block('order_bump'),
// 'order' => 98,
// 'fields' => array(
// 'order_bump_template' => array(
// 'type' => 'select',
// 'title' => __('Layout', 'wp-ultimo'),
// 'placeholder' => __('Select your Layout', 'wp-ultimo'),
// 'options' => array($this, 'get_templates'),
// 'wrapper_classes' => 'wu-flex-grow',
// 'html_attr' => array(
// 'v-model' => 'order_bump_template',
// ),
// ),
// ),
// );
// @todo: re-add developer notes.
// $editor_fields['_dev_note_develop_your_own_template_order_bump'] = array(
// 'type' => 'note',
// 'order' => 99,
// 'wrapper_classes' => 'sm:wu-p-0 sm:wu-block',
// 'classes' => '',
// 'desc' => sprintf('<div class="wu-p-4 wu-bg-blue-100 wu-text-grey-600">%s</div>', __('Want to add customized order bump templates?<br><a target="_blank" class="wu-no-underline" href="https://help.wpultimo.com/article/343-customize-your-checkout-flow-using-field-templates">See how you can do that here</a>.', 'wp-ultimo')),
// );
return $editor_fields;
} // end get_fields;
/**
* Returns the field/element actual field array to be used on the checkout form.
*
* @since 2.0.0
*
* @param array $attributes Attributes saved on the editor form.
* @return array An array of fields, not the field itself.
*/
public function to_fields_array($attributes) {
$product_id = $attributes['product'];
$product = is_numeric($product_id) ? wu_get_product($product_id) : wu_get_product_by_slug($product_id);
if (!$product) {
return array();
} // end if;
$attributes['product'] = $product;
$template_class = Field_Templates_Manager::get_instance()->get_template_class('order_bump', $attributes['order_bump_template']);
$content = $template_class ? $template_class->render_container($attributes) : __('Template does not exist.', 'wp-ultimo');
return array(
$attributes['id'] => array(
'type' => 'note',
'desc' => $content,
'wrapper_classes' => $attributes['element_classes'],
),
);
} // end to_fields_array;
} // end class Signup_Field_Order_Bump;

View File

@ -0,0 +1,251 @@
<?php
/**
* Creates a cart with the parameters of the purchase being placed.
*
* @package WP_Ultimo
* @subpackage Order
* @since 2.0.0
*/
namespace WP_Ultimo\Checkout\Signup_Fields;
use \WP_Ultimo\Checkout\Signup_Fields\Base_Signup_Field;
use \WP_Ultimo\Managers\Field_Templates_Manager;
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Creates an cart with the parameters of the purchase being placed.
*
* @package WP_Ultimo
* @subpackage Checkout
* @since 2.0.0
*/
class Signup_Field_Order_Summary extends Base_Signup_Field {
/**
* Returns the type of the field.
*
* @since 2.0.0
*/
public function get_type(): string {
return 'order_summary';
} // end get_type;
/**
* Returns if this field should be present on the checkout flow or not.
*
* @since 2.0.0
*/
public function is_required(): bool {
return true;
} // end is_required;
/**
* Requires the title of the field/element type.
*
* This is used on the Field/Element selection screen.
*
* @since 2.0.0
* @return string
*/
public function get_title() {
return __('Order Summary', 'wp-ultimo');
} // end get_title;
/**
* Returns the description of the field/element.
*
* This is used as the title attribute of the selector.
*
* @since 2.0.0
* @return string
*/
public function get_description() {
return __('Adds a summary table with prices, key subscription dates, discounts, and taxes.', 'wp-ultimo');
} // end get_description;
/**
* Returns the tooltip of the field/element.
*
* This is used as the tooltip attribute of the selector.
*
* @since 2.0.0
* @return string
*/
public function get_tooltip() {
return __('Adds a summary table with prices, key subscription dates, discounts, and taxes.', 'wp-ultimo');
} // end get_tooltip;
/**
* Returns the icon to be used on the selector.
*
* Can be either a dashicon class or a wu-dashicon class.
*
* @since 2.0.0
*/
public function get_icon(): string {
return 'dashicons-wu-dollar-sign';
} // end get_icon;
/**
* Returns the default values for the field-elements.
*
* This is passed through a wp_parse_args before we send the values
* to the method that returns the actual fields for the checkout form.
*
* @since 2.0.0
* @return array
*/
public function defaults() {
return array(
'order_summary_template' => 'clean',
'table_columns' => 'simple',
);
} // end defaults;
/**
* List of keys of the default fields we want to display on the builder.
*
* @since 2.0.0
* @return array
*/
public function default_fields() {
return array(
'name',
);
} // end default_fields;
/**
* If you want to force a particular attribute to a value, declare it here.
*
* @since 2.0.0
* @return array
*/
public function force_attributes() {
return array(
'id' => 'order_summary',
);
} // end force_attributes;
/**
* Returns the list of available pricing table templates.
*
* @since 2.0.0
* @return array
*/
public function get_templates() {
$available_templates = Field_Templates_Manager::get_instance()->get_templates_as_options('order_summary');
return $available_templates;
} // end get_templates;
/**
* Returns the list of additional fields specific to this type.
*
* @since 2.0.0
* @return array
*/
public function get_fields() {
$editor_fields = array();
$editor_fields['table_columns'] = array(
'type' => 'select',
'title' => __('Table Columns', 'wp-ultimo'),
'desc' => __('"Simplified" will condense all discount and tax info into separate rows to keep the table with only two columns. "Display All" adds a discounts and taxes column to each product row.', 'wp-ultimo'),
'options' => array(
'simple' => __('Simplified', 'wp-ultimo'),
'full' => __('Display All', 'wp-ultimo'),
)
);
$editor_fields['order_summary_template'] = array(
'type' => 'group',
'desc' => Field_Templates_Manager::get_instance()->render_preview_block('order_summary'),
'fields' => array(
'order_summary_template' => array(
'type' => 'select',
'title' => __('Layout', 'wp-ultimo'),
'placeholder' => __('Select your Layout', 'wp-ultimo'),
'options' => array($this, 'get_templates'),
'wrapper_classes' => 'wu-flex-grow',
'html_attr' => array(
'v-model' => 'order_summary_template',
),
),
),
);
// @todo: re-add developer notes.
// $editor_fields['_dev_note_develop_your_own_template_order_summary'] = array(
// 'type' => 'note',
// 'order' => 99,
// 'wrapper_classes' => 'sm:wu-p-0 sm:wu-block',
// 'classes' => '',
// 'desc' => sprintf('<div class="wu-p-4 wu-bg-blue-100 wu-text-grey-600">%s</div>', __('Want to add customized order summary templates?<br><a target="_blank" class="wu-no-underline" href="https://help.wpultimo.com/article/343-customize-your-checkout-flow-using-field-templates">See how you can do that here</a>.', 'wp-ultimo')),
// );
return $editor_fields;
} // end get_fields;
/**
* Returns the field/element actual field array to be used on the checkout form.
*
* @since 2.0.0
*
* @param array $attributes Attributes saved on the editor form.
* @return array An array of fields, not the field itself.
*/
public function to_fields_array($attributes) {
$checkout_fields = array();
/*
* Backwards compatibility with previous betas
*/
if ($attributes['order_summary_template'] === 'simple') {
$attributes['order_summary_template'] = 'clean';
} // end if;
$template_class = Field_Templates_Manager::get_instance()->get_template_class('order_summary', $attributes['order_summary_template']);
$content = $template_class ? $template_class->render_container($attributes) : __('Template does not exist.', 'wp-ultimo');
$checkout_fields[$attributes['id']] = array(
'type' => 'note',
'desc' => $content,
'wrapper_classes' => wu_get_isset($attributes, 'wrapper_element_classes', ''),
'classes' => wu_get_isset($attributes, 'element_classes', ''),
'wrapper_html_attr' => array(
'style' => $this->calculate_style_attr(),
),
);
return $checkout_fields;
} // end to_fields_array;
} // end class Signup_Field_Order_Summary;

View File

@ -0,0 +1,259 @@
<?php
/**
* Creates a cart with the parameters of the purchase being placed.
*
* @package WP_Ultimo
* @subpackage Order
* @since 2.0.0
*/
namespace WP_Ultimo\Checkout\Signup_Fields;
use \WP_Ultimo\Checkout\Signup_Fields\Base_Signup_Field;
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Creates an cart with the parameters of the purchase being placed.
*
* @package WP_Ultimo
* @subpackage Checkout
* @since 2.0.0
*/
class Signup_Field_Password extends Base_Signup_Field {
/**
* Returns the type of the field.
*
* @since 2.0.0
* @return string
*/
public function get_type() {
return 'password';
} // end get_type;
/**
* Returns if this field should be present on the checkout flow or not.
*
* @since 2.0.0
* @return boolean
*/
public function is_required() {
return true;
} // end is_required;
/**
* Is this a user-related field?
*
* If this is set to true, this field will be hidden
* when the user is already logged in.
*
* @since 2.0.0
* @return boolean
*/
public function is_user_field() {
return true;
} // end is_user_field;
/**
* Requires the title of the field/element type.
*
* This is used on the Field/Element selection screen.
*
* @since 2.0.0
* @return string
*/
public function get_title() {
return __('Password', 'wp-ultimo');
} // end get_title;
/**
* Returns the description of the field/element.
*
* This is used as the title attribute of the selector.
*
* @since 2.0.0
* @return string
*/
public function get_description() {
return __('Adds a password field, with options for enforcing password strength and adding password confirmation field. This password is then used to create the WordPress user.', 'wp-ultimo');
} // end get_description;
/**
* Returns the tooltip of the field/element.
*
* This is used as the tooltip attribute of the selector.
*
* @since 2.0.0
* @return string
*/
public function get_tooltip() {
return __('Adds a password field, with options for enforcing password strength and adding password confirmation field. This password is then used to create the WordPress user.', 'wp-ultimo');
} // end get_tooltip;
/**
* Returns the icon to be used on the selector.
*
* Can be either a dashicon class or a wu-dashicon class.
*
* @since 2.0.0
* @return string
*/
public function get_icon() {
return 'dashicons-wu-lock1';
} // end get_icon;
/**
* Returns the default values for the field-elements.
*
* This is passed through a wp_parse_args before we send the values
* to the method that returns the actual fields for the checkout form.
*
* @since 2.0.0
* @return array
*/
public function defaults() {
return array(
'password_confirm_field' => false,
'password_confirm_label' => __('Confirm Password', 'wp-ultimo'),
);
} // end defaults;
/**
* List of keys of the default fields we want to display on the builder.
*
* @since 2.0.0
* @return array
*/
public function default_fields() {
return array(
'name',
'placeholder',
'tooltip',
);
} // end default_fields;
/**
* If you want to force a particular attribute to a value, declare it here.
*
* @since 2.0.0
* @return array
*/
public function force_attributes() {
return array(
'id' => 'password',
'required' => true,
);
} // end force_attributes;
/**
* Returns the list of additional fields specific to this type.
*
* @since 2.0.0
* @return array
*/
public function get_fields() {
return array(
'password_strength_meter' => array(
'type' => 'toggle',
'title' => __('Display Password Strength Meter', 'wp-ultimo'),
'desc' => __('Adds a password strength meter below the password field. Enabling this option also enforces passwords to be strong.', 'wp-ultimo'),
'value' => 1,
),
'password_confirm_field' => array(
'type' => 'toggle',
'title' => __('Display Password Confirm Field', 'wp-ultimo'),
'desc' => __('Adds a "Confirm your Password" field below the default password field to reduce the chance or making a mistake.', 'wp-ultimo'),
'value' => 1,
),
);
} // end get_fields;
/**
* Returns the field/element actual field array to be used on the checkout form.
*
* @since 2.0.0
*
* @param array $attributes Attributes saved on the editor form.
* @return array An array of fields, not the field itself.
*/
public function to_fields_array($attributes) {
/*
* Logged in user, bail.
*/
if (is_user_logged_in()) {
return array();
} // end if;
$checkout_fields = array();
$checkout_fields['password'] = array(
'type' => 'password',
'id' => 'password',
'name' => $attributes['name'],
'placeholder' => $attributes['placeholder'],
'tooltip' => $attributes['tooltip'],
'meter' => $attributes['password_strength_meter'],
'required' => true,
'wrapper_classes' => wu_get_isset($attributes, 'wrapper_element_classes', ''),
'classes' => wu_get_isset($attributes, 'element_classes', ''),
'html_attr' => array(
'autocomplete' => 'new-password',
),
'wrapper_html_attr' => array(
'style' => $this->calculate_style_attr(),
),
);
if ($attributes['password_confirm_field']) {
$checkout_fields['password_conf'] = array(
'type' => 'password',
'id' => 'password_conf',
'name' => $attributes['password_confirm_label'],
'placeholder' => '',
'tooltip' => '',
'meter' => false,
'required' => true,
'wrapper_classes' => wu_get_isset($attributes, 'wrapper_element_classes', ''),
'classes' => wu_get_isset($attributes, 'element_classes', ''),
'html_attr' => array(
'autocomplete' => 'new-password',
),
'wrapper_html_attr' => array(
'style' => $this->calculate_style_attr(),
),
);
} // end if;
return $checkout_fields;
} // end to_fields_array;
} // end class Signup_Field_Password;

View File

@ -0,0 +1,224 @@
<?php
/**
* Creates a cart with the parameters of the purchase being placed.
*
* @package WP_Ultimo
* @subpackage Order
* @since 2.0.0
*/
namespace WP_Ultimo\Checkout\Signup_Fields;
use \WP_Ultimo\Checkout\Signup_Fields\Base_Signup_Field;
use \WP_Ultimo\Managers\Gateway_Manager;
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Creates an cart with the parameters of the purchase being placed.
*
* @package WP_Ultimo
* @subpackage Checkout
* @since 2.0.0
*/
class Signup_Field_Payment extends Base_Signup_Field {
/**
* Returns the type of the field.
*
* @since 2.0.0
* @return string
*/
public function get_type() {
return 'payment';
} // end get_type;
/**
* Returns if this field should be present on the checkout flow or not.
*
* @since 2.0.0
* @return boolean
*/
public function is_required() {
return true;
} // end is_required;
/**
* Requires the title of the field/element type.
*
* This is used on the Field/Element selection screen.
*
* @since 2.0.0
* @return string
*/
public function get_title() {
return __('Payment', 'wp-ultimo');
} // end get_title;
/**
* Returns the description of the field/element.
*
* This is used as the title attribute of the selector.
*
* @since 2.0.0
* @return string
*/
public function get_description() {
return __('Adds the payment options and the additional fields required to complete a purchase (e.g. credit card field).', 'wp-ultimo');
} // end get_description;
/**
* Returns the tooltip of the field/element.
*
* This is used as the tooltip attribute of the selector.
*
* @since 2.0.0
* @return string
*/
public function get_tooltip() {
return __('Adds the payment options and the additional fields required to complete a purchase (e.g. credit card field).', 'wp-ultimo');
} // end get_tooltip;
/**
* Returns the icon to be used on the selector.
*
* Can be either a dashicon class or a wu-dashicon class.
*
* @since 2.0.0
* @return string
*/
public function get_icon() {
return 'dashicons-wu-credit-card2';
} // end get_icon;
/**
* Returns the default values for the field-elements.
*
* This is passed through a wp_parse_args before we send the values
* to the method that returns the actual fields for the checkout form.
*
* @since 2.0.0
* @return array
*/
public function defaults() {
return array(
''
);
} // end defaults;
/**
* List of keys of the default fields we want to display on the builder.
*
* @since 2.0.0
* @return array
*/
public function default_fields() {
return array(
'name',
);
} // end default_fields;
/**
* If you want to force a particular attribute to a value, declare it here.
*
* @since 2.0.0
* @return array
*/
public function force_attributes() {
return array(
'id' => 'payment',
);
} // end force_attributes;
/**
* Returns the list of additional fields specific to this type.
*
* @since 2.0.0
* @return array
*/
public function get_fields() {
return array();
} // end get_fields;
/**
* Returns the field/element actual field array to be used on the checkout form.
*
* @since 2.0.0
*
* @param array $attributes Attributes saved on the editor form.
* @return array An array of fields, not the field itself.
*/
public function to_fields_array($attributes) {
$fields = array(
'payment_template' => array(
'type' => 'text',
'id' => 'payment_template',
'name' => '',
'classes' => 'wu-hidden',
),
'payment' => array(
'type' => 'payment-methods',
'id' => 'payment',
'name' => $attributes['name'],
'wrapper_classes' => wu_get_isset($attributes, 'wrapper_element_classes', ''),
'classes' => wu_get_isset($attributes, 'element_classes', ''),
'wrapper_html_attr' => array(
'style' => $this->calculate_style_attr(),
),
),
);
/*
* Checks if we need to add the
* auto renew field.
*/
if (!wu_get_setting('force_auto_renew', 1)) {
$auto_renewable_gateways = Gateway_Manager::get_instance()->get_auto_renewable_gateways();
$fields['auto_renew'] = array(
'type' => 'toggle',
'id' => 'auto_renew',
'name' => __('Auto-renew', 'wp-ultimo'),
'tooltip' => '',
'value' => '1',
'html_attr' => array(
'v-model' => 'auto_renew',
'true-value' => '1',
'false-value' => '0',
),
'wrapper_html_attr' => array(
'v-cloak' => 1,
'v-show' => sprintf('%s.includes(gateway) && order.should_collect_payment && order.has_recurring', json_encode($auto_renewable_gateways)),
)
);
} // end if;
return $fields;
} // end to_fields_array;
} // end class Signup_Field_Payment;

Some files were not shown because too many files have changed in this diff Show More