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;