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

69
inc/functions/admin.php Normal file
View File

@ -0,0 +1,69 @@
<?php
/**
* Admin Panel Functions
*
* @package WP_Ultimo\Functions
* @since 2.0.0
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Returns the HTML markup of a empty state page.
*
* @since 2.0.0
*
* @param array $args List of the page arguments.
* @return string
*/
function wu_render_empty_state($args = array()) {
$args = wp_parse_args($args, array(
'message' => __('This is not yet available...'),
'sub_message' => __('We\'re still working on this part of the product.'),
'link_label' => __('&larr; Go Back', 'wp-ultimo'),
'link_url' => 'javascript:history.go(-1)',
'link_classes' => '',
'link_icon' => '',
'display_background_image' => true,
));
return wu_get_template_contents('base/empty-state', $args);
} // end wu_render_empty_state;
/**
* Checks if should use wrap container or not based on user setting.
*
* @since 2.0.0
*/
function wu_wrap_use_container() {
echo get_user_setting('wu_use_container', false) ? 'admin-lg:wu-container admin-lg:wu-mx-auto' : '';
} // end wu_wrap_use_container;
/**
* Renders the responsive table single-line.
*
* @since 2.0.0
*
* @param array $args Main arguments.
* @param array $first_row The first row of icons + labels.
* @param array $second_row The second row, on the right.
* @return string
*/
function wu_responsive_table_row($args = array(), $first_row = array(), $second_row = array()) {
$args = wp_parse_args($args, array(
'id' => '',
'title' => __('No Title', 'wp-ultimo'),
'url' => '#',
'status' => '',
'image' => '',
));
return wu_get_template_contents('base/responsive-table-row', compact('args', 'first_row', 'second_row'));
} // end wu_responsive_table_row;

View File

@ -0,0 +1,294 @@
<?php
/**
* Array Helpers
*
* @package WP_Ultimo\Functions
* @since 2.0.11
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
use \WP_Ultimo\Helpers\Arr;
/**
* Turns a multi-dimensional array into a flat array.
*
* @since 2.0.0
*
* @param array $array The array to flatten.
* @param boolean $indexes If we need to add the indexes as well.
* @return array
*/
function wu_array_flatten($array, $indexes = false) {
$return = array();
array_walk_recursive($array, function($x, $index) use (&$return, $indexes) {
if ($indexes) {
$return[] = $index;
} // end if;
$return[] = $x;
});
return $return;
} // end wu_array_flatten;
/**
* Copy from http://www.php.net/manual/en/function.array-merge-recursive.php#92195
*
* The array_merge_recursive does indeed merge arrays, but it converts values with duplicate
* keys to arrays rather than overwriting the value in the first array with the duplicate
* value in the second array, as array_merge does. I.e., with array_merge_recursive,
* this happens (documented behavior):
*
* array_merge_recursive(array('key' => 'org value'), array('key' => 'new value'));
* => array('key' => array('org value', 'new value'));
*
* array_merge_recursive_distinct does not change the datatypes of the values in the arrays.
* Matching keys' values in the second array overwrite those in the first array, as is the
* case with array_merge, i.e.:
*
* array_merge_recursive_distinct(array('key' => 'org value'), array('key' => 'new value'));
* => array('key' => array('new value'));
*
* Parameters are passed by reference, though only for performance reasons. They're not
* altered by this function.
*
* @author Gabriel Sobrinho <gabriel (dot) sobrinho (at) gmail (dot) com>
* @author Daniel <daniel (at) danielsmedegaardbuus (dot) dk>
*
* @param array $array1 The arrays original.
* @param array $array2 The array to be merged in.
* @param bool $should_sum If we should add up numeric values instead of replacing the original.
* @return array
*/
function wu_array_merge_recursive_distinct(array &$array1, array &$array2, $should_sum = true) {
$merged = $array1;
foreach ($array2 as $key => &$value) {
if (is_array($value) && isset($merged[$key]) && is_array($merged[$key])) {
$merged[$key] = wu_array_merge_recursive_distinct($merged[$key], $value, $should_sum);
} else {
if (isset($merged[$key]) && is_numeric($merged[$key]) && is_numeric($value) && $should_sum) {
$merged[$key] = ((int) $merged[$key]) + $value;
} else {
$merged[$key] = $value;
} // end if;
} // end if;
} // end foreach;
return $merged;
} // end wu_array_merge_recursive_distinct;
/**
* Compares two arrays and returns the diff, recursively.
*
* This is frequently used to compare Limitation sets so we can have
* a waterfall of limitations coming from the product, to the
* membership, down to the site.
*
* @since 2.0.0
*
* @param array $array1 Array 1.
* @param array $array2 Array 2.
* @param array $to_keep List of keys to keep regardless of diff status.
* @return array
*/
function wu_array_recursive_diff($array1, $array2, $to_keep = array()) {
$arr_return = array();
$array1 = (array) $array1;
$array2 = (array) $array2;
foreach ($array1 as $key => $value) {
if (array_key_exists($key, $array2)) {
if (is_array($value)) {
$array_recursive_diff = wu_array_recursive_diff($value, $array2[$key], $to_keep);
if (count($array_recursive_diff)) {
$arr_return[$key] = $array_recursive_diff;
} // end if;
} else {
if ((!is_null($value) && $value != $array2[$key]) || ($value && $array2[$key] && in_array($key, $to_keep, true))) { // phpcs:ignore
$arr_return[$key] = $value;
} // end if;
} // end if;
} else {
$arr_return[$key] = $value;
} // end if;
} // end foreach;
return $arr_return;
} // end wu_array_recursive_diff;
/**
* Array map implementation to deal with keys.
*
* @since 2.0.0
*
* @param callable $callable The callback to run.
* @param array $array The array to map the keys.
*/
function wu_array_map_keys($callable, $array): array {
$keys = array_keys($array);
$keys = array_map($callable, $keys);
return array_combine($keys, $array);
} // end wu_array_map_keys;
/**
* Converts a key => value array into an array of objects with key and value entries.
*
* Example:
*
* - Input:
* array(
* 'key' => 'value',
* 'other' => 'foobar',
* );
*
* - Output:
* array(
* array(
* 'id' => 'key',
* 'value => 'value',
* ),
* array(
* 'id' => 'other',
* 'value => 'foobar',
* ),
* );
*
* @since 2.0.11
*
* @param array $assoc_array The key => value array.
* @param string $key_name The name to use for the key entry.
* @param string $value_name The name to use for the value entry.
* @return array
*/
function wu_key_map_to_array($assoc_array, $key_name = 'id', $value_name = 'value') {
$results = array();
foreach ($assoc_array as $key => &$value) {
$results[] = array(
$key_name => $key,
$value_name => $value,
);
} // end foreach;
return $results;
} // end wu_key_map_to_array;
/**
* Find a value inside an array by a particular key or property.
*
* Dot notation is supported.
*
* @since 2.0.11
*
* @param array $array The array to be searched.
* @param string $property The property to find by. Supports dot notation.
* @param mixed $expected The expected property value.
* @param integer $flag How to return the results. Can be Arr::RESULTS_ALL, Arr::RESULTS_FIRST, and Arr::RESULTS_LAST.
* @return mixed
*/
function wu_array_find_by($array, $property, $expected, $flag = 0) {
return Arr::filter_by_property($array, $property, $expected, $flag);
} // end wu_array_find_by;
/**
* Finds all the values inside an array by a particular key or property.
*
* Dot notation is supported.
*
* @since 2.0.11
*
* @param array $array The array to be searched.
* @param string $property The property to find by. Supports dot notation.
* @param mixed $expected The expected property value.
* @return mixed
*/
function wu_array_find_all_by($array, $property, $expected) {
return wu_array_find_by($array, $property, $expected, Arr::RESULTS_ALL);
} // end wu_array_find_all_by;
/**
* Finds the first value inside an array by a particular key or property.
*
* Dot notation is supported.
*
* @since 2.0.11
*
* @param array $array The array to be searched.
* @param string $property The property to find by. Supports dot notation.
* @param mixed $expected The expected property value.
* @return mixed
*/
function wu_array_find_first_by($array, $property, $expected) {
return wu_array_find_by($array, $property, $expected, Arr::RESULTS_FIRST);
} // end wu_array_find_first_by;
/**
* Finds the last value inside an array by a particular key or property.
*
* Dot notation is supported.
*
* @since 2.0.11
*
* @param array $array The array to be searched.
* @param string $property The property to find by. Supports dot notation.
* @param mixed $expected The expected property value.
* @return mixed
*/
function wu_array_find_last_by($array, $property, $expected) {
return wu_array_find_by($array, $property, $expected, Arr::RESULTS_LAST);
} // end wu_array_find_last_by;

32
inc/functions/assets.php Normal file
View File

@ -0,0 +1,32 @@
<?php
/**
* Asset Helpers
*
* @package WP_Ultimo\Functions
* @since 2.0.11
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Returns the URL for assets inside the assets folder.
*
* @since 2.0.0
*
* @param string $asset Asset file name with the extention.
* @param string $assets_dir Assets sub-directory. Defaults to 'img'.
* @param string $base_dir Base dir. Defaults to 'assets'.
* @return string
*/
function wu_get_asset($asset, $assets_dir = 'img', $base_dir = 'assets') {
if (!defined('SCRIPT_DEBUG') || !SCRIPT_DEBUG) {
$asset = preg_replace('/(?<!\.min)(\.js|\.css)/', '.min$1', $asset);
} // end if;
return wu_url("$base_dir/$assets_dir/$asset");
} // end wu_get_asset;

145
inc/functions/broadcast.php Normal file
View File

@ -0,0 +1,145 @@
<?php
/**
* Broadcast Functions
*
* @package WP_Ultimo\Functions
* @since 2.0.0
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
use \WP_Ultimo\Models\Broadcast;
/**
* Queries broadcast.
*
* @since 2.0.0
*
* @param array $query Query arguments.
* @return \WP_Ultimo\Models\Broadcast[]
*/
function wu_get_broadcasts($query = array()) {
if (!isset($query['type__in'])) {
$query['type__in'] = array('broadcast_email', 'broadcast_notice');
} // end if;
return \WP_Ultimo\Models\Broadcast::query($query);
} // end wu_get_broadcasts;
/**
* Returns a single broadcast defined by a particular column and value.
*
* @since 2.0.7
*
* @param string $column The column name.
* @param mixed $value The column value.
* @return \WP_Ultimo\Models\Broadcast|false
*/
function wu_get_broadcast_by($column, $value) {
$first_attempt = \WP_Ultimo\Models\Broadcast::get_by($column, $value);
if ($first_attempt) {
return $first_attempt;
} // end if;
$query = array(
'number' => 1,
'type__in' => array('broadcast_email', 'broadcast_notice'),
);
$query['meta_query'] = array(
array(
'key' => $column,
'value' => $value,
),
);
$results = \WP_Ultimo\Models\Broadcast::query($query);
return !empty($results) ? array_pop($results) : false;
} // end wu_get_broadcast_by;
/**
* Gets a broadcast on the ID.
*
* @since 2.0.0
*
* @param integer $broadcast_id ID of the broadcast to retrieve.
* @return \WP_Ultimo\Models\Broadcast|false
*/
function wu_get_broadcast($broadcast_id) {
return \WP_Ultimo\Models\Broadcast::get_by_id($broadcast_id);
} // end wu_get_broadcast;
/**
* Gets a broadcast on the ID.
*
* @since 2.0.0
*
* @param integer $broadcast_id ID of the broadcast to retrieve.
* @param string $type Target type (customers or products).
* @return array All targets, based on the type, from a specific broadcast.
*/
function wu_get_broadcast_targets($broadcast_id, $type) {
$object = \WP_Ultimo\Models\Broadcast::get_by_id($broadcast_id);
$targets = $object->get_message_targets();
if (is_array($targets[$type])) {
return $targets[$type];
} elseif (is_string($targets[$type])) {
return explode(',', $targets[$type]);
} // end if;
return array();
} // end wu_get_broadcast_targets;
/**
* Creates a new broadcast.
*
* Check the wp_parse_args below to see what parameters are necessary.
*
* @since 2.0.0
*
* @param array $broadcast_data Broadcast attributes.
* @return \WP_Error|\WP_Ultimo\Models\Broadcast
*/
function wu_create_broadcast($broadcast_data) {
$broadcast_data = wp_parse_args($broadcast_data, array(
'type' => 'broadcast_notice',
'notice_type' => 'success',
'date_created' => wu_get_current_time('mysql', true),
'date_modified' => wu_get_current_time('mysql', true),
'migrated_from_id' => 0,
'skip_validation' => false,
'message_targets' => array(
'customers' => array(),
'products' => array(),
),
));
$broadcast = new Broadcast($broadcast_data);
$saved = $broadcast->save();
return is_wp_error($saved) ? $saved : $broadcast;
} // end wu_create_broadcast;

View File

@ -0,0 +1,234 @@
<?php
/**
* Checkout Form Functions
*
* @package WP_Ultimo\Functions
* @since 2.0.0
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
use \WP_Ultimo\Checkout\Checkout;
use \WP_Ultimo\Models\Checkout_Form;
/**
* Returns a checkout_form.
*
* @since 2.0.0
*
* @param int $checkout_form_id The ID of the checkout_form.
* @return \WP_Ultimo\Models\Checkout_Form|false
*/
function wu_get_checkout_form($checkout_form_id) {
return \WP_Ultimo\Models\Checkout_Form::get_by_id($checkout_form_id);
} // end wu_get_checkout_form;
/**
* Queries checkout_forms.
*
* @since 2.0.0
*
* @param array $query Query arguments.
* @return \WP_Ultimo\Models\Checkout_Form[]
*/
function wu_get_checkout_forms($query = array()) {
return \WP_Ultimo\Models\Checkout_Form::query($query);
} // end wu_get_checkout_forms;
/**
* Returns a checkout_form based on slug.
*
* @since 2.0.0
*
* @param string $checkout_form_slug The slug of the checkout_form.
* @return \WP_Ultimo\Models\Checkout_Form|false
*/
function wu_get_checkout_form_by_slug($checkout_form_slug) {
/**
* Fixed case: Upgrade/Downgrade forms.
*
* In this particular case, the fields are fixed,
* although they can be modified via a filter in the
* Checkout_Form::membership_change_form_fields() method.
*
* @see wu_checkout_form_membership_change_form_fields filter.
*/
if ($checkout_form_slug === 'wu-checkout') {
$checkout_form = new \WP_Ultimo\Models\Checkout_Form;
$checkout_fields = Checkout_Form::membership_change_form_fields();
$checkout_form->set_settings($checkout_fields);
return $checkout_form;
} elseif ($checkout_form_slug === 'wu-add-new-site') {
$checkout_form = new \WP_Ultimo\Models\Checkout_Form;
$checkout_fields = Checkout_Form::add_new_site_form_fields();
$checkout_form->set_settings($checkout_fields);
return $checkout_form;
} elseif ($checkout_form_slug === 'wu-finish-checkout') {
$checkout_form = new \WP_Ultimo\Models\Checkout_Form;
$checkout_fields = Checkout_Form::finish_checkout_form_fields();
$checkout_form->set_settings($checkout_fields);
return $checkout_form;
} // end if;
return \WP_Ultimo\Models\Checkout_Form::get_by('slug', $checkout_form_slug);
} // end wu_get_checkout_form_by_slug;
/**
* Creates a new checkout form.
*
* @since 2.0.0
*
* @param array $checkout_form_data Checkout_Form data.
* @return \WP_Error|\WP_Ultimo\Models\Checkout_Form
*/
function wu_create_checkout_form($checkout_form_data) {
$checkout_form_data = wp_parse_args($checkout_form_data, array(
'name' => false,
'slug' => false,
'settings' => array(),
'allowed_countries' => array(),
'date_created' => wu_get_current_time('mysql', true),
'date_modified' => wu_get_current_time('mysql', true),
));
$checkout_form = new Checkout_Form($checkout_form_data);
$saved = $checkout_form->save();
return is_wp_error($saved) ? $saved : $checkout_form;
} // end wu_create_checkout_form;
/**
* Returns a list of all the available domain options in all registered forms.
*
* @since 2.0.11
* @return array
*/
function wu_get_available_domain_options() {
$fields = array();
$main_form = wu_get_checkout_form_by_slug('main-form');
if ($main_form) {
$fields = $main_form->get_all_fields_by_type('site_url');
} else {
$forms = wu_get_checkout_forms(array(
'number' => 1,
));
if ($forms) {
$fields = $forms[0]->get_all_fields_by_type('site_url');
} // end if;
} // end if;
$domain_options = array();
if ($fields) {
foreach ($fields as $field) {
$available_domains = isset($field['available_domains']) ? $field['available_domains'] : '';
$field_domain_options = explode(PHP_EOL, (string) $available_domains);
if (isset($field['enable_domain_selection']) && $field['enable_domain_selection'] && $field_domain_options) {
$domain_options = array_merge($domain_options, $field_domain_options);
} // end if;
} // end foreach;
} // end if;
return $domain_options;
} // end wu_get_available_domain_options;
/**
* Check if the field is preselected in request.
*
* @since 2.0.19
* @param string $field_slug Path to attach to the end of the URL.
* @return bool
*/
function wu_is_form_field_pre_selected($field_slug) {
$checkout = Checkout::get_instance();
$pre_selected = $checkout->request_or_session('pre_selected', array());
$from_request = stripslashes_deep(wu_get_isset($_GET, $field_slug)) || isset($pre_selected[$field_slug]);
return wu_request('wu_preselected') === $field_slug || $from_request;
} // end wu_is_form_field_pre_selected;
/**
* Get the request arg slug from a field.
*
* @since 2.0.19
* @param array $field The field from form step.
* @return string
*/
function wu_form_field_request_arg($field) {
if ($field['type'] === 'template_selection') {
return 'template_id';
} // end if;
if ($field['type'] === 'pricing_table') {
return 'products';
} // end if;
return $field['id'];
} // end wu_form_field_request_arg;
/**
* Check if the field should be hidden in form
*
* @since 2.0.19
* @param array $field The field from form step.
* @return bool
*/
function wu_should_hide_form_field($field) {
$hide_preselect = (bool) (int) wu_get_isset($field, "hide_{$field['type']}_when_pre_selected");
return $hide_preselect && wu_is_form_field_pre_selected(wu_form_field_request_arg($field));
} // end wu_should_hide_form_field;

326
inc/functions/checkout.php Normal file
View File

@ -0,0 +1,326 @@
<?php
/**
* Checkout Functions
*
* @package WP_Ultimo\Functions
* @since 2.0.0
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
use \WP_Ultimo\Managers\Signup_Fields_Manager;
/**
* Needs to be removed.
*
* @todo Remove this and use out functions instead.
* @since 2.0.0
* @return \WP_Error
*/
function wu_errors() {
global $wu_errors;
if (!is_wp_error($wu_errors)) {
$wu_errors = new \WP_Error();
} // end if;
return $wu_errors;
} // end wu_errors;
/**
* Generate an idempotency key.
*
* @since 2.0.0
*
* @param array $args Arguments used to create or update the current object.
* @param string $context The context in which the key was generated.
* @return string
*/
function wu_stripe_generate_idempotency_key($args, $context = 'new') {
$idempotency_key = md5(json_encode($args));
/**
* Filters the idempotency_key value sent with the Stripe charge options.
*
* @since 3.5.0
*
* @param string $idempotency_key Value of the idempotency key.
* @param array $args Arguments used to help generate the key.
* @param string $context Context under which the idempotency key is generated.
*/
$idempotency_key = apply_filters('wu_stripe_generate_idempotency_key', $idempotency_key, $args, $context);
return $idempotency_key;
} // end wu_stripe_generate_idempotency_key;
/**
* Loops through the signup field types to return the checkout fields.
*
* @since 2.0.0
*
* @param array $fields List of signup field types.
* @return array
*/
function wu_create_checkout_fields($fields = array()) {
$field_types = Signup_Fields_Manager::get_instance()->get_field_types();
$actual_fields = array();
// Extra check to prevent error messages from being displayed.
if (!is_array($fields)) {
$fields = array();
} // end if;
foreach ($fields as $field) {
$type = $field['type'];
if (!wu_get_isset($field_types, $type)) {
continue;
} // end if;
try {
$field_class = new $field_types[$type]();
} catch (\Throwable $exception) {
continue;
} // end try;
$field = wp_parse_args($field, $field_class->defaults());
$field = array_merge($field, $field_class->force_attributes());
/*
* Check Field Visibility
*/
$visibility = wu_get_isset($field, 'logged', 'always');
if ($visibility !== 'always') {
if ($visibility === 'guests_only' && is_user_logged_in()) {
continue;
} // end if;
if ($visibility === 'logged_only' && !is_user_logged_in()) {
continue;
} // end if;
} // end if;
/*
* Pass the attributes down to the field class.
*/
$field_class->set_attributes($field);
/*
* Makes sure we have default indexes.
*/
$field = wp_parse_args($field, array(
'element_classes' => '',
'classes' => '',
));
$field_array = $field_class->to_fields_array($field);
/**
* Fires before a field is added to the checkout form.
*
* @since 2.1.1
* @param array $field_array The field to be inserted.
*/
do_action("wu_checkout_add_field_{$field_class->get_type()}", $field_array);
$actual_fields = array_merge($actual_fields, $field_array);
} // end foreach;
return $actual_fields;
} // end wu_create_checkout_fields;
/**
* Returns the URL for the registration page.
*
* @since 2.0.0
* @param string|false $path Path to attach to the end of the URL.
* @return string
*/
function wu_get_registration_url($path = false) {
$checkout_pages = \WP_Ultimo\Checkout\Checkout_Pages::get_instance();
$url = $checkout_pages->get_page_url('register');
if (!$url) {
/**
* Just to be extra sure, we try to fetch the URL
* for a main site page that has the registration slug.
*/
$url = wu_switch_blog_and_run(function() {
$maybe_register_page = get_page_by_path('register');
if ($maybe_register_page && has_shortcode($maybe_register_page->post_content, 'wu_checkout')) {
return get_the_permalink($maybe_register_page->ID);
}
});
return $url ?? '#no-registration-url';
} // end if;
return $url . $path;
} // end wu_get_registration_url;
/**
* Returns the URL for the login page.
*
* @since 2.0.0
* @param string|false $path Path to attach to the end of the URL.
*/
function wu_get_login_url($path = false): string {
$checkout_pages = \WP_Ultimo\Checkout\Checkout_Pages::get_instance();
$url = $checkout_pages->get_page_url('login');
if (!$url) {
return '#no-login-url';
} // end if;
return $url . $path;
} // end wu_get_login_url;
/**
* Checks if we allow for multiple memberships.
*
* @todo: review this.
* @since 2.0.0
* @return boolean
*/
function wu_multiple_memberships_enabled() {
return wu_get_setting('enable_multiple_memberships', true);
} // end wu_multiple_memberships_enabled;
/**
* Get the number of days in a billing cycle.
*
* Taken from WooCommerce.
*
* @since 2.0.0
* @param string $duration_unit Unit: day, month, or year.
* @param int $duration Cycle duration.
*
* @return int
*/
function wu_get_days_in_cycle($duration_unit, $duration) {
$days_in_cycle = 0;
switch ($duration_unit) {
case 'day':
$days_in_cycle = $duration;
break;
case 'week':
$days_in_cycle = $duration * 7;
break;
case 'month':
$days_in_cycle = $duration * 30.4375;
break;
case 'year':
$days_in_cycle = $duration * 365.25;
break;
default:
$days_in_cycle = $days_in_cycle;
break;
} // end switch;
return $days_in_cycle;
} // end wu_get_days_in_cycle;
/**
* Register a new field type.
*
* Field types are types of field (duh!) that can be
* added to the checkout flow and other forms inside WP Ultimo.
*
* @see https://help.wpultimo.com/article/344-add-custom-field-types-to-wp-ultimo
*
* @since 2.0.0
*
* @param string $field_type_id The field type id. E.g. pricing_table, template_selection.
* @param string $field_type_class_name The field type class name. The "absolute" path to the class.
* @return void
*/
function wu_register_field_type($field_type_id, $field_type_class_name) {
add_filter('wu_checkout_field_types', function($field_types) use ($field_type_id, $field_type_class_name) {
$field_types[$field_type_id] = $field_type_class_name;
return $field_types;
});
} // end wu_register_field_type;
/**
* Register a new field template for a field type.
*
* Field templates are different layouts that can be added to
* WP Ultimo to be used as the final representation of a given
* checkout field.
*
* @see https://help.wpultimo.com/article/343-customize-your-checkout-flow-using-field-templates
*
* @since 2.0.0
*
* @param string $field_type The field type. E.g. pricing_table, template_selection.
* @param string $field_template_id The field template ID. e.g. clean, minimal.
* @param string $field_template_class_name The field template class name. The "absolute" path to the class.
* @return void
*/
function wu_register_field_template($field_type, $field_template_id, $field_template_class_name) {
add_filter('wu_checkout_field_templates', function($field_templates) use ($field_type, $field_template_id, $field_template_class_name) {
$field_templates_for_field_type = wu_get_isset($field_templates, $field_type, array());
$field_templates_for_field_type[$field_template_id] = $field_template_class_name;
$field_templates[$field_type] = $field_templates_for_field_type;
return $field_templates;
});
} // end wu_register_field_template;

65
inc/functions/color.php Normal file
View File

@ -0,0 +1,65 @@
<?php
/**
* Color Functions
*
* Uses the Mexitek\PHPColors\Color class as a basis.
*
* @see https://github.com/mexitek/phpColors
* @see http://mexitek.github.io/phpColors/
*
* @package WP_Ultimo\Functions
* @since 2.0.0
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
use \WP_Ultimo\Dependencies\Mexitek\PHPColors\Color;
/**
* Returns a Color object.
*
* @since 2.0.0
*
* @param string $hex Hex code for the color. E.g. #000.
* @return \WP_Ultimo\Dependencies\Mexitek\PHPColors\Color
*/
function wu_color($hex) {
try {
$color = new Color($hex);
} catch (Exception $exception) {
$color = new Color('#f9f9f9');
} // end try;
return $color;
} // end wu_color;
/**
* Gets a random color for the progress bar.
*
* @since 2.0.0
*
* @param int $index The index number.
* @return string
*/
function wu_get_random_color($index) {
$colors = array(
'wu-bg-red-500',
'wu-bg-green-500',
'wu-bg-blue-500',
'wu-bg-yellow-500',
'wu-bg-orange-500',
'wu-bg-purple-500',
'wu-bg-pink-500',
);
return wu_get_isset($colors, $index, $colors[ rand(0, count($colors) - 1) ]);
} // end wu_get_random_color;

546
inc/functions/countries.php Normal file
View File

@ -0,0 +1,546 @@
<?php
/**
* Country Functions
*
* @package WP_Ultimo\Functions
* @since 2.0.0
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Returns the list of countries.
*
* @since 2.0.0
* @return array
*/
function wu_get_countries() {
return apply_filters('wu_get_countries', array(
'AF' => __('Afghanistan', 'wp-ultimo-locations'),
'AX' => __('&#197;land Islands', 'wp-ultimo-locations'),
'AL' => __('Albania', 'wp-ultimo-locations'),
'DZ' => __('Algeria', 'wp-ultimo-locations'),
'AS' => __('American Samoa', 'wp-ultimo-locations'),
'AD' => __('Andorra', 'wp-ultimo-locations'),
'AO' => __('Angola', 'wp-ultimo-locations'),
'AI' => __('Anguilla', 'wp-ultimo-locations'),
'AQ' => __('Antarctica', 'wp-ultimo-locations'),
'AG' => __('Antigua and Barbuda', 'wp-ultimo-locations'),
'AR' => __('Argentina', 'wp-ultimo-locations'),
'AM' => __('Armenia', 'wp-ultimo-locations'),
'AW' => __('Aruba', 'wp-ultimo-locations'),
'AU' => __('Australia', 'wp-ultimo-locations'),
'AT' => __('Austria', 'wp-ultimo-locations'),
'AZ' => __('Azerbaijan', 'wp-ultimo-locations'),
'BS' => __('Bahamas', 'wp-ultimo-locations'),
'BH' => __('Bahrain', 'wp-ultimo-locations'),
'BD' => __('Bangladesh', 'wp-ultimo-locations'),
'BB' => __('Barbados', 'wp-ultimo-locations'),
'BY' => __('Belarus', 'wp-ultimo-locations'),
'BE' => __('Belgium', 'wp-ultimo-locations'),
'PW' => __('Belau', 'wp-ultimo-locations'),
'BZ' => __('Belize', 'wp-ultimo-locations'),
'BJ' => __('Benin', 'wp-ultimo-locations'),
'BM' => __('Bermuda', 'wp-ultimo-locations'),
'BT' => __('Bhutan', 'wp-ultimo-locations'),
'BO' => __('Bolivia', 'wp-ultimo-locations'),
'BQ' => __('Bonaire, Saint Eustatius and Saba', 'wp-ultimo-locations'),
'BA' => __('Bosnia and Herzegovina', 'wp-ultimo-locations'),
'BW' => __('Botswana', 'wp-ultimo-locations'),
'BV' => __('Bouvet Island', 'wp-ultimo-locations'),
'BR' => __('Brazil', 'wp-ultimo-locations'),
'IO' => __('British Indian Ocean Territory', 'wp-ultimo-locations'),
'VG' => __('British Virgin Islands', 'wp-ultimo-locations'),
'BN' => __('Brunei', 'wp-ultimo-locations'),
'BG' => __('Bulgaria', 'wp-ultimo-locations'),
'BF' => __('Burkina Faso', 'wp-ultimo-locations'),
'BI' => __('Burundi', 'wp-ultimo-locations'),
'KH' => __('Cambodia', 'wp-ultimo-locations'),
'CM' => __('Cameroon', 'wp-ultimo-locations'),
'CA' => __('Canada', 'wp-ultimo-locations'),
'CV' => __('Cape Verde', 'wp-ultimo-locations'),
'KY' => __('Cayman Islands', 'wp-ultimo-locations'),
'CF' => __('Central African Republic', 'wp-ultimo-locations'),
'TD' => __('Chad', 'wp-ultimo-locations'),
'CL' => __('Chile', 'wp-ultimo-locations'),
'CN' => __('China', 'wp-ultimo-locations'),
'CX' => __('Christmas Island', 'wp-ultimo-locations'),
'CC' => __('Cocos (Keeling) Islands', 'wp-ultimo-locations'),
'CO' => __('Colombia', 'wp-ultimo-locations'),
'KM' => __('Comoros', 'wp-ultimo-locations'),
'CG' => __('Congo (Brazzaville)', 'wp-ultimo-locations'),
'CD' => __('Congo (Kinshasa)', 'wp-ultimo-locations'),
'CK' => __('Cook Islands', 'wp-ultimo-locations'),
'CR' => __('Costa Rica', 'wp-ultimo-locations'),
'HR' => __('Croatia', 'wp-ultimo-locations'),
'CU' => __('Cuba', 'wp-ultimo-locations'),
'CW' => __('Cura&ccedil;ao', 'wp-ultimo-locations'),
'CY' => __('Cyprus', 'wp-ultimo-locations'),
'CZ' => __('Czech Republic', 'wp-ultimo-locations'),
'DK' => __('Denmark', 'wp-ultimo-locations'),
'DJ' => __('Djibouti', 'wp-ultimo-locations'),
'DM' => __('Dominica', 'wp-ultimo-locations'),
'DO' => __('Dominican Republic', 'wp-ultimo-locations'),
'EC' => __('Ecuador', 'wp-ultimo-locations'),
'EG' => __('Egypt', 'wp-ultimo-locations'),
'SV' => __('El Salvador', 'wp-ultimo-locations'),
'GQ' => __('Equatorial Guinea', 'wp-ultimo-locations'),
'ER' => __('Eritrea', 'wp-ultimo-locations'),
'EE' => __('Estonia', 'wp-ultimo-locations'),
'ET' => __('Ethiopia', 'wp-ultimo-locations'),
'FK' => __('Falkland Islands', 'wp-ultimo-locations'),
'FO' => __('Faroe Islands', 'wp-ultimo-locations'),
'FJ' => __('Fiji', 'wp-ultimo-locations'),
'FI' => __('Finland', 'wp-ultimo-locations'),
'FR' => __('France', 'wp-ultimo-locations'),
'GF' => __('French Guiana', 'wp-ultimo-locations'),
'PF' => __('French Polynesia', 'wp-ultimo-locations'),
'TF' => __('French Southern Territories', 'wp-ultimo-locations'),
'GA' => __('Gabon', 'wp-ultimo-locations'),
'GM' => __('Gambia', 'wp-ultimo-locations'),
'GE' => __('Georgia', 'wp-ultimo-locations'),
'DE' => __('Germany', 'wp-ultimo-locations'),
'GH' => __('Ghana', 'wp-ultimo-locations'),
'GI' => __('Gibraltar', 'wp-ultimo-locations'),
'GR' => __('Greece', 'wp-ultimo-locations'),
'GL' => __('Greenland', 'wp-ultimo-locations'),
'GD' => __('Grenada', 'wp-ultimo-locations'),
'GP' => __('Guadeloupe', 'wp-ultimo-locations'),
'GU' => __('Guam', 'wp-ultimo-locations'),
'GT' => __('Guatemala', 'wp-ultimo-locations'),
'GG' => __('Guernsey', 'wp-ultimo-locations'),
'GN' => __('Guinea', 'wp-ultimo-locations'),
'GW' => __('Guinea-Bissau', 'wp-ultimo-locations'),
'GY' => __('Guyana', 'wp-ultimo-locations'),
'HT' => __('Haiti', 'wp-ultimo-locations'),
'HM' => __('Heard Island and McDonald Islands', 'wp-ultimo-locations'),
'HN' => __('Honduras', 'wp-ultimo-locations'),
'HK' => __('Hong Kong', 'wp-ultimo-locations'),
'HU' => __('Hungary', 'wp-ultimo-locations'),
'IS' => __('Iceland', 'wp-ultimo-locations'),
'IN' => __('India', 'wp-ultimo-locations'),
'ID' => __('Indonesia', 'wp-ultimo-locations'),
'IR' => __('Iran', 'wp-ultimo-locations'),
'IQ' => __('Iraq', 'wp-ultimo-locations'),
'IE' => __('Ireland', 'wp-ultimo-locations'),
'IM' => __('Isle of Man', 'wp-ultimo-locations'),
'IL' => __('Israel', 'wp-ultimo-locations'),
'IT' => __('Italy', 'wp-ultimo-locations'),
'CI' => __('Ivory Coast', 'wp-ultimo-locations'),
'JM' => __('Jamaica', 'wp-ultimo-locations'),
'JP' => __('Japan', 'wp-ultimo-locations'),
'JE' => __('Jersey', 'wp-ultimo-locations'),
'JO' => __('Jordan', 'wp-ultimo-locations'),
'KZ' => __('Kazakhstan', 'wp-ultimo-locations'),
'KE' => __('Kenya', 'wp-ultimo-locations'),
'KI' => __('Kiribati', 'wp-ultimo-locations'),
'KW' => __('Kuwait', 'wp-ultimo-locations'),
'KG' => __('Kyrgyzstan', 'wp-ultimo-locations'),
'LA' => __('Laos', 'wp-ultimo-locations'),
'LV' => __('Latvia', 'wp-ultimo-locations'),
'LB' => __('Lebanon', 'wp-ultimo-locations'),
'LS' => __('Lesotho', 'wp-ultimo-locations'),
'LR' => __('Liberia', 'wp-ultimo-locations'),
'LY' => __('Libya', 'wp-ultimo-locations'),
'LI' => __('Liechtenstein', 'wp-ultimo-locations'),
'LT' => __('Lithuania', 'wp-ultimo-locations'),
'LU' => __('Luxembourg', 'wp-ultimo-locations'),
'MO' => __('Macao S.A.R., China', 'wp-ultimo-locations'),
'MK' => __('Macedonia', 'wp-ultimo-locations'),
'MG' => __('Madagascar', 'wp-ultimo-locations'),
'MW' => __('Malawi', 'wp-ultimo-locations'),
'MY' => __('Malaysia', 'wp-ultimo-locations'),
'MV' => __('Maldives', 'wp-ultimo-locations'),
'ML' => __('Mali', 'wp-ultimo-locations'),
'MT' => __('Malta', 'wp-ultimo-locations'),
'MH' => __('Marshall Islands', 'wp-ultimo-locations'),
'MQ' => __('Martinique', 'wp-ultimo-locations'),
'MR' => __('Mauritania', 'wp-ultimo-locations'),
'MU' => __('Mauritius', 'wp-ultimo-locations'),
'YT' => __('Mayotte', 'wp-ultimo-locations'),
'MX' => __('Mexico', 'wp-ultimo-locations'),
'FM' => __('Micronesia', 'wp-ultimo-locations'),
'MD' => __('Moldova', 'wp-ultimo-locations'),
'MC' => __('Monaco', 'wp-ultimo-locations'),
'MN' => __('Mongolia', 'wp-ultimo-locations'),
'ME' => __('Montenegro', 'wp-ultimo-locations'),
'MS' => __('Montserrat', 'wp-ultimo-locations'),
'MA' => __('Morocco', 'wp-ultimo-locations'),
'MZ' => __('Mozambique', 'wp-ultimo-locations'),
'MM' => __('Myanmar', 'wp-ultimo-locations'),
'NA' => __('Namibia', 'wp-ultimo-locations'),
'NR' => __('Nauru', 'wp-ultimo-locations'),
'NP' => __('Nepal', 'wp-ultimo-locations'),
'NL' => __('Netherlands', 'wp-ultimo-locations'),
'NC' => __('New Caledonia', 'wp-ultimo-locations'),
'NZ' => __('New Zealand', 'wp-ultimo-locations'),
'NI' => __('Nicaragua', 'wp-ultimo-locations'),
'NE' => __('Niger', 'wp-ultimo-locations'),
'NG' => __('Nigeria', 'wp-ultimo-locations'),
'NU' => __('Niue', 'wp-ultimo-locations'),
'NF' => __('Norfolk Island', 'wp-ultimo-locations'),
'MP' => __('Northern Mariana Islands', 'wp-ultimo-locations'),
'KP' => __('North Korea', 'wp-ultimo-locations'),
'NO' => __('Norway', 'wp-ultimo-locations'),
'OM' => __('Oman', 'wp-ultimo-locations'),
'PK' => __('Pakistan', 'wp-ultimo-locations'),
'PS' => __('Palestinian Territory', 'wp-ultimo-locations'),
'PA' => __('Panama', 'wp-ultimo-locations'),
'PG' => __('Papua New Guinea', 'wp-ultimo-locations'),
'PY' => __('Paraguay', 'wp-ultimo-locations'),
'PE' => __('Peru', 'wp-ultimo-locations'),
'PH' => __('Philippines', 'wp-ultimo-locations'),
'PN' => __('Pitcairn', 'wp-ultimo-locations'),
'PL' => __('Poland', 'wp-ultimo-locations'),
'PT' => __('Portugal', 'wp-ultimo-locations'),
'PR' => __('Puerto Rico', 'wp-ultimo-locations'),
'QA' => __('Qatar', 'wp-ultimo-locations'),
'RE' => __('Reunion', 'wp-ultimo-locations'),
'RO' => __('Romania', 'wp-ultimo-locations'),
'RU' => __('Russia', 'wp-ultimo-locations'),
'RW' => __('Rwanda', 'wp-ultimo-locations'),
'BL' => __('Saint Barth&eacute;lemy', 'wp-ultimo-locations'),
'SH' => __('Saint Helena', 'wp-ultimo-locations'),
'KN' => __('Saint Kitts and Nevis', 'wp-ultimo-locations'),
'LC' => __('Saint Lucia', 'wp-ultimo-locations'),
'MF' => __('Saint Martin (French part)', 'wp-ultimo-locations'),
'SX' => __('Saint Martin (Dutch part)', 'wp-ultimo-locations'),
'PM' => __('Saint Pierre and Miquelon', 'wp-ultimo-locations'),
'VC' => __('Saint Vincent and the Grenadines', 'wp-ultimo-locations'),
'SM' => __('San Marino', 'wp-ultimo-locations'),
'ST' => __('S&atilde;o Tom&eacute; and Pr&iacute;ncipe', 'wp-ultimo-locations'),
'SA' => __('Saudi Arabia', 'wp-ultimo-locations'),
'SN' => __('Senegal', 'wp-ultimo-locations'),
'RS' => __('Serbia', 'wp-ultimo-locations'),
'SC' => __('Seychelles', 'wp-ultimo-locations'),
'SL' => __('Sierra Leone', 'wp-ultimo-locations'),
'SG' => __('Singapore', 'wp-ultimo-locations'),
'SK' => __('Slovakia', 'wp-ultimo-locations'),
'SI' => __('Slovenia', 'wp-ultimo-locations'),
'SB' => __('Solomon Islands', 'wp-ultimo-locations'),
'SO' => __('Somalia', 'wp-ultimo-locations'),
'ZA' => __('South Africa', 'wp-ultimo-locations'),
'GS' => __('South Georgia/Sandwich Islands', 'wp-ultimo-locations'),
'KR' => __('South Korea', 'wp-ultimo-locations'),
'SS' => __('South Sudan', 'wp-ultimo-locations'),
'ES' => __('Spain', 'wp-ultimo-locations'),
'LK' => __('Sri Lanka', 'wp-ultimo-locations'),
'SD' => __('Sudan', 'wp-ultimo-locations'),
'SR' => __('Suriname', 'wp-ultimo-locations'),
'SJ' => __('Svalbard and Jan Mayen', 'wp-ultimo-locations'),
'SZ' => __('Swaziland', 'wp-ultimo-locations'),
'SE' => __('Sweden', 'wp-ultimo-locations'),
'CH' => __('Switzerland', 'wp-ultimo-locations'),
'SY' => __('Syria', 'wp-ultimo-locations'),
'TW' => __('Taiwan', 'wp-ultimo-locations'),
'TJ' => __('Tajikistan', 'wp-ultimo-locations'),
'TZ' => __('Tanzania', 'wp-ultimo-locations'),
'TH' => __('Thailand', 'wp-ultimo-locations'),
'TL' => __('Timor-Leste', 'wp-ultimo-locations'),
'TG' => __('Togo', 'wp-ultimo-locations'),
'TK' => __('Tokelau', 'wp-ultimo-locations'),
'TO' => __('Tonga', 'wp-ultimo-locations'),
'TT' => __('Trinidad and Tobago', 'wp-ultimo-locations'),
'TN' => __('Tunisia', 'wp-ultimo-locations'),
'TR' => __('Turkey', 'wp-ultimo-locations'),
'TM' => __('Turkmenistan', 'wp-ultimo-locations'),
'TC' => __('Turks and Caicos Islands', 'wp-ultimo-locations'),
'TV' => __('Tuvalu', 'wp-ultimo-locations'),
'UG' => __('Uganda', 'wp-ultimo-locations'),
'UA' => __('Ukraine', 'wp-ultimo-locations'),
'AE' => __('United Arab Emirates', 'wp-ultimo-locations'),
'GB' => __('United Kingdom (UK)', 'wp-ultimo-locations'),
'US' => __('United States (US)', 'wp-ultimo-locations'),
'UM' => __('United States (US) Minor Outlying Islands', 'wp-ultimo-locations'),
'VI' => __('United States (US) Virgin Islands', 'wp-ultimo-locations'),
'UY' => __('Uruguay', 'wp-ultimo-locations'),
'UZ' => __('Uzbekistan', 'wp-ultimo-locations'),
'VU' => __('Vanuatu', 'wp-ultimo-locations'),
'VA' => __('Vatican', 'wp-ultimo-locations'),
'VE' => __('Venezuela', 'wp-ultimo-locations'),
'VN' => __('Vietnam', 'wp-ultimo-locations'),
'WF' => __('Wallis and Futuna', 'wp-ultimo-locations'),
'EH' => __('Western Sahara', 'wp-ultimo-locations'),
'WS' => __('Samoa', 'wp-ultimo-locations'),
'YE' => __('Yemen', 'wp-ultimo-locations'),
'ZM' => __('Zambia', 'wp-ultimo-locations'),
'ZW' => __('Zimbabwe', 'wp-ultimo-locations'),
));
} // end wu_get_countries;
/**
* Returns the list of countries with an additional empty state option.
*
* @since 2.0.0
* @return array
*/
function wu_get_countries_as_options() {
return array_merge(array(
'' => __('Select Country', 'wp-ultimo'),
), wu_get_countries());
} // end wu_get_countries_as_options;
/**
* Returns the country object.
*
* @since 2.0.11
*
* @param string $country_code Two-letter country ISO code.
* @param string|null $name The country name.
* @param array $fallback_attributes Fallback attributes if the country class is not present.
* @return \WP_Ultimo\Country\Country
*/
function wu_get_country($country_code, $name = null, $fallback_attributes = array()) {
$country_code = strtoupper($country_code);
$country_class = "\\WP_Ultimo\\Country\\Country_{$country_code}";
if (class_exists($country_class)) {
return $country_class::get_instance();
} // end if;
return \WP_Ultimo\Country\Country_Default::build($country_code, $name, $fallback_attributes);
} // end wu_get_country;
/**
* Get the state list for a country.
*
* @since 2.0.12
*
* @param string $country_code The country code.
* @param string $key_name The name to use for the key entry.
* @param string $value_name The name to use for the value entry.
* @return array
*/
function wu_get_country_states($country_code, $key_name = 'id', $value_name = 'value') {
static $state_options = array();
$options = array();
$cache = wu_get_isset($state_options, $country_code, false);
if ($cache) {
$options = $cache;
} else {
$country = wu_get_country($country_code);
$state_options[$country_code] = $country->get_states_as_options(false);
$options = $state_options[$country_code];
} // end if;
if (empty($key_name)) {
return $options;
} // end if;
return wu_key_map_to_array($options, $key_name, $value_name);
} // end wu_get_country_states;
/**
* Get cities for a collection of states of a country.
*
* @since 2.0.11
*
* @param string $country_code The country code.
* @param array $states The list of state codes to retrieve.
* @param string $key_name The name to use for the key entry.
* @param string $value_name The name to use for the value entry.
* @return array
*/
function wu_get_country_cities($country_code, $states, $key_name = 'id', $value_name = 'value') {
static $city_options = array();
$states = (array) $states;
$options = array();
foreach ($states as $state_code) {
$cache = wu_get_isset($city_options, $state_code, false);
if ($cache) {
$options = array_merge($options, $cache);
} else {
$country = wu_get_country($country_code);
$city_options[$state_code] = $country->get_cities_as_options($state_code, false);
$options = array_merge($options, $city_options[$state_code]);
} // end if;
} // end foreach;
if (empty($key_name)) {
return $options;
} // end if;
return wu_key_map_to_array($options, $key_name, $value_name);
} // end wu_get_country_cities;
/**
* Returns the country name for a given country code.
*
* @since 2.0.0
*
* @param string $country_code Country code.
* @return string
*/
function wu_get_country_name($country_code) {
$country_name = wu_get_isset(wu_get_countries(), $country_code, __('Not found', 'wp-ultimo'));
return apply_filters('wu_get_country_name', $country_name, $country_code);
} // end wu_get_country_name;
/**
* Get the list of countries and counts based on customers.
*
* @since 2.0.0
* @param integer $count The number of results to return.
* @param boolean|string $start_date The start date.
* @param boolean|string $end_date The end date.
* @return array
*/
function wu_get_countries_of_customers($count = 10, $start_date = false, $end_date = false) {
global $wpdb;
$table_name = "{$wpdb->base_prefix}wu_customermeta";
$customer_table_name = "{$wpdb->base_prefix}wu_customers";
$date_query = '';
if ($start_date || $end_date) {
$date_query = 'AND c.date_registered >= %s AND c.date_registered <= %s';
$date_query = $wpdb->prepare($date_query, $start_date . ' 00:00:00', $end_date . " 23:59:59"); // phpcs:ignore
} // end if;
$query = "
SELECT m.meta_value as country, COUNT(distinct c.id) as count
FROM `{$table_name}` as m
INNER JOIN `{$customer_table_name}` as c ON m.wu_customer_id = c.id
WHERE m.meta_key = 'ip_country' AND m.meta_value != ''
$date_query
GROUP BY m.meta_value
ORDER BY count DESC
LIMIT %d
";
$query = $wpdb->prepare($query, $count); // phpcs:ignore
$results = $wpdb->get_results($query); // phpcs:ignore
$countries = array();
foreach ($results as $result) {
$countries[$result->country] = $result->count;
} // end foreach;
return $countries;
} // end wu_get_countries_of_customers;
/**
* Get the list of countries and counts based on customers.
*
* @since 2.0.0
* @param string $country_code The country code.
* @param integer $count The number of results to return.
* @param boolean|string $start_date The start date.
* @param boolean|string $end_date The end date.
* @return array
*/
function wu_get_states_of_customers($country_code, $count = 100, $start_date = false, $end_date = false) {
global $wpdb;
static $states = array();
$table_name = "{$wpdb->base_prefix}wu_customermeta";
$customer_table_name = "{$wpdb->base_prefix}wu_customers";
$date_query = '';
if ($start_date || $end_date) {
$date_query = 'AND c.date_registered >= %s AND c.date_registered <= %s';
$date_query = $wpdb->prepare($date_query, $start_date . ' 00:00:00', $end_date . " 23:59:59"); // phpcs:ignore
} // end if;
$states = wu_get_country_states('BR', false);
if (empty($states)) {
return array();
} // end if;
$states_in = implode("','", array_keys($states));
$query = "
SELECT m.meta_value as state, COUNT(distinct c.id) as count
FROM `{$table_name}` as m
INNER JOIN `{$customer_table_name}` as c ON m.wu_customer_id = c.id
WHERE m.meta_key = 'ip_state' AND m.meta_value IN ('$states_in')
$date_query
GROUP BY m.meta_value
ORDER BY count DESC
LIMIT %d
";
$query = $wpdb->prepare($query, $count); // phpcs:ignore
$results = $wpdb->get_results($query); // phpcs:ignore
if (empty($results)) {
return array();
} // end if;
$_states = array();
foreach ($results as $result) {
$final_label = sprintf('%s (%s)', $states[$result->state], $result->state);
$_states[$final_label] = absint($result->count);
} // end foreach;
return $_states;
} // end wu_get_states_of_customers;

342
inc/functions/currency.php Normal file
View File

@ -0,0 +1,342 @@
<?php
/**
* Country Functions
*
* @package WP_Ultimo\Functions
* @since 1.4.0
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Get all the currencies we use in WP Ultimo
*
* @return array Return the currencies array.
*/
function wu_get_currencies(): array {
$currencies = apply_filters('wu_currencies', array(
'AED' => __('United Arab Emirates Dirham', 'wp-ultimo'),
'ARS' => __('Argentine Peso', 'wp-ultimo'),
'AUD' => __('Australian Dollars', 'wp-ultimo'),
'BDT' => __('Bangladeshi Taka', 'wp-ultimo'),
'BRL' => __('Brazilian Real', 'wp-ultimo'),
'BGN' => __('Bulgarian Lev', 'wp-ultimo'),
'CAD' => __('Canadian Dollars', 'wp-ultimo'),
'CLP' => __('Chilean Peso', 'wp-ultimo'),
'CNY' => __('Chinese Yuan', 'wp-ultimo'),
'COP' => __('Colombian Peso', 'wp-ultimo'),
'CZK' => __('Czech Koruna', 'wp-ultimo'),
'DKK' => __('Danish Krone', 'wp-ultimo'),
'DOP' => __('Dominican Peso', 'wp-ultimo'),
'EUR' => __('Euros', 'wp-ultimo'),
'HKD' => __('Hong Kong Dollar', 'wp-ultimo'),
'HRK' => __('Croatia kuna', 'wp-ultimo'),
'HUF' => __('Hungarian Forint', 'wp-ultimo'),
'ISK' => __('Icelandic krona', 'wp-ultimo'),
'IDR' => __('Indonesia Rupiah', 'wp-ultimo'),
'INR' => __('Indian Rupee', 'wp-ultimo'),
'NPR' => __('Nepali Rupee', 'wp-ultimo'),
'ILS' => __('Israeli Shekel', 'wp-ultimo'),
'JPY' => __('Japanese Yen', 'wp-ultimo'),
'KES' => __('Kenyan Shilling', 'wp-ultimo'),
'KIP' => __('Lao Kip', 'wp-ultimo'),
'KRW' => __('South Korean Won', 'wp-ultimo'),
'MYR' => __('Malaysian Ringgits', 'wp-ultimo'),
'MXN' => __('Mexican Peso', 'wp-ultimo'),
'NGN' => __('Nigerian Naira', 'wp-ultimo'),
'NOK' => __('Norwegian Krone', 'wp-ultimo'),
'NZD' => __('New Zealand Dollar', 'wp-ultimo'),
'PYG' => __('Paraguayan Guaraní', 'wp-ultimo'),
'PHP' => __('Philippine Pesos', 'wp-ultimo'),
'PLN' => __('Polish Zloty', 'wp-ultimo'),
'GBP' => __('Pounds Sterling', 'wp-ultimo'),
'RON' => __('Romanian Leu', 'wp-ultimo'),
'RUB' => __('Russian Ruble', 'wp-ultimo'),
'SGD' => __('Singapore Dollar', 'wp-ultimo'),
'ZAR' => __('South African rand', 'wp-ultimo'),
'SAR' => __('Saudi Riyal', 'wp-ultimo'),
'SEK' => __('Swedish Krona', 'wp-ultimo'),
'CHF' => __('Swiss Franc', 'wp-ultimo'),
'TWD' => __('Taiwan New Dollars', 'wp-ultimo'),
'THB' => __('Thai Baht', 'wp-ultimo'),
'TRY' => __('Turkish Lira', 'wp-ultimo'),
'UAH' => __('Ukrainian Hryvnia', 'wp-ultimo'),
'USD' => __('US Dollars', 'wp-ultimo'),
'VND' => __('Vietnamese Dong', 'wp-ultimo'),
'EGP' => __('Egyptian Pound', 'wp-ultimo'),
));
return array_unique($currencies);
} // end wu_get_currencies;
/**
* Gets the currency symbol of a currency.
*
* @since 0.0.1
*
* @param string $currency Currency to get symbol of.
* @return string
*/
function wu_get_currency_symbol($currency = '') {
if (!$currency) {
$currency = wu_get_setting('currency_symbol');
} switch ($currency) {
case 'AED':
$currency_symbol = 'د.إ';
break;
case 'AUD':
case 'ARS':
case 'CAD':
case 'CLP':
case 'COP':
case 'HKD':
case 'MXN':
case 'NZD':
case 'SGD':
case 'USD':
$currency_symbol = '$';
break;
case 'BDT':
$currency_symbol = '৳&nbsp;';
break;
case 'BGN':
$currency_symbol = 'лв.';
break;
case 'BRL':
$currency_symbol = 'R$';
break;
case 'CHF':
$currency_symbol = 'CHF';
break;
case 'CNY':
case 'JPY':
case 'RMB':
$currency_symbol = '&yen;';
break;
case 'CZK':
$currency_symbol = 'Kč';
break;
case 'DKK':
$currency_symbol = 'DKK';
break;
case 'DOP':
$currency_symbol = 'RD$';
break;
case 'EGP':
$currency_symbol = 'EGP';
break;
case 'EUR':
$currency_symbol = '&euro;';
break;
case 'GBP':
$currency_symbol = '&pound;';
break;
case 'HRK':
$currency_symbol = 'Kn';
break;
case 'HUF':
$currency_symbol = 'Ft';
break;
case 'IDR':
$currency_symbol = 'Rp';
break;
case 'ILS':
$currency_symbol = '₪';
break;
case 'INR':
$currency_symbol = 'Rs.';
break;
case 'ISK':
$currency_symbol = 'Kr.';
break;
case 'KES':
$currency_symbol = 'KSh';
break;
case 'KIP':
$currency_symbol = '₭';
break;
case 'KRW':
$currency_symbol = '₩';
break;
case 'MYR':
$currency_symbol = 'RM';
break;
case 'NGN':
$currency_symbol = '₦';
break;
case 'NOK':
$currency_symbol = 'kr';
break;
case 'NPR':
$currency_symbol = 'Rs.';
break;
case 'PHP':
$currency_symbol = '₱';
break;
case 'PLN':
$currency_symbol = 'zł';
break;
case 'PYG':
$currency_symbol = '₲';
break;
case 'RON':
$currency_symbol = 'lei';
break;
case 'RUB':
$currency_symbol = 'руб.';
break;
case 'SEK':
$currency_symbol = 'kr';
break;
case 'THB':
$currency_symbol = '฿';
break;
case 'TRY':
$currency_symbol = '₺';
break;
case 'TWD':
$currency_symbol = 'NT$';
break;
case 'UAH':
$currency_symbol = '₴';
break;
case 'VND':
$currency_symbol = '₫';
break;
case 'ZAR':
$currency_symbol = 'R';
break;
case 'SAR':
$currency_symbol = 'ر.س';
break;
default:
$currency_symbol = $currency;
break;
} // end switch;
return apply_filters('wu_currency_symbol', $currency_symbol, $currency);
} // end wu_get_currency_symbol;
/**
* Formats a value into our defined format
*
* @param string $value Value to be processed.
* @param string|null $currency Currency code.
* @param string|null $format Format to return the string.
* @param string|null $thousands_sep Thousands separator.
* @param string|null $decimal_sep Decimal separator.
* @param string|null $precision Number of decimal places.
* @return string Formatted Value.
*/
function wu_format_currency($value, $currency = null, $format = null, $thousands_sep = null, $decimal_sep = null, $precision = null) {
$value = wu_to_float($value);
$args = array(
'currency' => $currency,
'format' => $format,
'thousands_sep' => $thousands_sep,
'decimal_sep' => $decimal_sep,
'precision' => $precision,
);
// Remove invalid args
$args = array_filter($args);
$atts = wp_parse_args($args, array(
'currency' => wu_get_setting('currency_symbol'),
'format' => wu_get_setting('currency_position'),
'thousands_sep' => wu_get_setting('thousand_separator'),
'decimal_sep' => wu_get_setting('decimal_separator'),
'precision' => (int) wu_get_setting('precision', 2),
));
$currency_symbol = wu_get_currency_symbol($atts['currency']);
$value = number_format($value, $atts['precision'], $atts['decimal_sep'], $atts['thousands_sep']);
$format = str_replace('%v', $value, (string) $atts['format']);
$format = str_replace('%s', $currency_symbol, $format);
return apply_filters('wu_format_currency', $format, $currency_symbol, $value);
} // end wu_format_currency;
/**
* Determines if WP Ultimo is using a zero-decimal currency.
*
* @param string $currency The currency code to check.
*
* @since 2.0.0
* @return bool True if currency set to a zero-decimal currency.
*/
function wu_is_zero_decimal_currency($currency = 'USD') {
$zero_dec_currencies = array(
'BIF', // Burundian Franc
'CLP', // Chilean Peso
'DJF', // Djiboutian Franc
'GNF', // Guinean Franc
'JPY', // Japanese Yen
'KMF', // Comorian Franc
'KRW', // South Korean Won
'MGA', // Malagasy Ariary
'PYG', // Paraguayan Guarani
'RWF', // Rwandan Franc
'VND', // Vietnamese Dong
'VUV', // Vanuatu Vatu
'XAF', // Central African CFA Franc
'XOF', // West African CFA Franc
'XPF', // CFP Franc
);
return apply_filters('wu_is_zero_decimal_currency', in_array($currency, $zero_dec_currencies, true));
} // end wu_is_zero_decimal_currency;
/**
* Sets the number of decimal places based on the currency.
*
* @param int $decimals The number of decimal places. Default is 2.
*
* @todo add the missing currency parameter?
* @since 2.0.0
* @return int The number of decimal places.
*/
function wu_currency_decimal_filter($decimals = 2) {
$currency = 'USD';
if (wu_is_zero_decimal_currency($currency)) {
$decimals = 0;
} // end if;
return apply_filters('wu_currency_decimal_filter', $decimals, $currency);
} // end wu_currency_decimal_filter;
/**
* Returns the multiplier for the currency. Most currencies are multiplied by 100.
* Zero decimal currencies should not be multiplied so use 1.
*
* @since 2.0.0
*
* @param string $currency The currency code, all uppercase.
* @return int
*/
function wu_stripe_get_currency_multiplier($currency = 'USD') {
$multiplier = (wu_is_zero_decimal_currency($currency)) ? 1 : 100;
return apply_filters('wu_stripe_get_currency_multiplier', $multiplier, $currency);
} // end wu_stripe_get_currency_multiplier;

551
inc/functions/customer.php Normal file
View File

@ -0,0 +1,551 @@
<?php
/**
* Customer Functions
*
* @package WP_Ultimo\Functions
* @since 2.0.0
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
use \WP_Ultimo\Models\Customer;
/**
* Returns a customer.
*
* @since 2.0.0
*
* @param int $customer_id The id of the customer. This is not the user ID.
* @return \WP_Ultimo\Models\Customer|false
*/
function wu_get_customer($customer_id) {
return \WP_Ultimo\Models\Customer::get_by_id($customer_id);
} // end wu_get_customer;
/**
* Returns a single customer defined by a particular column and value.
*
* @since 2.0.0
*
* @param string $column The column name.
* @param mixed $value The column value.
* @return \WP_Ultimo\Models\Customer|false
*/
function wu_get_customer_by($column, $value) {
return \WP_Ultimo\Models\Customer::get_by($column, $value);
} // end wu_get_customer_by;
/**
* Gets a customer based on the hash.
*
* @since 2.0.0
*
* @param mixed $hash The customer hash.
* @return \WP_Ultimo\Models\Customer|false
*/
function wu_get_customer_by_hash($hash) {
return \WP_Ultimo\Models\Customer::get_by_hash($hash);
} // end wu_get_customer_by_hash;
/**
* Queries customers.
*
* @since 2.0.0
*
* @param array $query Query arguments.
* @return \WP_Ultimo\Models\Customer[]
*/
function wu_get_customers($query = array()) {
if (!empty($query['search'])) {
$user_ids = get_users(array(
'blog_id' => 0,
'number' => -1,
'search' => '*' . $query['search'] . '*',
'fields' => 'ids',
));
if (!empty($user_ids)) {
$query['user_id__in'] = $user_ids;
unset($query['search']);
} // end if;
} // end if;
/*
* Force search limit to customers only.
*/
$query['type'] = 'customer';
return \WP_Ultimo\Models\Customer::query($query);
} // end wu_get_customers;
/**
* Returns a customer based on user_id.
*
* @since 2.0.0
*
* @param int $user_id The ID of the WP User associated with that customer.
* @return \WP_Ultimo\Models\Customer|false
*/
function wu_get_customer_by_user_id($user_id) {
return \WP_Ultimo\Models\Customer::get_by('user_id', $user_id);
} // end wu_get_customer_by_user_id;
/**
* Returns the current customer.
*
* @since 2.0.0
* @return \WP_Ultimo\Models\Customer|false
*/
function wu_get_current_customer() {
return wu_get_customer_by_user_id(get_current_user_id());
} // end wu_get_current_customer;
/**
* Creates a new customer.
*
* Check the wp_parse_args below to see what parameters are necessary.
* If the use_id is not passed, we try to create a new WP User.
*
* @since 2.0.0
*
* @param array $customer_data Customer attributes.
* @return \WP_Error|\WP_Ultimo\Models\Customer
*/
function wu_create_customer($customer_data) {
$customer_data = wp_parse_args($customer_data, array(
'user_id' => false,
'email' => false,
'username' => false,
'password' => false,
'vip' => false,
'ip' => false,
'email_verification' => 'none',
'meta' => array(),
'date_registered' => wu_get_current_time('mysql', true),
'date_modified' => wu_get_current_time('mysql', true),
'last_login' => wu_get_current_time('mysql', true),
'signup_form' => 'by-admin',
'billing_address' => array(),
));
$user = get_user_by('email', $customer_data['email']);
if (!$user) {
$user = get_user_by('ID', $customer_data['user_id']);
} // end if;
if (!$user) {
if ($customer_data['password']) {
$user_id = wpmu_create_user($customer_data['username'], $customer_data['password'], $customer_data['email']);
} else {
$user_id = register_new_user($customer_data['username'], $customer_data['email']);
} // end if;
if (is_wp_error($user_id)) {
return $user_id;
} // end if;
if ($user_id === false) {
return new \WP_Error('user', __('We were not able to create a new user with the provided username and email address combination.', 'wp-ultimo'), $customer_data);
} // end if;
} else {
$user_id = $user->ID;
} // end if;
if (!get_userdata($user_id)) {
return new \WP_Error('user_id', __('We were not able to find a user with the given user_id.', 'wp-ultimo'), $customer_data);
} // end if;
$customer = new Customer(array(
'user_id' => $user_id,
'email_verification' => $customer_data['email_verification'],
'meta' => $customer_data['meta'],
'date_registered' => $customer_data['date_registered'],
'signup_form' => $customer_data['signup_form'],
'billing_address' => $customer_data['billing_address'],
'last_login' => $customer_data['last_login'],
'type' => 'customer',
));
$saved = $customer->save();
return is_wp_error($saved) ? $saved : $customer;
} // end wu_create_customer;
/**
* Get the customer meta types available.
*
* Meta types are basically meta data saved onto the customer,
* and custom fields found on every form passed as a parameter.
*
* @since 2.0.11
*
* @param boolean|array $form_slugs The form slugs to search for fields.
* @return array
*/
function wu_get_customer_meta_types($form_slugs = false) {
$meta_keys = array();
$query = array(
'number' => 99999,
);
if (is_array($form_slugs)) {
$query['slug__in'] = (array) $form_slugs;
} // end if;
$forms = wu_get_checkout_forms($query);
foreach ($forms as $form) {
$customer_meta_fields = $form->get_all_meta_fields('customer_meta');
foreach ($customer_meta_fields as $customer_meta_field) {
$meta_keys[$customer_meta_field['id']] = array(
'type' => $customer_meta_field['type'],
'title' => $customer_meta_field['name'],
'description' => wu_get_isset($customer_meta_field, 'description', ''),
'tooltip' => wu_get_isset($customer_meta_field, 'tooltip', ''),
'default' => wu_get_isset($customer_meta_field, 'default', ''),
'id' => wu_get_isset($customer_meta_field, 'id', ''),
'step' => wu_get_isset($customer_meta_field, 'step', ''),
'options' => wu_get_isset($customer_meta_field, 'options', array()),
'form' => $form->get_slug(),
'value' => '',
'exists' => false,
);
} // end foreach;
} // end foreach;
return $meta_keys;
} // end wu_get_customer_meta_types;
/**
* Returns all the meta data keys present on a customer.
*
* @since 2.0.11
*
* @param int $customer_id The customer id.
* @param boolean $include_unset If we should include fields that exist but are not set
* for this particular customer.
* @return array
*/
function wu_get_all_customer_meta($customer_id, $include_unset = true) {
$all_meta = array();
$customer = wu_get_customer($customer_id);
if ($include_unset) {
$form_slugs = $customer ? array($customer->get_signup_form()) : false;
$all_meta = array_merge($all_meta, wu_get_customer_meta_types($form_slugs));
} // end if;
if (!$customer) {
return $all_meta;
} // end if;
$meta_keys = $customer->get_meta('wu_custom_meta_keys');
if ($meta_keys) {
$meta_keys = array_map(function($item) {
$item['exists'] = true;
return $item;
}, $meta_keys);
$all_meta = wu_array_merge_recursive_distinct($all_meta, $meta_keys);
} // end if;
return $all_meta;
} // end wu_get_all_customer_meta;
/**
* Returns a customer meta.
*
* @since 2.0.11
*
* @param int $customer_id The local (wu) customer id.
* @param string $meta_key The key to use on meta value.
* @param bool $default The default value to be passed.
* @param bool $single To return single values or not.
* @return mixed
*/
function wu_get_customer_meta($customer_id, $meta_key, $default = false, $single = true) {
$customer = wu_get_customer($customer_id);
if (!$customer) {
return $default;
} // end if;
return $customer->get_meta($meta_key, $default, $single);
} // end wu_get_customer_meta;
/**
* Updates a customer meta.
*
* @since 2.0.11
*
* @param int $customer_id The local (wu) customer id.
* @param string $key The key to use on meta value.
* @param mixed $value The new meta value.
* @param string $type The data type.
* @param string $title The data title.
* @return int|bool The new meta field ID if a field with the given
* key didn't exist and was therefore added, true on
* successful update, false if customer did not exist
* or on failure or if the value passed to the function
* is the same as the one that is already in the database.
*/
function wu_update_customer_meta($customer_id, $key, $value, $type = null, $title = null) {
$customer = wu_get_customer($customer_id);
if (!$customer) {
return false;
} // end if;
if ($type) {
$custom_keys = $customer->get_meta('wu_custom_meta_keys', array());
$custom_keys = array_merge($custom_keys, array(
$key => array(
'type' => $type,
'title' => $title,
),
));
$customer->update_meta('wu_custom_meta_keys', $custom_keys);
} // end if;
return $customer->update_meta($key, $value);
} // end wu_update_customer_meta;
/**
* Deletes a customer meta with a custom type field.
*
* @since 2.0.11
*
* @param int $customer_id The local (wu) customer id.
* @param string $meta_key The key to use on meta value.
* @return bool
*/
function wu_delete_customer_meta($customer_id, $meta_key) {
$customer = wu_get_customer($customer_id);
if (!$customer) {
return false;
} // end if;
$custom_keys = $customer->get_meta('wu_custom_meta_keys', array());
if (isset($custom_keys[$meta_key])) {
unset($custom_keys[$meta_key]);
$customer->update_meta('wu_custom_meta_keys', $custom_keys);
} // end if;
return (bool) $customer->delete_meta($meta_key);
} // end wu_delete_customer_meta;
/**
* Searches for a existing gateway customer among the customer memberships.
*
* @since 2.0.0
*
* @param int $customer_id The local (wu) customer id.
* @param array $allowed_gateways The list of allowed gateways to search.
* @return string
*/
function wu_get_customer_gateway_id($customer_id, $allowed_gateways = array()) {
$memberships = wu_get_memberships(array(
'customer_id' => absint($customer_id),
'gateway__in' => $allowed_gateways,
'number' => 1,
'gateway_customer_id__not_in' => array(''),
));
return !empty($memberships) ? $memberships[0]->get_gateway_customer_id() : '';
} // end wu_get_customer_gateway_id;
/**
* Create a unique username for a new customer based on the email address passed.
*
* This is heavily based on the WooCommerce implementation
*
* @see https://github.com/woocommerce/woocommerce/blob/b19500728b4b292562afb65eb3a0c0f50d5859de/includes/wc-user-functions.php#L120
*
* @since 2.0.0
*
* @param string $email New customer email address.
* @param array $new_user_args Array of new user args, maybe including first and last names.
* @param string $suffix Append string to username to make it unique.
* @return string Generated username.
*/
function wu_username_from_email($email, $new_user_args = array(), $suffix = '') {
$username_parts = array();
if (isset($new_user_args['first_name'])) {
$username_parts[] = sanitize_user($new_user_args['first_name'], true);
} // end if;
if (isset($new_user_args['last_name'])) {
$username_parts[] = sanitize_user($new_user_args['last_name'], true);
} // end if;
// Remove empty parts.
$username_parts = array_filter($username_parts);
// If there are no parts, e.g. name had unicode chars, or was not provided, fallback to email.
if (empty($username_parts)) {
$email_parts = explode('@', $email);
$email_username = $email_parts[0];
$common_emails = array(
'sales',
'hello',
'mail',
'contact',
'info',
);
// Exclude common prefixes.
if (in_array($email_username, $common_emails, true)) {
// Get the domain part, minus the dot.
$email_username = strtok($email_parts[1], '.');
} // end if;
$username_parts[] = sanitize_user($email_username, true);
} // end if;
$username = strtolower(implode('', $username_parts));
if ($suffix) {
$username .= $suffix;
} // end if;
$illegal_logins = (array) apply_filters('illegal_user_logins', array()); // phpcs:ignore
// Stop illegal logins and generate a new random username.
if (in_array(strtolower($username), array_map('strtolower', $illegal_logins), true)) {
$new_args = array();
/**
* Filter generated customer username.
*
* @since 3.7.0
* @param string $username Generated username.
* @param string $email New customer email address.
* @param array $new_user_args Array of new user args, maybe including first and last names.
* @param string $suffix Append string to username to make it unique.
*/
$new_args['first_name'] = apply_filters(
'wu_generated_username_from_email',
'woo_user_' . zeroise(wp_rand(0, 9999), 4),
$email,
$new_user_args,
$suffix
);
return wu_username_from_email($email, $new_args, $suffix);
} // end if;
if (username_exists($username)) {
// Generate something unique to append to the username in case of a conflict with another user.
$suffix = '-' . zeroise(wp_rand(0, 9999), 4);
return wu_username_from_email( $email, $new_user_args, $suffix );
} // end if;
/**
* Filter new customer username.
*
* @since 2.0.0
* @param string $username Customer username.
* @param string $email New customer email address.
* @param array $new_user_args Array of new user args, maybe including first and last names.
* @param string $suffix Append string to username to make it unique.
*/
return apply_filters('wu_username_from_email', $username, $email, $new_user_args, $suffix);
} // end wu_username_from_email;

40
inc/functions/danger.php Normal file
View File

@ -0,0 +1,40 @@
<?php
/**
* Danger Database Functions
*
* @package WP_Ultimo\Functions
* @since 2.0.11
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Drop our custom tables.
*
* @since 2.0.0
* @return void
* @throws \Exception In case of failures, an exception is thrown.
*/
function wu_drop_tables() {
$tables = apply_filters('wu_drop_tables', \WP_Ultimo\Loaders\Table_Loader::get_instance()->get_tables());
$except = array(
'blogs',
'blogmeta',
);
$except = apply_filters('wu_drop_tables_except', $except);
foreach ($tables as $table) {
if (!in_array($table->name, $except, true)) {
$table->uninstall();
} // end if;
} // end foreach;
} // end wu_drop_tables;

237
inc/functions/date.php Normal file
View File

@ -0,0 +1,237 @@
<?php
/**
* Date Functions
*
* @package WP_Ultimo\Functions
* @since 2.0.0
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Checks if a date is valid in the Gregorian calendar.
*
* @since 2.0.0
*
* @param string|false|null $date Date to check.
* @param string $format Format to check against.
* @return bool
*/
function wu_validate_date($date, $format = 'Y-m-d H:i:s') {
if (is_null($date)) {
return true;
} elseif (!$date) {
return false;
} // end if;
try {
$d = \DateTime::createFromFormat($format, $date);
} catch (\Throwable $exception) {
return false;
} // end try;
return $d && $d->format($format) === $date;
} // end wu_validate_date;
/**
* Returns a Carbon object to deal with dates in a more compelling way.
*
* Note: this function uses the wu_validate function to check
* if the string passed is a valid date string. If the string
* is not valid, now is used.
*
* @since 2.0.0
* @see https://carbon.nesbot.com/docs/
*
* @param string|false $date Parsable date string.
* @return \WP_Ultimo\Dependencies\Carbon\Carbon
*/
function wu_date($date = false) {
if (!wu_validate_date($date)) {
$date = date_i18n('Y-m-d H:i:s');
} // end if;
return \WP_Ultimo\Dependencies\Carbon\Carbon::parse($date);
} // end wu_date;
/**
* Returns how many days ago the first date was in relation to the second date.
*
* If second date is empty, now is used.
*
* @since 1.7.0
*
* @param string $date_1 First date to compare.
* @param string|false $date_2 Second date to compare.
* @return integer Negative if days ago, positive if days in the future.
*/
function wu_get_days_ago($date_1, $date_2 = false) {
$datetime_1 = wu_date($date_1);
$datetime_2 = wu_date($date_2);
return - $datetime_1->diffInDays($datetime_2, false);
} // end wu_get_days_ago;
/**
* Returns the current time from the network
*
* @param string $type Type of the return string to return.
* @param bool $gmt If the date returned should be GMT or not.
* @return string
*/
function wu_get_current_time($type = 'mysql', $gmt = false) {
switch_to_blog(wu_get_main_site_id());
$time = current_time($type, $gmt); // phpcs:ignore
restore_current_blog();
return $time;
} // end wu_get_current_time;
/**
* Returns a more user friendly version of the duration unit string.
*
* @since 2.0.0
*
* @param string $unit The duration unit string.
* @param int $length The duration.
* @return string
*/
function wu_filter_duration_unit($unit, $length) {
$new_unit = '';
switch ($unit) {
case 'day':
$new_unit = $length > 1 ? __('Days', 'wp-ultimo') : __('Day', 'wp-ultimo');
break;
case 'month':
$new_unit = $length > 1 ? __('Months', 'wp-ultimo') : __('Month', 'wp-ultimo');
break;
case 'year':
$new_unit = $length > 1 ? __('Years', 'wp-ultimo') : __('Year', 'wp-ultimo');
break;
default:
$new_unit = $new_unit;
break;
}
return $new_unit;
} // end wu_filter_duration_unit;
/**
* Get the human time diff.
*
* @since 2.0.0
*
* @param string $from The time to calculate from.
* @param string $limit The limit to switch back to a normal date representation.
* @param string $to The date to compare against.
*/
function wu_human_time_diff($from, $limit = '-5 days', $to = false): string {
$timestamp_from = is_numeric($from) ? $from : strtotime(get_date_from_gmt($from));
$limit = strtotime($limit);
if ($timestamp_from <= $limit) {
// translators: %s: date.
return sprintf(__('on %s', 'wp-ultimo'), date_i18n(get_option('date_format'), $timestamp_from));
} // end if;
if ($to === false) {
$to = wu_get_current_time('timestamp'); // phpcs:ignore
} // end if;
$placeholder = wu_get_current_time('timestamp') > $timestamp_from ? __('%s ago', 'wp-ultimo') : __('In %s', 'wp-ultimo'); // phpcs:ignore
return sprintf($placeholder, human_time_diff($timestamp_from, $to));
} // end wu_human_time_diff;
/**
* Converts php DateTime format to Javascript Moment format.
*
* @since 2.0.10
*
* @param string $php_date_format The PHP date format to convert.
* @return string The moment.js date format
*/
function wu_convert_php_date_format_to_moment_js_format($php_date_format): string {
$replacements = array(
'A' => 'A', // for the sake of escaping below
'a' => 'a', // for the sake of escaping below
'B' => '', // Swatch internet time (.beats), no equivalent
'c' => 'YYYY-MM-DD[T]HH:mm:ssZ', // ISO 8601
'D' => 'ddd',
'd' => 'DD',
'e' => 'zz', // deprecated since version 1.6.0 of moment.js
'F' => 'MMMM',
'G' => 'H',
'g' => 'h',
'H' => 'HH',
'h' => 'hh',
'I' => '', // Daylight Saving Time? => moment().isDST();
'i' => 'mm',
'j' => 'D',
'L' => '', // Leap year? => moment().isLeapYear();
'l' => 'dddd',
'M' => 'MMM',
'm' => 'MM',
'N' => 'E',
'n' => 'M',
'O' => 'ZZ',
'o' => 'YYYY',
'P' => 'Z',
'r' => 'ddd, DD MMM YYYY HH:mm:ss ZZ', // RFC 2822
'S' => 'o',
's' => 'ss',
'T' => 'z', // deprecated since version 1.6.0 of moment.js
't' => '', // days in the month => moment().daysInMonth();
'U' => 'X',
'u' => 'SSSSSS', // microseconds
'v' => 'SSS', // milliseconds (from PHP 7.0.0)
'W' => 'W', // for the sake of escaping below
'w' => 'e',
'Y' => 'YYYY',
'y' => 'YY',
'Z' => '', // time zone offset in minutes => moment().zone();
'z' => 'DDD',
);
// Converts escaped characters.
foreach ($replacements as $from => $to) {
$replacements['\\' . $from] = '[' . $from . ']';
} // end foreach;
return strtr($php_date_format, $replacements);
} // end wu_convert_php_date_format_to_moment_js_format;

44
inc/functions/debug.php Normal file
View File

@ -0,0 +1,44 @@
<?php
/**
* Debug Functions
*
* @package WP_Ultimo\Functions
* @since 2.0.11
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Setup the trap for memory limit, to prevent the default fatal error.
*
* @since 2.0.11
* @return void
*/
function wu_try_unlimited_server_limits() {
// Disable memory_limit by setting it to minus 1.
@ini_set('memory_limit', '-1'); // phpcs:ignore
// Disable the time limit by setting it to 0.
@set_time_limit(0); // phpcs:ignore
} // end wu_try_unlimited_server_limits;
/**
* Custom error handler for memory leaks
*
* @since 2.0.11
* @param string $return_type The return type to echo to the screen.
* 'json', to return json; 'plain' to simply echo the message.
* @return void
*/
function wu_setup_memory_limit_trap($return_type = 'plain') {
$trap = \WP_Ultimo\Internal\Memory_Trap::get_instance();
$trap->set_return_type($return_type);
$trap->setup();
} // end wu_setup_memory_limit_trap;

View File

@ -0,0 +1,118 @@
<?php
/**
* Discount Code Functions
*
* @package WP_Ultimo\Functions
* @since 2.0.0
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
use \WP_Ultimo\Models\Discount_Code;
/**
* Returns a discount code object searching by the code.
*
* @since 2.0.0
*
* @param string $coupon_code Coupon code to search.
* @return \WP_Ultimo\Models\Discount_Code|false
*/
function wu_get_discount_code_by_code($coupon_code) {
return \WP_Ultimo\Models\Discount_Code::get_by('code', $coupon_code);
} // end wu_get_discount_code_by_code;
/**
* Gets a discount code based on the ID.
*
* @since 2.0.0
*
* @param integer $discount_code_id ID of the discount code to retrieve.
* @return \WP_Ultimo\Models\Discount_Code|false
*/
function wu_get_discount_code($discount_code_id) {
return \WP_Ultimo\Models\Discount_Code::get_by_id($discount_code_id);
} // end wu_get_discount_code;
/**
* Queries discount codes.
*
* @since 2.0.0
*
* @param array $query Query arguments.
* @return \WP_Ultimo\Models\Discount_Code[]
*/
function wu_get_discount_codes($query = array()) {
return \WP_Ultimo\Models\Discount_Code::query($query);
} // end wu_get_discount_codes;
/**
* Calculates the discounted price after running it through the discount code.
*
* @since 2.0.0
*
* @param float $base_price Original price of the product.
* @param float $amount Discount amount.
* @param string $type Type of the discount, can be percentage or absolute.
* @param boolean $format If we should format the results or not.
* @return float|string
*/
function wu_get_discounted_price($base_price, $amount, $type, $format = true) {
if ($type === 'percentage') {
$discounted_price = $base_price - ($base_price * ($amount / 100));
} elseif ($type === 'absolute') {
$discounted_price = $base_price - $amount;
} // end if;
if (!$format) {
return $discounted_price;
} // end if;
return number_format((float) $discounted_price, 2);
} // end wu_get_discounted_price;
/**
* Creates a new discount code.
*
* Check the wp_parse_args below to see what parameters are necessary.
*
* @since 2.0.0
*
* @param array $discount_code_data Discount code attributes.
* @return \WP_Error|\WP_Ultimo\Models\Discount_Code
*/
function wu_create_discount_code($discount_code_data) {
$discount_code_data = wp_parse_args($discount_code_data, array(
'max_uses' => true,
'name' => false,
'code' => false,
'value' => false,
'setup_fee_value' => false,
'start_date' => false,
'active' => true,
'expiration_date' => false,
'date_created' => wu_get_current_time('mysql', true),
'date_modified' => wu_get_current_time('mysql', true),
'skip_validation' => false,
));
$discount_code = new Discount_Code($discount_code_data);
$saved = $discount_code->save();
return is_wp_error($saved) ? $saved : $discount_code;
} // end wu_create_discount_code;

View File

@ -0,0 +1,25 @@
<?php
/**
* Documentation Functions
*
* @package WP_Ultimo\Functions
* @since 2.0.11
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Returns the content.
*
* @since 2.0.0
*
* @param string $slug The slug of the link to be returned.
* @param bool $return_default If we should return a default value.
* @return string
*/
function wu_get_documentation_url($slug, $return_default = true) {
return \WP_Ultimo\Documentation::get_instance()->get_link($slug, $return_default);
} // end wu_get_documentation_url;

157
inc/functions/domain.php Normal file
View File

@ -0,0 +1,157 @@
<?php
/**
* Domain Functions
*
* @package WP_Ultimo\Functions
* @since 2.0.0
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
use \WP_Ultimo\Models\Domain;
/**
* Returns a domain.
*
* @since 2.0.0
*
* @param int $domain_id The id of the domain. This is not the user ID.
* @return \WP_Ultimo\Models\Domain|false
*/
function wu_get_domain($domain_id) {
return \WP_Ultimo\Models\Domain::get_by_id($domain_id);
} // end wu_get_domain;
/**
* Queries domains.
*
* @since 2.0.0
*
* @param array $query Query arguments.
* @return \WP_Ultimo\Models\Domain[]
*/
function wu_get_domains($query = array()) {
return \WP_Ultimo\Models\Domain::query($query);
} // end wu_get_domains;
/**
* Returns a domain based on domain.
*
* @since 2.0.0
*
* @param string $domain The domain url.
* @return \WP_Ultimo\Models\Domain|false
*/
function wu_get_domain_by_domain($domain) {
return \WP_Ultimo\Models\Domain::get_by('domain', $domain);
} // end wu_get_domain_by_domain;
/**
* Creates a new domain.
*
* Check the wp_parse_args below to see what parameters are necessary.
*
* @since 2.0.0
*
* @param array $domain_data Domain attributes.
* @return \WP_Error|\WP_Ultimo\Models\Domain
*/
function wu_create_domain($domain_data) {
$domain_data = wp_parse_args($domain_data, array(
'blog_id' => false,
'domain' => false,
'active' => true,
'primary_domain' => false,
'secure' => false,
'stage' => 'checking-dns',
'date_created' => wu_get_current_time('mysql', true),
'date_modified' => wu_get_current_time('mysql', true),
));
$domain = new Domain($domain_data);
$saved = $domain->save();
if (is_wp_error($saved)) {
return $saved;
} // end if;
/*
* Add the processing.
*/
wu_enqueue_async_action('wu_async_process_domain_stage', array('domain_id' => $domain->get_id()), 'domain');
return $domain;
} // end wu_create_domain;
/**
* Restores the original URL for a mapped URL.
*
* @since 2.0.0
*
* @param string $url URL with mapped domain.
* @param int $blog_id The blog ID.
* @return string
*/
function wu_restore_original_url($url, $blog_id) {
$site = wu_get_site($blog_id);
if ($site) {
$original_site_url = $site->get_site_url();
$mapped_domain_url = $site->get_active_site_url();
$original_domain = trim(preg_replace('#^https?://#', '', $original_site_url), '/');
$mapped_domain = wp_parse_url($mapped_domain_url, PHP_URL_HOST);
if ($original_domain !== $mapped_domain) {
$url = str_replace($mapped_domain, $original_domain, $url);
} // end if;
} // end if;
return $url;
} // end wu_restore_original_url;
/**
* Adds the sso tags to a given URL.
*
* @since 2.0.11
*
* @param string $url The base url to sso-fy.
* @return string
*/
function wu_with_sso($url) {
return \WP_Ultimo\SSO\SSO::with_sso($url);
} // end wu_with_sso;
/**
* Compares the current domain to the main network domain.
*
* @since 2.0.11
* @return bool
*/
function wu_is_same_domain() {
global $current_blog, $current_site;
return wp_parse_url(wu_get_current_url(), PHP_URL_HOST) === $current_blog->domain && $current_blog->domain === $current_site->domain;
} // end wu_is_same_domain;

22
inc/functions/element.php Normal file
View File

@ -0,0 +1,22 @@
<?php
/**
* Element Functions
*
* @package WP_Ultimo\Functions
* @since 2.0.5
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Triggers the setup_preview hooks for all registered elements.
*
* @since 2.0.5
* @return void
*/
function wu_element_setup_preview() {
!did_action('wu_element_preview') && do_action('wu_element_preview');
} // end wu_element_setup_preview;

179
inc/functions/email.php Normal file
View File

@ -0,0 +1,179 @@
<?php
/**
* Email Functions
*
* @package WP_Ultimo\Functions
* @since 2.0.0
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
use \WP_Ultimo\Managers\Email_Manager;
use \WP_Ultimo\Models\Email;
use \WP_Ultimo\Helpers\Sender;
/**
* Returns a email.
*
* @since 2.0.0
*
* @param int $email_id The id of the email. This is not the user ID.
* @return Email|false
*/
function wu_get_email($email_id) {
return Email::get_by_id($email_id);
} // end wu_get_email;
/**
* Returns a single email defined by a particular column and value.
*
* @since 2.0.0
*
* @param string $column The column name.
* @param mixed $value The column value.
* @return Email|false
*/
function wu_get_email_by($column, $value) {
return Email::get_by($column, $value);
} // end wu_get_email_by;
/**
* Queries emails.
*
* @since 2.0.0
*
* @param array $query Query arguments.
* @return Email[]
*/
function wu_get_emails($query = array()) {
$query['type__in'] = array('system_email');
if (wu_get_isset($query, 'event')) {
$query['meta_query'] = array(
'event_query' => array(
'key' => 'wu_system_email_event',
'value' => wu_get_isset($query, 'event'),
),
);
} // end if;
return Email::query($query);
} // end wu_get_emails;
/**
* Get all saved system email.
*
* @since 2.0.0
*
* @return array With all system emails.
*/
function wu_get_all_system_emails() {
return Email::query(array(
'status__in' => array('draft', 'publish'),
'type__in' => array('system_email'),
));
} // end wu_get_all_system_emails;
/**
* Get a single or all default registered system emails.
*
* @since 2.0.0
*
* @param string $slug Default system email slug.
* @return array All default system emails.
*/
function wu_get_default_system_emails($slug = '') {
return Email_Manager::get_instance()->get_default_system_emails($slug);
} // end wu_get_default_system_emails;
/**
* Create a single default system email.
*
* @since 2.0.0
*
* @param string $slug Default system email slug to be create.
* @return array
*/
function wu_create_default_system_email($slug) {
$args = wu_get_default_system_emails($slug);
return Email_Manager::get_instance()->create_system_email($args);
} // end wu_create_default_system_email;
/**
* Send an email to one or more users.
*
* @since 2.0.0
*
* @param array $from From whom will be send this mail.
* @param mixed $to To who this email is.
* @param array $args With content, subject and other arguments, has shortcodes, mail type.
* @return array
*/
function wu_send_mail($from = array(), $to = array(), $args = array()) {
return Sender::send_mail($from, $to, $args);
} // end wu_send_mail;
/**
* Returns email-like strings.
*
* E.g.: Robert Smith <robert@rs.org>
*
* @since 2.0.0
*
* @param string $email The email address.
* @param false|string $name The customer/user display name.
* @return string
*/
function wu_format_email_string($email, $name = false) {
return $name ? sprintf('%s <%s>', $name, $email) : $email;
} // end wu_format_email_string;
/**
* Creates a new email.
*
* Check the wp_parse_args below to see what parameters are necessary.
*
* @since 2.0.0
*
* @param array $email_data Email attributes.
* @return \WP_Error|Email
*/
function wu_create_email($email_data) {
$email_data = wp_parse_args($email_data, array(
'type' => 'system_email',
'event' => 'Laborum consectetur',
'title' => 'Lorem Ipsum',
'slug' => 'lorem-ipsum',
'target' => 'admin',
'date_created' => wu_get_current_time('mysql', true),
'date_modified' => wu_get_current_time('mysql', true),
));
$email = new Email($email_data);
$saved = $email->save();
return is_wp_error($saved) ? $saved : $email;
} // end wu_create_email;

39
inc/functions/env.php Normal file
View File

@ -0,0 +1,39 @@
<?php
/**
* Environment Functions
*
* @package WP_Ultimo\Functions
* @since 2.0.11
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Picks content to return depending on the environment.
*
* This is useful when creating layouts that will be used on the front-end as well as
* the backend (admin panel). You can use this function to pick the content to return
* according to the environment. Can be used both for HTML, but is must useful when
* dealing with CSS classes.
*
* E.g. <?php echo wu_env_picker('wu-m-0', 'wu--mx-3 wu--my-2'); ?>
* In the backend, this will return the classes 'wu--mx-3 wu--my-2',
* while it will return wu-m-0 omn the frontend.
*
* Values can be anything, but will usually be strings.
*
* @since 2.0.0
*
* @param mixed $frontend_content Content to return on the frontend.
* @param mixed $backend_content Content to return on the backend.
* @param bool $is_admin You can manually pass the is_admin result, if need be.
* @return mixed
*/
function wu_env_picker($frontend_content, $backend_content, $is_admin = null) {
$is_admin = is_null($is_admin) ? is_admin() : $is_admin;
return $is_admin ? $backend_content : $frontend_content;
} // end wu_env_picker;

360
inc/functions/event.php Normal file
View File

@ -0,0 +1,360 @@
<?php
/**
* Event Functions
*
* @package WP_Ultimo\Functions
* @since 2.0.0
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
use \WP_Ultimo\Managers\Event_Manager;
use \WP_Ultimo\Models\Event;
/**
* Add a new event to the System.
*
* @since 2.0.0
*
* @param string $slug The slug of the event. Something like payment_received.
* @param array $payload defined when the event is registered.
* @return bool
*/
function wu_do_event($slug, $payload) {
return Event_Manager::get_instance()->do_event($slug, $payload);
} // end wu_do_event;
/**
* Register a new event globally in order to set the params.
*
* @since 2.0.0
*
* @param string $slug The slug of the event. Something like payment_received.
* @param array $args defined when the event is registered.
* @return bool
*/
function wu_register_event_type($slug, $args) {
return Event_Manager::get_instance()->register_event($slug, $args);
} // end wu_register_event_type;
/**
* Gets all th events registered in the system
*
* @since 2.0.0
*
* @return array with all events and parameters
*/
function wu_get_event_types() {
return Event_Manager::get_instance()->get_events();
} // end wu_get_event_types;
/**
* Get the available event types as a key => label array.
*
* @since 2.0.0
*
* @return array
*/
function wu_get_event_types_as_options() {
$event_types = Event_Manager::get_instance()->get_events();
foreach ($event_types as $event_type_key => &$event_type) {
$event_type = $event_type['name'];
} // end foreach;
return $event_types;
} // end wu_get_event_types_as_options;
/**
* Gets all th events registered in the system.
*
* @since 2.0.0
*
* @param string $slug of the event.
* @return array with all events and parameters.
*/
function wu_get_event_type($slug) {
return Event_Manager::get_instance()->get_event($slug);
} // end wu_get_event_type;
/**
* Queries events.
*
* @since 2.0.0
*
* @param array $query Query arguments.
* @return \WP_Ultimo\Models\Event[]
*/
function wu_get_events($query = array()) {
return \WP_Ultimo\Models\Event::query($query);
} // end wu_get_events;
/**
* Gets a event on the ID.
*
* @since 2.0.0
*
* @param integer $event_id ID of the event to retrieve.
* @return \WP_Ultimo\Models\Event|false
*/
function wu_get_event($event_id) {
return \WP_Ultimo\Models\Event::get_by_id($event_id);
} // end wu_get_event;
/**
* Returns a event based on slug.
*
* @since 2.0.0
*
* @param string $event_slug The slug of the event.
* @return \WP_Ultimo\Models\Event|false
*/
function wu_get_event_by_slug($event_slug) {
return \WP_Ultimo\Models\Event::get_by('slug', $event_slug);
} // end wu_get_event_by_slug;
/**
* Creates a new event.
*
* Check the wp_parse_args below to see what parameters are necessary.
*
* @since 2.0.0
*
* @param array $event_data Event attributes.
* @return \WP_Error|\WP_Ultimo\Models\Event
*/
function wu_create_event($event_data) {
$author_id = function_exists('get_current_user_id') ? get_current_user_id() : 0;
$event_data = wp_parse_args($event_data, array(
'severity' => Event::SEVERITY_NEUTRAL,
'initiator' => 'system',
'author_id' => $author_id,
'object_type' => 'network',
'object_id' => 0,
'date_created' => wu_get_current_time('mysql', true),
'payload' => array(
'key' => 'None',
'old_value' => 'None',
'new_value' => 'None',
),
));
$event = new Event($event_data);
$saved = $event->save();
return is_wp_error($saved) ? $saved : $event;
} // end wu_create_event;
/**
* Generates payload arrays for events.
*
* If no model is passed, we mock one to generate example payloads!
*
* @since 2.0.0
*
* @param string $model_name Model name. E.g. membership, site, customer, product, etc.
* @param false|object $model The model object, or false.
* @return array
*/
function wu_generate_event_payload($model_name, $model = false): array {
$payload = array();
if (!$model) {
switch ($model_name) {
case 'product':
$model = wu_mock_product();
break;
case 'customer':
$model = wu_mock_customer();
break;
case 'membership':
$model = wu_mock_membership();
break;
case 'payment':
$model = wu_mock_payment();
break;
case 'site':
$model = wu_mock_site();
break;
case 'domain':
$model = wu_mock_domain();
break;
} // end switch;
if (!$model) {
return array();
} // end if;
} // end if;
if ($model_name === 'customer') {
$payload = $model->to_search_results();
$payload = array(
'customer_id' => $payload['id'],
'customer_name' => $payload['display_name'],
'customer_user_id' => $payload['user_id'],
'customer_user_email' => $payload['user_email'],
'customer_email_verification' => $payload['email_verification'],
'customer_avatar' => $payload['avatar'],
'customer_billing_address' => $payload['billing_address'],
'customer_manage_url' => wu_network_admin_url('wp-ultimo-edit-customer', array(
'id' => $model->get_id(),
)),
);
} elseif ($model_name === 'membership') {
$payload = $model->to_search_results();
$p = $payload;
$payload = array(
'membership_id' => $p['id'],
'membership_status' => $p['status'],
'membership_reference_code' => $p['reference_code'],
'membership_initial_amount' => wu_format_currency($p['initial_amount'], $p['currency']),
'membership_initial_amount_raw' => $p['initial_amount'],
'membership_amount' => wu_format_currency($p['amount'], $p['currency']),
'membership_amount_raw' => $p['amount'],
'membership_currency' => $p['currency'],
'membership_description' => $p['formatted_price'],
'membership_gateway' => $p['gateway'],
'membership_date_expiration' => $p['date_expiration'],
'membership_manage_url' => wu_network_admin_url('wp-ultimo-edit-membership', array(
'id' => $model->get_id(),
)),
);
} elseif ($model_name === 'product') {
$payload = $model->to_search_results();
$payload = array(
'product_id' => $payload['id'],
'product_amount' => wu_format_currency($payload['amount'], $payload['currency']),
'product_amount_raw' => $payload['amount'],
'product_setup_fee' => wu_format_currency($payload['setup_fee'], $payload['currency']),
'product_setup_fee_raw' => $payload['setup_fee'],
'product_currency' => $payload['currency'],
'product_description' => $payload['formatted_price'],
'product_image' => $payload['image'],
'product_manage_url' => wu_network_admin_url('wp-ultimo-edit-payment', array(
'id' => $model->get_id(),
)),
);
} elseif ($model_name === 'payment') {
$payload = $model->to_search_results();
$payload = array(
'payment_id' => $payload['id'],
'payment_status' => $payload['status'],
'payment_reference_code' => $payload['reference_code'],
'payment_subtotal' => wu_format_currency($payload['subtotal'], $payload['currency']),
'payment_subtotal_raw' => $payload['subtotal'],
'payment_tax_total' => wu_format_currency($payload['tax_total'], $payload['currency']),
'payment_tax_total_raw' => $payload['tax_total'],
'payment_total' => wu_format_currency($payload['total'], $payload['currency']),
'payment_total_raw' => $payload['total'],
'payment_currency' => $payload['currency'],
'payment_product_names' => $payload['product_names'],
'payment_date_created' => $payload['date_created'],
'payment_gateway' => $payload['gateway'],
'payment_invoice_url' => $model->get_invoice_url(),
'payment_manage_url' => wu_network_admin_url('wp-ultimo-edit-payment', array(
'id' => $model->get_id(),
)),
);
} elseif ($model_name === 'site') {
$payload = $model->to_search_results();
$payload = array(
'site_id' => $payload['blog_id'],
'site_title' => $payload['title'],
'site_description' => $payload['description'],
'site_url' => $payload['siteurl'],
'site_admin_url' => get_admin_url($model->get_id()),
'site_manage_url' => wu_network_admin_url('wp-ultimo-edit-site', array(
'id' => $model->get_id(),
)),
);
} elseif ($model_name === 'domain') {
$payload = $model->to_search_results();
$payload = array(
'domain_id' => $payload['id'],
'domain_domain' => $payload['domain'],
'domain_site_id' => $payload['blog_id'],
'domain_stage' => $payload['stage'],
'domain_active' => var_export(wu_string_to_bool($payload['active']), true),
'domain_primary' => var_export(wu_string_to_bool($payload['primary_domain']), true),
'domain_secure' => var_export(wu_string_to_bool($payload['secure']), true),
'domain_date_created' => $payload['date_created'],
'domain_manage_url' => wu_network_admin_url('wp-ultimo-edit-domain', array(
'id' => $model->get_id(),
)),
);
} // end if;
return $payload;
} // end wu_generate_event_payload;
/**
* Checks if the payload is a callable or if it's ready to use.
*
* @since 2.0.8
*
* @param mixed $payload The payload.
* @return array
*/
function wu_maybe_lazy_load_payload($payload) {
if (is_callable($payload)) {
$payload = (array) call_user_func($payload);
} // end if;
/*
* Adds the version number for control purposes.
*/
$payload['wu_version'] = wu_get_version();
return $payload;
} // end wu_maybe_lazy_load_payload;

580
inc/functions/financial.php Normal file
View File

@ -0,0 +1,580 @@
<?php
/**
* Financial Functions
*
* @package WP_Ultimo\Functions
* @since 2.0.0
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
use \WP_Ultimo\Database\Payments\Payment_Status;
use \WP_Ultimo\Database\Memberships\Membership_Status;
/**
* Calculates the Monthly Recurring Revenue of the network.
*
* @since 2.0.0
* @return float
*/
function wu_calculate_mrr() {
$total_mrr = 0;
$memberships = wu_get_memberships(array(
'recurring' => true,
'status__in' => array(
Membership_Status::ACTIVE,
),
));
foreach ($memberships as $membership) {
$recurring_amount = $membership->get_amount();
if (!$membership->is_recurring()) {
continue;
} // end if;
$duration = $membership->get_duration() ? $membership->get_duration() : 1;
$duration_unit = $membership->get_duration_unit();
$normalized_duration_unit = wu_convert_duration_unit_to_month($duration_unit);
$mrr = $recurring_amount / ($duration * $normalized_duration_unit);
$total_mrr += $mrr;
} // end foreach;
return $total_mrr;
} // end wu_calculate_mrr;
/**
* Converts the duration unit strings such as 'day', 'year' and such into
* a integer/float representing the amount of monhts.
*
* @since 2.0.0
*
* @param string $duration_unit The duration unit.
* @return float
*/
function wu_convert_duration_unit_to_month($duration_unit) {
$months = 1;
switch ($duration_unit) {
case 'day':
$months = 1 / 30;
break;
case 'week':
$months = 1 / 4;
break;
case 'month':
$months = 1;
break;
case 'year':
$months = 12;
break;
default:
$months = $months;
break;
} // end switch;
return $months;
} // end wu_convert_duration_unit_to_month;
/**
* Calculates the Annual Recurring Revenue.
*
* It is basically MRR * 12.
*
* @since 2.0.0
* @return float
*/
function wu_calculate_arr() {
return wu_calculate_mrr() * 12;
} // end wu_calculate_arr;
/**
* Calculates the total revenue.
*
* @since 2.0.0
*
* @param string $start_date The start date for the stat.
* @param string $end_date The end date for the stat.
* @param boolean $inclusive If true, will include payments on the start and end date.
* @return float
*/
function wu_calculate_revenue($start_date = false, $end_date = false, $inclusive = true) {
$total_revenue = 0;
$query_args = array(
'fields' => array('total'),
'date_query' => array(),
'status__in' => array(
Payment_Status::COMPLETED,
Payment_Status::PARTIAL,
),
);
if ($start_date) {
$query_args['date_query']['column'] = 'date_created';
$query_args['date_query']['after'] = $start_date;
$query_args['date_query']['inclusive'] = $inclusive;
} // end if;
if ($end_date) {
$query_args['date_query']['column'] = 'date_created';
$query_args['date_query']['before'] = $end_date;
$query_args['date_query']['inclusive'] = $inclusive;
} // end if;
$payments = wu_get_payments($query_args);
foreach ($payments as $payment) {
$total_revenue += (float) $payment->total;
} // end foreach;
return $total_revenue;
} // end wu_calculate_revenue;
/**
* Calculates the total refunds.
*
* @since 2.0.0
*
* @param string $start_date The start date for the stat.
* @param string $end_date The end date for the stat.
* @param boolean $inclusive If true, will include payments on the start and end date.
* @return float
*/
function wu_calculate_refunds($start_date = false, $end_date = false, $inclusive = true) {
$total_revenue = 0;
$query_args = array(
'fields' => array('refund_total'),
'date_query' => array(),
'status__in' => array(
Payment_Status::REFUND,
Payment_Status::PARTIAL_REFUND,
),
);
if ($start_date) {
$query_args['date_query']['column'] = 'date_created';
$query_args['date_query']['after'] = $start_date;
$query_args['date_query']['inclusive'] = $inclusive;
} // end if;
if ($end_date) {
$query_args['date_query']['column'] = 'date_created';
$query_args['date_query']['before'] = $end_date;
$query_args['date_query']['inclusive'] = $inclusive;
} // end if;
$payments = wu_get_payments($query_args);
foreach ($payments as $payment) {
$total_revenue += -(float) $payment->refund_total;
} // end foreach;
return $total_revenue;
} // end wu_calculate_refunds;
/**
* Calculates the taxes collected grouped by the rate.
*
* @since 2.0.0
*
* @param string $start_date The start date to compile data.
* @param string $end_date The end date to compile data.
* @param boolean $inclusive To include or not the start and end date.
* @return array
*/
function wu_calculate_taxes_by_rate($start_date = false, $end_date = false, $inclusive = true) {
$query_args = array(
'date_query' => array(),
);
if ($start_date) {
$query_args['date_query']['after'] = $start_date;
$query_args['date_query']['inclusive'] = $inclusive;
} // end if;
if ($end_date) {
$query_args['date_query']['before'] = $end_date;
$query_args['date_query']['inclusive'] = $inclusive;
} // end if;
$order = 0;
$taxes_paid_list = array();
$line_items_groups = \WP_Ultimo\Checkout\Line_Item::get_line_items($query_args);
foreach ($line_items_groups as $line_items_group) {
$order++;
foreach ($line_items_group as $line_item) {
$tax_name = $line_item->get_tax_label();
if ($line_item->get_tax_rate() <= 0) {
continue;
} // end if;
if (!wu_get_isset($taxes_paid_list, $tax_name)) {
$taxes_paid_list[$tax_name] = array(
'title' => $tax_name,
'country' => '',
'state' => '',
'order_count' => $order,
'tax_rate' => $line_item->get_tax_rate(),
'tax_total' => $line_item->get_tax_total(),
);
} else {
$taxes_paid_list[$tax_name]['tax_total'] += $line_item->get_tax_total();
$taxes_paid_list[$tax_name]['order_count'] += $order;
} // end if;
} // end foreach;
} // end foreach;
return $taxes_paid_list;
} // end wu_calculate_taxes_by_rate;
/**
* Aggregate financial data on a per product basis.
*
* @since 2.0.0
*
* @param string $start_date The start date to compile data.
* @param string $end_date The end date to compile data.
* @param boolean $inclusive To include or not the start and end date.
* @return array
*/
function wu_calculate_financial_data_by_product($start_date = false, $end_date = false, $inclusive = true) {
$query_args = array(
'date_query' => array(),
'payment_status' => Payment_Status::COMPLETED,
);
if ($start_date) {
$query_args['date_query']['after'] = $start_date;
$query_args['date_query']['inclusive'] = $inclusive;
} // end if;
if ($end_date) {
$query_args['date_query']['before'] = $end_date;
$query_args['date_query']['inclusive'] = $inclusive;
} // end if;
$line_items_groups = \WP_Ultimo\Checkout\Line_Item::get_line_items($query_args);
$data = array();
$products = wu_get_products();
foreach ($products as $product) {
$data[$product->get_id()] = array(
'label' => $product->get_name(),
'revenue' => 0,
);
} // end foreach;
foreach ($line_items_groups as $line_items_group) {
foreach ($line_items_group as $line_item) {
$product_id = $line_item->get_product_id();
if (empty($product_id)) {
continue;
} // end if;
if (!wu_get_isset($data, $product_id)) {
continue;
} // end if;
$data[$product_id]['revenue'] += $line_item->get_total();
} // end foreach;
} // end foreach;
uasort($data, fn($a, $b) => wu_sort_by_column($b, $a, 'revenue'));
return $data;
} // end wu_calculate_financial_data_by_product;
/**
* Calculates the taxes collected grouped by date.
*
* @since 2.0.0
*
* @param string $start_date The start date to compile data.
* @param string $end_date The end date to compile data.
* @param boolean $inclusive To include or not the start and end date.
* @return array
*/
function wu_calculate_taxes_by_day($start_date = false, $end_date = false, $inclusive = true) {
$query_args = array(
'date_query' => array(),
);
if ($start_date) {
$query_args['date_query']['after'] = $start_date;
$query_args['date_query']['inclusive'] = $inclusive;
} // end if;
if ($end_date) {
$query_args['date_query']['before'] = $end_date;
$query_args['date_query']['inclusive'] = $inclusive;
} // end if;
$line_items_groups = \WP_Ultimo\Checkout\Line_Item::get_line_items($query_args);
$data = array();
$period = new \DatePeriod(
new \DateTime($start_date),
new \DateInterval('P1D'),
new \DateTime($end_date . ' 23:59:59')
);
$days = array_reverse(iterator_to_array($period));
foreach ($days as $day_datetime) {
$data[$day_datetime->format('Y-m-d')] = array(
'order_count' => 0,
'total' => 0,
'tax_total' => 0,
'net_profit' => 0,
);
} // end foreach;
foreach ($line_items_groups as $line_items_group) {
foreach ($line_items_group as $line_item) {
$date = gmdate('Y-m-d', strtotime((string) $line_item->date_created));
if (!wu_get_isset($data, $date)) {
$data[$date] = array(
'order_count' => 0,
'total' => $line_item->get_total(),
'tax_total' => $line_item->get_tax_total(),
'net_profit' => $line_item->get_total() - $line_item->get_tax_total(),
);
} else {
$data[$date]['order_count'] += 1;
$data[$date]['total'] += $line_item->get_total();
$data[$date]['tax_total'] += $line_item->get_tax_total();
$data[$date]['net_profit'] += $line_item->get_total() - $line_item->get_tax_total();
} // end if;
} // end foreach;
} // end foreach;
return $data;
} // end wu_calculate_taxes_by_day;
/**
* Calculates the taxes collected this year, segregated by month.
*
* @since 2.0.0
* @return array
*/
function wu_calculate_taxes_by_month() {
$cache = get_site_transient('wu_tax_monthly_stats');
if (is_array($cache)) {
return $cache;
} // end if;
$query_args = array(
'date_query' => array(
'after' => 'first day of January this year',
'before' => 'last day of December this year',
'inclusive' => true,
),
);
$line_items_groups = \WP_Ultimo\Checkout\Line_Item::get_line_items($query_args);
$data = array();
$period = new \DatePeriod(
new \DateTime($query_args['date_query']['after']),
new \DateInterval('P1M'),
new \DateTime($query_args['date_query']['before'])
);
$months = iterator_to_array($period);
foreach ($months as $month_datetime) {
$data[$month_datetime->format('n')] = array(
'order_count' => 0,
'total' => 0,
'tax_total' => 0,
'net_profit' => 0,
);
} // end foreach;
foreach ($line_items_groups as $line_items_group) {
foreach ($line_items_group as $line_item) {
$date = gmdate('n', strtotime((string) $line_item->date_created));
if (!wu_get_isset($data, $date)) {
$data[$date] = array(
'order_count' => 0,
'total' => $line_item->get_total(),
'tax_total' => $line_item->get_tax_total(),
'net_profit' => $line_item->get_total() - $line_item->get_tax_total(),
);
} else {
$data[$date]['order_count'] += 1;
$data[$date]['total'] += $line_item->get_total();
$data[$date]['tax_total'] += $line_item->get_tax_total();
$data[$date]['net_profit'] += $line_item->get_total() - $line_item->get_tax_total();
} // end if;
} // end foreach;
} // end foreach;
set_site_transient('wu_tax_monthly_stats', $data);
return $data;
} // end wu_calculate_taxes_by_month;
/**
* Returns the number of sign-ups by form slug.
*
* @since 2.0.0
*
* @param string $start_date The start date to compile data.
* @param string $end_date The end date to compile data.
* @param boolean $inclusive To include or not the start and end date.
* @return array
*/
function wu_calculate_signups_by_form($start_date = false, $end_date = false, $inclusive = true) {
global $wpdb;
$query = array(
'date_query' => array(),
);
if ($start_date) {
$query['date_query']['after'] = $start_date;
$query['date_query']['inclusive'] = $inclusive;
} // end if;
if ($end_date) {
$query['date_query']['before'] = $end_date;
$query['date_query']['inclusive'] = $inclusive;
} // end if;
$date_query = new \WP_Date_Query($query['date_query']);
$date_query_sql = $date_query->get_sql();
$date_query_sql = str_replace($wpdb->base_prefix . 'posts.post_date', 'date_registered', $date_query_sql);
// phpcs:disable;
$query_sql = "
SELECT signup_form, COUNT(id) as count
FROM {$wpdb->base_prefix}wu_customers as d
WHERE 1 = 1
AND signup_form IS NOT NULL
{$date_query_sql}
GROUP BY signup_form
ORDER BY count DESC
";
$results = $wpdb->get_results($query_sql); // phpcs:ignore
return $results;
} // end wu_calculate_signups_by_form;

74
inc/functions/form.php Normal file
View File

@ -0,0 +1,74 @@
<?php
/**
* Form Functions
*
* @package WP_Ultimo\Functions
* @since 2.0.0
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
use \WP_Ultimo\Managers\Form_Manager;
/**
* Registers a new Ajax Form.
*
* Ajax forms are forms that get loaded via an ajax call using thickbox.
* This is useful for displaying inline edit forms that support Vue and our
* Form/Fields API.
*
* @since 2.0.0
* @see \WP_Ultimo\Managers\Form_Manager::register_form
*
* @param string $form_id Form id.
* @param array $atts Form attributes, check wp_parse_atts call below.
* @return mixed
*/
function wu_register_form($form_id, $atts = array()) {
return Form_Manager::get_instance()->register_form($form_id, $atts);
} // end wu_register_form;
/**
* Returns the ajax URL for a given form.
*
* @since 2.0.0
* @see \WP_Ultimo\Managers\Form_Manager::get_form_url
*
* @param string $form_id The id of the form to return.
* @param array $atts List of parameters, check wp_parse_args below.
* @param boolean $inline If this form is has content.
* @return string
*/
function wu_get_form_url($form_id, $atts = array(), $inline = false) {
if ($inline) {
$atts = wp_parse_args($atts, array(
'inlineId' => $form_id,
'width' => '400',
'height' => '360',
));
// TB_inline?height=300&width=300&inlineId=wu-add-field
return add_query_arg($atts, '#TB_inline');
} // end if;
return Form_Manager::get_instance()->get_form_url($form_id, $atts, $inline);
} // end wu_get_form_url;
/**
* Adds our fork of the thickbox script.
*
* @since 2.0.0
* @return void
*/
function add_wubox() { // phpcs:ignore
wp_enqueue_script('wubox');
} // end add_wubox;

110
inc/functions/fs.php Normal file
View File

@ -0,0 +1,110 @@
<?php
/**
* File System Functions
*
* @package WP_Ultimo\Functions
* @since 2.0.11
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Returns the main site uploads dir array from WordPress.
*
* @since 2.0.11
* @return array
*/
function wu_get_main_site_upload_dir() {
global $current_site;
is_multisite() && switch_to_blog($current_site->blog_id);
if (!defined('WP_CONTENT_URL')) {
define('WP_CONTENT_URL', get_option('siteurl') . '/wp-content');
} // end if;
$uploads = wp_upload_dir(null, false);
is_multisite() && restore_current_blog();
return $uploads;
} // end wu_get_main_site_upload_dir;
/**
* Creates a WP Ultimo folder inside the uploads folder - if needed - and return its path.
*
* @since 2.0.11
*
* @param string $folder Name of the folder.
* @param string ...$path Additional path segments to be attached to the folder path.
* @return string The path to the folder
*/
function wu_maybe_create_folder($folder, ...$path) {
$uploads = wu_get_main_site_upload_dir();
$folder_path = trailingslashit($uploads['basedir'] . '/' . $folder);
/*
* Checks if the folder exists.
*/
if (!file_exists($folder_path)) {
// Creates the Folder
wp_mkdir_p($folder_path);
// Creates htaccess
$htaccess = $folder_path . '.htaccess';
if (!file_exists($htaccess)) {
$fp = @fopen($htaccess, 'w');
@fputs($fp, 'deny from all'); // phpcs:ignore
@fclose($fp); // phpcs:ignore
} // end if;
// Creates index
$index = $folder_path . 'index.html';
if (!file_exists($index)) {
$fp = @fopen($index, 'w');
@fputs($fp, ''); // phpcs:ignore
@fclose($fp); // phpcs:ignore
} // end if;
} // end if;
return $folder_path . implode('/', $path);
} // end wu_maybe_create_folder;
/**
* Gets the URL for the folders created with maybe_create_folder().
*
* @see wu_maybe_create_folder()
* @since 2.0.0
*
* @param string $folder The name of the folder.
* @return string
*/
function wu_get_folder_url($folder) {
$uploads = wu_get_main_site_upload_dir();
$folder_url = trailingslashit($uploads['baseurl'] . '/' . $folder);
return set_url_scheme($folder_url);
} // end wu_get_folder_url;

158
inc/functions/gateway.php Normal file
View File

@ -0,0 +1,158 @@
<?php
/**
* Gateway Functions
*
* @package WP_Ultimo\Functions
* @since 2.0.0
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
use WP_Ultimo\Managers\Gateway_Manager;
/**
* Adds a new Gateway to the System. Used by gateways to make themselves visible.
*
* @since 2.0.0
*
* @param string $id ID of the gateway. This is how we will identify the gateway in the system.
* @param string $title Name of the gateway.
* @param string $desc A description of the gateway to help super admins understand what services they integrate with.
* @param string $class_name Gateway class name.
* @param bool $hidden If we need to hide this gateway publicly.
* @return bool
*/
function wu_register_gateway($id, $title, $desc, $class_name, $hidden = false) {
if (!did_action('wu_register_gateways')) {
_doing_it_wrong(__FUNCTION__, __('You should not register new payment gateways before the wu_register_gateways hook.', 'wp-ultimo'), '2.0.0');
} // end if;
return Gateway_Manager::get_instance()->register_gateway($id, $title, $desc, $class_name, $hidden);
} // end wu_register_gateway;
/**
* Returns the currently registered gateways.
*
* @since 2.0.0
*
* @return array
*/
function wu_get_gateways() {
return Gateway_Manager::get_instance()->get_registered_gateways();
} // end wu_get_gateways;
/**
* Returns the currently registered and active gateways.
*
* @since 2.0.0
* @return array
*/
function wu_get_active_gateways() {
$gateways = array();
$active_gateways = (array) wu_get_setting('active_gateways', array());
foreach ($active_gateways as $active_gateway) {
if (Gateway_Manager::get_instance()->is_gateway_registered($active_gateway)) {
$gateways[$active_gateway] = Gateway_Manager::get_instance()->get_gateway($active_gateway);
} // end if;
} // end foreach;
return apply_filters('wu_get_active_gateways', $gateways);
} // end wu_get_active_gateways;
/**
* Returns a gateway class if it exists.
*
* @since 2.0.0
*
* @param string $id Gateway ID.
* @param string $subscription Subscription object to load into the gateway.
* @return mixed Gateway class.
*/
function wu_get_gateway($id, $subscription = null) {
$gateway = Gateway_Manager::get_instance()->get_gateway($id);
if (!$gateway) {
return false;
} // end if;
$gateway_class = new $gateway['class_name']();
return $gateway_class;
} // end wu_get_gateway;
/**
* Returns the list of available gateways as key => name.
*
* @since 2.0.0
* @return array
*/
function wu_get_gateway_as_options() {
$options = array();
foreach (wu_get_gateways() as $gateway_slug => $gateway) {
$instance = class_exists($gateway['class_name']) ? new $gateway['class_name']() : false;
if ($instance === false || $gateway['hidden']) {
continue;
} // end if;
$options[$gateway_slug] = $gateway['title'];
} // end foreach;
return $options;
} // end wu_get_gateway_as_options;
/**
* Get the active gateways.
*
* @since 2.0.0
* @return array
*/
function wu_get_active_gateway_as_options() {
$options = array();
foreach (wu_get_active_gateways() as $gateway_slug => $gateway) {
$instance = class_exists($gateway['class_name']) ? new $gateway['class_name']() : false;
if ($instance === false || $gateway['hidden']) {
continue;
} // end if;
$title = $instance->get_public_title();
$options[$gateway_slug] = apply_filters("wu_gateway_{$gateway_slug}_as_option_title", $title, $gateway);
} // end foreach;
return $options;
} // end wu_get_active_gateway_as_options;

View File

@ -0,0 +1,49 @@
<?php
/**
* Generator Functions
*
* @package WP_Ultimo\Functions
* @since 2.0.11
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Generate CSV file
*
* @param string $file_name File name.
* @param array $data Content.
* @return void
*/
function wu_generate_csv($file_name, $data = array()) {
$fp = fopen('php://output', 'w');
if ($fp && $data) {
header('Content-Type: text/csv; charset=utf-8');
header('Content-Disposition: attachment; filename="' . $file_name . '.csv"');
header('Pragma: no-cache');
header('Expires: 0');
foreach ($data as $data_line) {
if (is_array($data_line)) {
fputcsv($fp, array_values($data_line));
} elseif (is_object($data_line)) {
fputcsv($fp, array_values(get_object_vars($data_line)));
} // end if;
} // end foreach;
} // end if;
} // end wu_generate_csv;

View File

@ -0,0 +1,24 @@
<?php
/**
* Geolocation Functions
*
* @package WP_Ultimo\Functions
* @since 2.0.0
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Get the customers' IP address.
*
* @since 2.0.0
* @return string
*/
function wu_get_ip() {
$geolocation = \WP_Ultimo\Geolocation::geolocate_ip('', true);
return apply_filters('wu_get_ip', $geolocation['ip']);
} // end wu_get_ip;

336
inc/functions/helper.php Normal file
View File

@ -0,0 +1,336 @@
<?php
/**
* Core Helper Functions
*
* @package WP_Ultimo\Functions
* @since 2.0.0
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
use \WP_Ultimo\Exception\Runtime_Exception;
use \WP_Ultimo\Dependencies\Psr\Log\LogLevel;
/**
* Returns the WP Ultimo version.
*
* @since 2.0.0
* @return string
*/
function wu_get_version() {
return class_exists(\WP_Ultimo::class) ? \WP_Ultimo::VERSION : '';
} // end wu_get_version;
/**
* Check the debug status.
*
* @since 2.0.11
* @return bool
*/
function wu_is_debug() {
return defined('WP_ULTIMO_DEBUG') && WP_ULTIMO_DEBUG;
} // end wu_is_debug;
/**
* Checks if WP Ultimo is being loaded as a must-use plugin.
*
* @since 2.0.0
* @return bool
*/
function wu_is_must_use() {
return defined('WP_ULTIMO_IS_MUST_USE') && WP_ULTIMO_IS_MUST_USE;
} // end wu_is_must_use;
/**
* Checks if an array key value is set and returns it.
*
* If the key is not set, returns the $default parameter.
* This function is a helper to serve as a shorthand for the tedious
* and ugly $var = isset($array['key'])) ? $array['key'] : $default.
* Using this, that same line becomes wu_get_isset($array, 'key', $default);
*
* Since PHP 7.4, this can be replaced by the null-coalesce operator (??)
* in almost any circunstante.
*
* @since 2.0.0
*
* @param array|object $array Array or object to check key.
* @param string $key Key to check.
* @param mixed $default Default value, if the key is not set.
* @return mixed
*/
function wu_get_isset($array, $key, $default = false) {
if (!is_array($array)) {
$array = (array) $array;
} // end if;
return isset($array[$key]) ? $array[$key] : $default;
} // end wu_get_isset;
/**
* Returns the main site id for the network.
*
* @since 2.0.0
* @return int
*/
function wu_get_main_site_id() {
_wu_require_hook('ms_loaded');
global $current_site;
return $current_site->blog_id;
} // end wu_get_main_site_id;
/**
* This function return 'slugfied' options terms to be used as options ids.
*
* @since 0.0.1
* @param string $term Returns a string based on the term and this plugin slug.
* @return string
*/
function wu_slugify($term) {
return "wp-ultimo_$term";
} // end wu_slugify;
/**
* Returns the full path to the plugin folder.
*
* @since 2.0.11
* @param string $dir Path relative to the plugin root you want to access.
*/
function wu_path($dir): string {
return WP_ULTIMO_PLUGIN_DIR . $dir; // @phpstan-ignore-line
} // end wu_path;
/**
* Returns the URL to the plugin folder.
*
* @since 2.0.11
* @param string $dir Path relative to the plugin root you want to access.
* @return string
*/
function wu_url($dir) {
return apply_filters('wp_ultimo_url', WP_ULTIMO_PLUGIN_URL . $dir); // @phpstan-ignore-line
} // end wu_url;
/**
* Shorthand to retrieving variables from $_GET, $_POST and $_REQUEST;
*
* @since 2.0.0
*
* @param string $key Key to retrieve.
* @param mixed $default Default value, when the variable is not available.
* @return mixed
*/
function wu_request($key, $default = false) {
$value = isset($_REQUEST[$key]) ? stripslashes_deep($_REQUEST[$key]) : $default;
return apply_filters('wu_request', $value, $key, $default);
} // end wu_request;
/**
* Throws an exception if a given hook was not yet run.
*
* @since 2.0.11
*
* @param string $hook The hook to check. Defaults to 'ms_loaded'.
* @throws Runtime_Exception When the hook has not yet run.
* @return void
*/
function _wu_require_hook($hook = 'ms_loaded') { // phpcs:ignore
if (!did_action($hook)) {
$message = "This function can not yet be run as it relies on processing that happens on hook {$hook}.";
throw new Runtime_Exception($message);
} // end if;
} // end _wu_require_hook;
/**
* Checks if reflection is available.
*
* Opcache settings can stripe comments and
* make reflection unavailable.
*
* @since 2.0.11
* @return boolean
*/
function wu_are_code_comments_available() {
static $res;
if ($res === null) {
$res = (bool) (new \ReflectionFunction(__FUNCTION__))->getDocComment();
} // end if;
return $res;
} // end wu_are_code_comments_available;
/**
* Join string into a single path string.
*
* @since 2.0.11
* @param string ...$parts The parts of the path to join.
* @return string The URL string.
*/
function wu_path_join(...$parts): string {
if (sizeof($parts) === 0) {
return '';
} // end if;
$prefix = ($parts[0] === DIRECTORY_SEPARATOR) ? DIRECTORY_SEPARATOR : '';
$processed = array_filter(array_map(fn($part) => rtrim((string) $part, DIRECTORY_SEPARATOR), $parts), fn($part) => !empty($part));
return $prefix . implode(DIRECTORY_SEPARATOR, $processed);
} // end wu_path_join;
/**
* Add a log entry to chosen file.
*
* @since 2.0.0
*
* @param string $handle Name of the log file to write to.
* @param string|\WP_Error $message Log message to write.
* @param string $log_level Log level to write.
* @return void
*/
function wu_log_add($handle, $message, $log_level = LogLevel::INFO) {
\WP_Ultimo\Logger::add($handle, $message, $log_level);
} // end wu_log_add;
/**
* Clear entries from chosen file.
*
* @since 2.0.0
*
* @param mixed $handle Name of the log file to clear.
* @return void
*/
function wu_log_clear($handle) {
\WP_Ultimo\Logger::clear($handle);
} // end wu_log_clear;
/**
* Maybe log errors to the file.
*
* @since 2.0.0
*
* @param \Throwable $e The exception object.
* @return void
*/
function wu_maybe_log_error($e) {
if (defined('WP_DEBUG') && WP_DEBUG) {
error_log($e);
} // end if;
} // end wu_maybe_log_error;
/**
* Get the function caller.
*
* @since 2.0.0
*
* @param integer $depth The depth of the backtrace.
* @return string|null
*/
function wu_get_function_caller($depth = 1) {
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, $depth + 1);
$caller = isset($backtrace[$depth]['function']) ? $backtrace[$depth]['function'] : null;
return $caller;
} // end wu_get_function_caller;
/**
* Checks if a particular plugin is skipped in a CLI context.
*
* @since 2.1.0
*
* @param mixed $plugin The plugin slug. E.g. wp-ultimo.
*/
function wu_cli_is_plugin_skipped($plugin = null): bool {
if (!class_exists(\WP_CLI::class)) {
return false;
} // end if;
$skipped_plugins = \WP_CLI::get_config('skip-plugins');
if (is_bool($skipped_plugins)) {
return true;
} // end if;
$skipped_plugins = array_map(fn($plugin_slug) => trim((string) $plugin_slug), explode(',', (string) $skipped_plugins));
return in_array($plugin, $skipped_plugins, true);
} // end wu_cli_is_plugin_skipped;
/**
* Capture errors and exceptions thrown inside the callback to prevent breakage.
*
* @since 2.1.0
*
* @todo Implement the logging portion of the feature.
* @param \Callable $fn A callable to be run inside the capture block.
* @param bool $log Wether or not captured errors should be logged to a file.
*
* @return void
*/
function wu_ignore_errors($fn, $log = false) {
try {
call_user_func($fn);
} catch (\Throwable $exception) {
// Ignore it or log it.
} // end try;
} // end wu_ignore_errors;

74
inc/functions/http.php Normal file
View File

@ -0,0 +1,74 @@
<?php
/**
* HTTP, Request and Response Helper Functions
*
* @package WP_Ultimo\Functions
* @since 2.0.11
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Returns the PHP input (php://input) as JSON.
*
* @since 2.0.0
*
* @param boolean $raw Wether to return the raw string or a decoded value.
* @return object
*/
function wu_get_input($raw = false) {
$body = @file_get_contents('php://input'); // phpcs:ignore
return $raw ? $body : json_decode($body);
} // end wu_get_input;
/**
* Prevents the current page from being cached.
*
* @since 2.0.0
* @return void
*/
function wu_no_cache() {
if (!headers_sent()) {
nocache_headers();
header('Pragma: no-cache');
/*
* Let's send something custom so we can
* easily spot when no-caching is out fault!
*/
wu_x_header('X-Ultimo-Cache: prevent-caching');
} // end if;
do_action('wu_no_cache');
} // end wu_no_cache;
/**
* Maybe sends a WP Ultimo X Header.
*
* Useful for debugging purposes.
* These headers can easily be omitted by
* running add_filter('wu_should_send_x_headers', '__return_false');
*
* @since 2.0.0
*
* @param string $header The header to send. Example: X-Ultimo-Caching: prevent-caching.
* @return void
*/
function wu_x_header($header) {
if (apply_filters('wu_should_send_x_headers', defined('WP_DEBUG') && WP_DEBUG)) {
!headers_sent() && header($header);
} // end if;
} // end wu_x_header;

23
inc/functions/invoice.php Normal file
View File

@ -0,0 +1,23 @@
<?php
/**
* Invoice Functions
*
* @package WP_Ultimo\Functions
* @since 2.0.11
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Create the invoice template used in the editor customizer.
*
* @since 2.0.0
*
* @return boolean
*/
function wu_get_invoice_template() {
return false;
} // end wu_get_invoice_template;

478
inc/functions/legacy.php Normal file
View File

@ -0,0 +1,478 @@
<?php
/**
* Legacy Functions and Classes
*
* @package WP_Ultimo\Functions
* @since 2.0.0
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
// phpcs:disable
/**
* Return the instance of the function
*/
function WU_Signup() {
return \WP_Ultimo\Checkout\Legacy_Checkout::get_instance();
} // end WU_Signup;
/**
*
* We need to load our functions in case people access this from wp-signup without the .php extension
*/
if (!function_exists('validate_blog_form')) {
function validate_blog_form() {
$user = '';
if ( is_user_logged_in() ) {
$user = wp_get_current_user();
} // end if;
return wpmu_validate_blog_signup($_POST['blogname'], $_POST['blog_title'], $user);
} // end validate_blog_form;
} // end if;
if (!function_exists('validate_user_form')) {
function validate_user_form() {
return wpmu_validate_user_signup($_POST['user_name'], $_POST['user_email']);
} // end validate_user_form;
} // end if;
/**
* Builds HTML attributes from a PHP array
*
* @param array $attributes
* @return void
*/
function wu_create_html_attributes_from_array($attributes = array()) {
$output = '';
foreach ($attributes as $name => $value) {
if (is_bool($value)) {
if ($value) {
$output .= $name . ' ';
} // end if;
} else {
$output .= sprintf('%s="%s"', $name, $value);
} // end if;
} // end foreach;
return $output;
} // end wu_create_html_attributes_from_array;
/**
* Display one single option
*
* @since 1.7.3
* @param string $option_value
* @param string $option_label
* @return void
*/
function wu_print_signup_field_option($option_value, $option_label, $field = array()) { ?>
<option <?php selected(isset($field['default']) && $field['default'] == $option_value); ?> value="<?php echo $option_value; ?>"><?php echo $option_label; ?></option>
<?php
} // end wu_print_signup_field_option;
/**
* Displays the option tags of an select field
*
* @since 1.7.3
* @param array $options
* @return void
*/
function wu_print_signup_field_options($options, $field = array()) {
foreach ($options as $option_value => $option_label) {
if (is_array($option_label)) {
echo sprintf('<optgroup label="%s">', $option_value);
foreach ($option_label as $option_value => $option_label) {
wu_print_signup_field_option($option_value, $option_label, $field);
} // end foreach;
echo '</optgroup>';
} else {
wu_print_signup_field_option($option_value, $option_label, $field);
} // end if;
} // end foreach;
} // end wu_print_signup_field_options;
/**
* Print sing-up fields
*
* @param string $field_slug
* @param array $field
* @param array $results
* @return void
*/
function wu_print_signup_field($field_slug, $field, $results) {
$display = true;
// Requires Logic
if (isset($field['requires']) && is_array($field['requires'])) {
$display = false;
/**
* Builds required elements list
*/
$elements = array_keys($field['requires']);
$elements = implode(', ', $elements);
wp_enqueue_script('jquery');
?>
<script type="text/javascript">
document.addEventListener('DOMContentLoaded', function() {
var requires = <?php echo json_encode($field['requires']); ?>,
target_field = document.getElementById('<?php echo $field_slug; ?>-field');
var display_field = function(target_field, requires, velocity) {
var conditions_count = Object.keys(requires).length,
conditions_met = 0;
requires.forEach(function(element, value) {
var element = document.getElementById(element),
element_value = element.value;
if (element.type === "checkbox") {
var is_checked = element.checked;
if (is_checked === value) {
conditions_met++;
}
return true;
} // end if;
value = Array.isArray(value) ? value : [value];
if (value.indexOf(element_value) > -1) {
conditions_met++;
} // end if;
});
if (conditions_met == conditions_count) {
target_field.slideDown(velocity);
} else {
target_field.slideUp(velocity);
} // end
} // end display_field;
display_field(target_field, requires, 0);
[<?php echo $elements; ?>].forEach(function(element) {
document.getElementById(element).addEventListener('change', function() {
display_field(target_field, requires, 300);
});
});
});
</script>
<?php
} // end if;
$wrapper_attributes = '';
$attributes = '';
/**
* Builds Attributes display
*/
if (isset($field['wrapper_attributes']) && $field['wrapper_attributes']) {
$wrapper_attributes = wu_create_html_attributes_from_array($field['wrapper_attributes']);
} // end if;
if (isset($field['attributes']) && $field['attributes']) {
$attributes = wu_create_html_attributes_from_array($field['attributes']);
} // end if;
/**
* Switch type for display
*/
switch ($field['type']) {
/**
* Normal Text Inputs
*/
case 'text':
case 'number':
case 'email':
case 'url':
?>
<p <?php echo $wrapper_attributes; ?> id="<?php echo $field_slug; ?>-field" <?php echo $wrapper_attributes; ?> style="<?php echo $display ? '' : 'display: none'; ?>" >
<label for="<?php echo $field_slug; ?>"><?php echo $field['name']; ?> <?php echo wu_tooltip($field['tooltip']); ?><br>
<input <?php echo $attributes; ?> <?php echo isset($field['required']) && $field['required'] ? 'required' : ''; ?> type="<?php echo $field['type']; ?>" name="<?php echo $field_slug; ?>" id="<?php echo $field_slug; ?>" class="input" value="<?php echo isset($results[$field_slug]) ? $results[$field_slug] : ''; ?>" size="20"></label>
<?php
if ($error_message = $results['errors']->get_error_message($field_slug)) {
echo '<p class="error">' . $error_message . '</p>';
} // end if;
?>
</p>
<?php
break;
case 'password':
wp_enqueue_script('utils');
wp_enqueue_script('user-profile');
?>
<p <?php echo $wrapper_attributes; ?> id="<?php echo $field_slug; ?>-field" <?php echo $wrapper_attributes; ?> style="<?php echo $display ? '' : 'display: none'; ?>" >
<?php
if (isset($field['display_force']) && $field['display_force']) :
$suffix = WP_Ultimo()->min;
wp_enqueue_script('wu-password-verify', WP_Ultimo()->get_asset("wu-password-verify$suffix.js", 'js'), array('jquery'), true);
?>
<span class="password-input-wrapper" style="display: block;">
<label for="<?php echo $field_slug; ?>"><?php echo $field['name']; ?> <?php echo wu_tooltip($field['tooltip']); ?><br>
<input <?php echo $attributes; ?> <?php echo isset($field['required']) && $field['required'] ? 'required' : ''; ?> type="<?php echo $field['type']; ?>" name="<?php echo $field_slug; ?>" id="<?php echo $field_slug; ?>" class="input" value="<?php echo isset($results[$field_slug]) ? $results[$field_slug] : ''; ?>" data-reveal="1" data-pw="<?php echo esc_attr( wp_generate_password( 16 ) ); ?>" class="input" size="20" autocomplete="off" aria-describedby="pass-strength-result" />
</span>
<span style="display: block; margin-top: -16px; opacity: 1; height: 36px;" id="pass-strength-result" class="hide-if-no-js" aria-live="polite"><?php _e( 'Strength indicator' ); ?></span>
<script>
document.addEventListener('DOMContentLoaded', function() {
var input = document.getElementById('<?php echo $field_slug; ?>');
input.addEventListener('keyup', function() {
wu_check_pass_strength('#<?php echo $field_slug; ?>', '#<?php echo $field_slug; ?>');
});
});
</script>
<?php else : ?>
<label for="<?php echo $field_slug; ?>"><?php echo $field['name']; ?> <?php echo wu_tooltip($field['tooltip']); ?><br>
<input <?php echo $attributes; ?> <?php echo isset($field['required']) && $field['required'] ? 'required' : ''; ?> type="<?php echo $field['type']; ?>" name="<?php echo $field_slug; ?>" id="<?php echo $field_slug; ?>" class="input" value="<?php echo isset($results[$field_slug]) ? $results[$field_slug] : ''; ?>" size="20"></label>
<?php endif; ?>
<?php
if ($error_message = $results['errors']->get_error_message($field_slug)) {
echo '<p class="error">' . $error_message . '</p>';
} // end if;
?>
</p>
<?php
break;
/**
* Case HTML
*/
case 'html':
?>
<div <?php echo $wrapper_attributes; ?> id="<?php echo $field_slug; ?>-field">
<?php echo $field['content']; ?>
</div>
<?php
break;
/**
* Case Submit Button
*/
case 'submit':
?>
<p class="submit">
<input name="signup_form_id" type="hidden" value="1">
<button id="wp-submit" <?php echo $attributes; ?> type="submit" class="button button-primary button-large button-next" value="1" name="save_step">
<?php esc_attr_e($field['name'], 'wp-ultimo'); ?>
</button>
<?php wp_nonce_field('signup_form_1', '_signup_form'); ?>
</p>
<?php
break;
/**
* Case Select
*/
case 'select':
?>
<p <?php echo $wrapper_attributes; ?> id="<?php echo $field_slug; ?>-field" style="<?php echo $display ? '' : 'display: none'; ?>">
<label for="<?php echo $field_slug; ?>"><?php echo $field['name']; ?> <?php echo wu_tooltip($field['tooltip']); ?><br>
<select <?php echo $attributes; ?> <?php echo isset($field['required']) && $field['required'] ? 'required' : ''; ?> name="<?php echo $field_slug; ?>" id="<?php echo $field_slug; ?>" class="input" value="<?php echo isset($results[$field_slug]) ? $results[$field_slug] : ''; ?>">
<?php wu_print_signup_field_options($field['options'], $field); ?>
</select>
</label>
<?php
if ($error_message = $results['errors']->get_error_message($field_slug)) {
echo '<p class="error">' . $error_message . '</p>';
} // end if;
?>
</p>
<?php
break;
/**
* Case Checkbox
*/
case 'checkbox':
$checked = isset($field['check_if']) && isset($result[$field['check_if']])
|| (isset($field['check_if']) && isset($_POST[$field['check_if']]) && $_POST[$field['check_if']])
|| (isset($field['checked']) && $field['checked'])
? true : false;
?>
<p>
<label for="<?php echo $field_slug; ?>">
<input type="checkbox" name="<?php echo $field_slug; ?>" value="1" id="<?php echo $field_slug; ?>" <?php echo checked($checked, true); ?>>
<?php echo $field['name']; ?>
</label>
<br>
<?php
if ($error_message = $results['errors']->get_error_message($field_slug)) {
echo '<p class="error">' . $error_message . '</p>';
} // end if;
?>
<br>
</p>
<?php
break;
} // end switch;
} // end wu_print_signup_field;
/**
* Alias function to allow creation of users for WP Ultimo.
*
* User Data should contain: user_login, user_email, user_pass;
* Plan Data should contain: plan_id, plan_freq;
* User Meta is an associative array containing key => value pairs to be saved as meta fields on that user.
*
* @param array $user_data
* @param array $plan_data
* @param array $user_meta
* @return int|bool
*/
function wu_create_user(array $user_data, array $plan_data, array $user_meta = array()) {
return WU_Signup()->create_user($user_data, $plan_data, $user_meta);
} // end wu_create_user;
/**
* Alias function to allow creation of sites for WP Ultimo.
*
* Site Data should contain: blog_title, blogname, and role;
* Site Meta is an associative array containing key => value pairs to be saved as meta fields on that site.
*
* @param integer $user_id
* @param array $site_data
* @param boolean $template_id
* @param array $site_meta
* @return void
*/
function wu_create_site_legacy($user_id, array $site_data, $template_id = false, $site_meta = array()) {
return WU_Signup()->create_site($user_id, $site_data, $template_id, $site_meta);
} // end wu_create_site_legacy;
/**
* Alias function that adds a new Step to the sign-up flow
*
* @since 1.4.0
* @param string $id
* @param integer $order
* @return void
*/
function wu_add_signup_step($id, $order, array $step) {
return WU_Signup()->add_signup_step($id, $order, $step);
} // end wu_add_signup_step;
/**
* Alias function that adds a new field to a step the sign-up flow
*
* @since 1.4.0
* @param string $step
* @param string $id
* @param integer $order
* @param array $step
* @return void
*/
function wu_add_signup_field($step, $id, $order, $field) {
return WU_Signup()->add_signup_field($step, $id, $order, $field);
} // end wu_add_signup_field;

View File

@ -0,0 +1,30 @@
<?php
/**
* Licensing Functions
*
* @package WP_Ultimo\Functions
* @since 2.0.0
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Adds the license key to a given URL.
*
* @since 2.0.0
*
* @param string $url URL to attach the license key to.
* @return string
*/
function wu_with_license_key($url) {
$license_key = '';
$license = \WP_Ultimo\License::get_instance();
$license_key = $license->get_license_key();
return add_query_arg('license_key', rawurlencode((string) $license_key), $url);
} // end wu_with_license_key;

View File

@ -0,0 +1,293 @@
<?php
/**
* Limitations Functions
*
* @package WP_Ultimo\Functions
* @since 2.0.0
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Checks if the current site has a certain product associated to it.
*
* This is useful for controlling the display of certain info
* based on the plans and other products attached to a membership -
* and as a consequence - to a site.
*
* For example, to display something only to the customers of the
* products with the "premium" slug, we'd have something like this:
*
* if (wu_has_product('premium')) {
*
* // premium content here.
*
* } else {
*
* // Content for non-members.
*
* }.
*
* One important things to keep in mind is that this function
* does not check for the status of that site's membership by default.
* If that's something that you need, pass the second param "blocking" as true.
* If the blocking flag is set, the function only returns true if the site has
* the product and if the membership is active.
*
* Another important note:
* This function behaves differently when called in the context of
* the main site or a regular site. In these cases, we loop through
* all of the customer's memberships to try to find at least one
* with the requested product. This makes this function useful
* to control access to content on the main site, for example.
*
* @since 2.0.0
* @see wu_is_membership_active()
*
* @todo Implement search algo for main site and regular site.
* @param string|array $product_slug Product slug to check. Can also be an array of product slugs.
* Will return true if ANY slug on the array is present.
* @param bool $blocking When set to true, this flag also validates the active status of the membership.
* @param string $site_id The site ID to test.
* @return boolean
*/
function wu_has_product($product_slug, $blocking = false, $site_id = '') {
if (!is_array($product_slug)) {
$product_slug = array($product_slug);
} // end if;
if (empty($site_id)) {
$site_id = get_current_blog_id();
} // end if;
$site = wu_get_site($site_id);
if (empty($site)) {
return new \WP_Error('site-not-found', __('Invalid site ID', 'wp-ultimo'));
} // end if;
$membership = $site->get_membership();
if (empty($membership)) {
return true;
} // end if;
$applicable_products_slugs = $membership->get_applicable_product_slugs();
$contains_product = empty(array_intersect($product_slug, $applicable_products_slugs)) === false;
$active_status = true;
if ($blocking) {
$active_status = $membership->is_active();
} // end if;
return $contains_product && $active_status;
} // end wu_has_product;
/**
* Checks if the membership associated with a site is active.
*
* @since 2.0.0
*
* @param string $site_id The site ID to test.
* @return bool
*/
function wu_is_membership_active($site_id = '') {
if (empty($site_id)) {
$site_id = get_current_blog_id();
} // end if;
$site = wu_get_site($site_id);
if (empty($site)) {
return new \WP_Error('site-not-found', __('Invalid site ID', 'wp-ultimo'));
} // end if;
$membership = $site->get_membership();
if (empty($membership)) {
return true;
} // end if;
return $membership->is_active();
} // end wu_is_membership_active;
/**
* Register a new Limitation module.
*
* @since 2.0.0
*
* @param string $id The id of the limitation module.
* @param string $class_name The module class name.
* @return void
*/
function wu_register_limit_module($id, $class_name) {
add_filter('wu_limit_classes', function($classes) use ($id, $class_name) {
$id = sanitize_title($id);
$classes[$id] = $class_name;
return $classes;
});
} // end wu_register_limit_module;
/**
* Generate the modal link to search for an upgrade path.
*
* @since 2.0.0
*
* @param array $args The module and type of limit that needs upgrading.
* @return string
*/
function wu_generate_upgrade_to_unlock_url($args) {
$args = wp_parse_args($args, array(
'module' => false,
'type' => false,
));
$membership = wu_get_current_site()->get_membership();
if (!$membership) {
return '';
} // end if;
$upgrade_url = wu_get_membership_update_url($membership);
$url = add_query_arg($args, $upgrade_url);
/**
* Allow developers to change the upgrade to unlock URL
*
* @param string $url The upgrade URL.
* @param array $args The module and type of limit that needs upgrading.
*/
return apply_filters('wu_upgrade_to_unlock_url', $url, $args);
} // end wu_generate_upgrade_to_unlock_url;
/**
* Generates a Unlock to Upgrade button for the upgrade modal.
*
* @since 2.0.0
*
* @param string $title The title of the modal and label of the button.
* @param array $args The module and type of limit that needs upgrading.
* @return string
*/
function wu_generate_upgrade_to_unlock_button($title, $args) {
$args = wp_parse_args($args, array(
'module' => false,
'type' => false,
'classes' => '',
));
$url = wu_generate_upgrade_to_unlock_url(array(
'module' => $args['module'],
'type' => $args['type'],
));
$element = sprintf(
'<a href="%s" title="%s" class="%s">%s</a>',
$url,
$title,
$args['classes'],
$title
);
return $element;
} // end wu_generate_upgrade_to_unlock_button;
/**
* Activate a plugin(s) via Job Queue.
*
* @since 2.0.0
*
* @param int $site_id The site ID.
* @param string|array $plugins The plugin or list of plugins to activate.
* @param boolean $network_wide If we want to activate it network-wide.
* @param boolean $silent IF we should do the process silently - true by default.
* @return void
*/
function wu_async_activate_plugins($site_id, $plugins, $network_wide = false, $silent = true) {
wu_enqueue_async_action('wu_async_handle_plugins', array(
'action' => 'activate',
'site_id' => $site_id,
'plugins' => $plugins,
'network_wide' => $network_wide,
'silent' => $silent,
));
} // end wu_async_activate_plugins;
/**
* Deactivates a plugin(s) via Job Queue.
*
* @since 2.0.0
*
* @param int $site_id The site ID.
* @param string|array $plugins The plugin or list of plugins to activate.
* @param boolean $network_wide If we want to activate it network-wide.
* @param boolean $silent IF we should do the process silently - true by default.
* @return void
*/
function wu_async_deactivate_plugins($site_id, $plugins, $network_wide = false, $silent = true) {
wu_enqueue_async_action('wu_async_handle_plugins', array(
'action' => 'deactivate',
'site_id' => $site_id,
'plugins' => $plugins,
'network_wide' => $network_wide,
'silent' => $silent,
));
} // end wu_async_deactivate_plugins;
/**
* Switch themes via Job Queue.
*
* @since 2.0.0
*
* @param int $site_id The site ID.
* @param string $theme_stylesheet The theme stylesheet.
* @return void
*/
function wu_async_switch_theme($site_id, $theme_stylesheet) {
wu_enqueue_async_action('wu_async_switch_theme', array(
'site_id' => $site_id,
'theme_stylesheet' => $theme_stylesheet,
));
} // end wu_async_switch_theme;

View File

@ -0,0 +1,779 @@
<?php
/**
* Markup Helper Functions
*
* @package WP_Ultimo\Functions
* @since 2.0.0
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Converts an array to a vue data-state parameter.
*
* @since 2.0.0
*
* @param array $state_array The array to convert.
* @return string
*/
function wu_convert_to_state($state_array = array()) {
$object = (object) $state_array; // Force object to prevent issues with Vue.
return json_encode($object);
} // end wu_convert_to_state;
/**
* Clean up p tags around block elements.
*
* @since 2.0.0
*
* @param string $content The content.
* @return string
*/
function wu_remove_empty_p($content): ?string {
$content = preg_replace(array(
'#<p>\s*<(div|aside|section|article|header|footer)#',
'#</(div|aside|section|article|header|footer)>\s*</p>#',
'#</(div|aside|section|article|header|footer)>\s*<br ?/?>#',
'#<(div|aside|section|article|header|footer)(.*?)>\s*</p>#',
'#<p>\s*</(div|aside|section|article|header|footer)#',
), array(
'<$1',
'</$1>',
'</$1>',
'<$1$2>',
'</$1',
), $content);
return preg_replace('#<p>(\s|&nbsp;)*+(<br\s*/*>)*(\s|&nbsp;)*</p>#i', '', $content);
} // end wu_remove_empty_p;
/**
* Generates a string containing html attributes to be used inside html tags.
*
* This function takes an array of attributes => value and returns
* a string of concatenated html attributes ready to be echoed inside
* a HTML element.
*
* Example input:
* array(
* 'id' => 'my-element-id',
* 'class' => 'my-class my-class-2',
* );
*
* Output: id="my-element-id" class="my-class my-class-2"
*
* @since 2.0.7
*
* @param array $attributes The list of attributes.
*/
function wu_array_to_html_attrs($attributes = array()): string {
$attributes = array_map(fn($key, $value) => $key . '="' . htmlspecialchars((string) $value) . '"', array_keys($attributes), $attributes);
return implode(' ', $attributes);
} // end wu_array_to_html_attrs;
/**
* Adds a tooltip icon.
*
* @since 2.0.0
*
* @param string $tooltip Message to display.
* @param string $icon Dashicon to display as the icon.
* @return string
*/
function wu_tooltip($tooltip, $icon = 'dashicons-editor-help') {
if (empty($tooltip)) {
return '';
} // end if;
$markup = sprintf('<span class="wu-styling" role="tooltip" aria-label="%s">', esc_attr($tooltip));
if (!is_admin()) {
$markup .= '<svg style="width:11px" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Layer_1" x="0px" y="0px" viewBox="0 0 122.88 122.88" xml:space="preserve"><g><path class="st0" d="M122.88,61.44C122.88,27.51,95.37,0,61.44,0C27.51,0,0,27.51,0,61.44c0,33.93,27.51,61.44,61.44,61.44 C95.37,122.88,122.88,95.37,122.88,61.44L122.88,61.44z M68.79,74.58H51.3v-1.75c0-2.97,0.32-5.39,1-7.25 c0.68-1.87,1.68-3.55,3.01-5.1c1.34-1.54,4.35-4.23,9.01-8.11c2.48-2.03,3.73-3.88,3.73-5.56c0-1.71-0.51-3.01-1.5-3.95 c-1-0.93-2.51-1.4-4.54-1.4c-2.19,0-3.98,0.73-5.4,2.16c-1.43,1.44-2.34,3.97-2.74,7.56l-17.88-2.22c0.61-6.57,3-11.86,7.15-15.85 c4.17-4.02,10.55-6.01,19.14-6.01c6.7,0,12.1,1.4,16.21,4.19c5.6,3.78,8.38,8.82,8.38,15.1c0,2.62-0.73,5.14-2.16,7.56 c-1.44,2.44-4.39,5.39-8.85,8.88c-3.09,2.48-5.05,4.44-5.86,5.93C69.19,70.24,68.79,72.19,68.79,74.58L68.79,74.58z M50.68,79.25 h18.76v16.53H50.68V79.25L50.68,79.25z"></path></g></svg>';
} else {
$markup .= sprintf('<span class="dashicons wu-text-xs wu-w-auto wu-h-auto wu-align-text-bottom %s"></span>', esc_attr($icon));
} // end if;
$markup .= '</span>';
return $markup;
} // end wu_tooltip;
/**
* Adds a tooltip to a HTML element. Needs to be echo'ed.
*
* @since 2.0.0
*
* @param string $tooltip Message to display.
*/
function wu_tooltip_text($tooltip): string {
return sprintf('role="tooltip" aria-label="%s"', esc_attr($tooltip));
} // end wu_tooltip_text;
/**
* Adds a preview tag that displays the image passed on hover.
*
* @since 2.0.0
*
* @param string $image_url The image URL.
* @param boolean $label The label for the preview tag. Defaults to Preview.
*/
function wu_preview_image($image_url, $label = false): string {
if (empty($label)) {
$label = __('Preview', 'wp-ultimo');
} // end if;
return sprintf(' <span class="wu-image-preview wu-text-gray-600 wu-bg-gray-200 wu-p-1 wu-px-2 wu-ml-1 wu-inline-block wu-text-2xs wu-uppercase wu-font-bold wu-rounded wu-cursor-pointer wu-border-gray-300 wu-border wu-border-solid" data-image="%s">%s %s</span>', $image_url, "<span class='dashicons-wu-image wu-align-middle wu-mr-1'></span>", $label);
} // end wu_preview_image;
/**
* Returns the list of available icons. To add more icons you need use the filter
* wu_icons_list, and new array using the Key as the optgroup label and the value
* as the array with all the icons you want to make available.
*
* Don't forget to add the css as well.
*
* @since 2.0.0
*
* @return array With all available icons.
*/
function wu_get_icons_list() {
$all_icons = array();
$all_icons['WP Ultimo Icons'] = array(
'dashicons-wu-add_task',
'dashicons-wu-address',
'dashicons-wu-add-to-list',
'dashicons-wu-add-user',
'dashicons-wu-adjust',
'dashicons-wu-air',
'dashicons-wu-aircraft',
'dashicons-wu-aircraft-landing',
'dashicons-wu-aircraft-take-off',
'dashicons-wu-align-bottom',
'dashicons-wu-align-horizontal-middle',
'dashicons-wu-align-left',
'dashicons-wu-align-right',
'dashicons-wu-align-top',
'dashicons-wu-align-vertical-middle',
'dashicons-wu-archive',
'dashicons-wu-area-graph',
'dashicons-wu-arrow-bold-down',
'dashicons-wu-arrow-bold-left',
'dashicons-wu-arrow-bold-right',
'dashicons-wu-arrow-bold-up',
'dashicons-wu-arrow-down',
'dashicons-wu-arrow-left',
'dashicons-wu-arrow-long-down',
'dashicons-wu-arrow-long-left',
'dashicons-wu-arrow-long-right',
'dashicons-wu-arrow-long-up',
'dashicons-wu-arrow-right',
'dashicons-wu-arrow-up',
'dashicons-wu-arrow-with-circle-down',
'dashicons-wu-arrow-with-circle-left',
'dashicons-wu-arrow-with-circle-right',
'dashicons-wu-arrow-with-circle-up',
'dashicons-wu-attachment',
'dashicons-wu-awareness-ribbon',
'dashicons-wu-back',
'dashicons-wu-back-in-time',
'dashicons-wu-bar-graph',
'dashicons-wu-battery',
'dashicons-wu-beamed-note',
'dashicons-wu-bell',
'dashicons-wu-blackboard',
'dashicons-wu-block',
'dashicons-wu-book',
'dashicons-wu-bookmark',
'dashicons-wu-bookmarks',
'dashicons-wu-bowl',
'dashicons-wu-box',
'dashicons-wu-briefcase',
'dashicons-wu-browser',
'dashicons-wu-brush',
'dashicons-wu-bucket',
'dashicons-wu-cake',
'dashicons-wu-calculator',
'dashicons-wu-calendar',
'dashicons-wu-camera',
'dashicons-wu-ccw',
'dashicons-wu-chat',
'dashicons-wu-check',
'dashicons-wu-checkbox-checked',
'dashicons-wu-checkbox-unchecked',
'dashicons-wu-chevron-down',
'dashicons-wu-chevron-left',
'dashicons-wu-chevron-right',
'dashicons-wu-chevron-small-down',
'dashicons-wu-chevron-small-left',
'dashicons-wu-chevron-small-right',
'dashicons-wu-chevron-small-up',
'dashicons-wu-chevron-thin-down',
'dashicons-wu-chevron-thin-left',
'dashicons-wu-chevron-thin-right',
'dashicons-wu-chevron-thin-up',
'dashicons-wu-chevron-up',
'dashicons-wu-chevron-with-circle-down',
'dashicons-wu-chevron-with-circle-left',
'dashicons-wu-chevron-with-circle-right',
'dashicons-wu-chevron-with-circle-up',
'dashicons-wu-circle',
'dashicons-wu-circle-with-cross',
'dashicons-wu-circle-with-minus',
'dashicons-wu-circle-with-plus',
'dashicons-wu-circular-graph',
'dashicons-wu-clapperboard',
'dashicons-wu-classic-computer',
'dashicons-wu-clipboard',
'dashicons-wu-clock',
'dashicons-wu-cloud',
'dashicons-wu-code',
'dashicons-wu-cog',
'dashicons-wu-coin-dollar',
'dashicons-wu-coin-euro',
'dashicons-wu-coin-pound',
'dashicons-wu-coin-yen',
'dashicons-wu-colours',
'dashicons-wu-compass',
'dashicons-wu-controller-fast-forward',
'dashicons-wu-controller-jump-to-start',
'dashicons-wu-controller-next',
'dashicons-wu-controller-paus',
'dashicons-wu-controller-play',
'dashicons-wu-controller-record',
'dashicons-wu-controller-stop',
'dashicons-wu-controller-volume',
'dashicons-wu-copy',
'dashicons-wu-credit',
'dashicons-wu-credit-card',
'dashicons-wu-credit-card1',
'dashicons-wu-cross',
'dashicons-wu-cup',
'dashicons-wu-cw',
'dashicons-wu-cycle',
'dashicons-wu-database',
'dashicons-wu-dial-pad',
'dashicons-wu-direction',
'dashicons-wu-document',
'dashicons-wu-document-landscape',
'dashicons-wu-documents',
'dashicons-wu-done',
'dashicons-wu-done_all',
'dashicons-wu-dot-single',
'dashicons-wu-dots-three-horizontal',
'dashicons-wu-dots-three-vertical',
'dashicons-wu-dots-two-horizontal',
'dashicons-wu-dots-two-vertical',
'dashicons-wu-download',
'dashicons-wu-drink',
'dashicons-wu-drive',
'dashicons-wu-drop',
'dashicons-wu-edit',
'dashicons-wu-email',
'dashicons-wu-emoji-flirt',
'dashicons-wu-emoji-happy',
'dashicons-wu-emoji-neutral',
'dashicons-wu-emoji-sad',
'dashicons-wu-erase',
'dashicons-wu-eraser',
'dashicons-wu-export',
'dashicons-wu-eye',
'dashicons-wu-feather',
'dashicons-wu-filter_1',
'dashicons-wu-filter_2',
'dashicons-wu-filter_3',
'dashicons-wu-filter_4',
'dashicons-wu-filter_5',
'dashicons-wu-filter_6',
'dashicons-wu-filter_7',
'dashicons-wu-filter_8',
'dashicons-wu-filter_9',
'dashicons-wu-filter_9_plus',
'dashicons-wu-flag',
'dashicons-wu-flash',
'dashicons-wu-flashlight',
'dashicons-wu-flat-brush',
'dashicons-wu-flow-branch',
'dashicons-wu-flow-cascade',
'dashicons-wu-flow-line',
'dashicons-wu-flow-parallel',
'dashicons-wu-flow-tree',
'dashicons-wu-folder',
'dashicons-wu-folder-images',
'dashicons-wu-folder-music',
'dashicons-wu-folder-video',
'dashicons-wu-forward',
'dashicons-wu-funnel',
'dashicons-wu-game-controller',
'dashicons-wu-gauge',
'dashicons-wu-globe',
'dashicons-wu-graduation-cap',
'dashicons-wu-grid',
'dashicons-wu-hair-cross',
'dashicons-wu-hand',
'dashicons-wu-hash',
'dashicons-wu-hashtag',
'dashicons-wu-heart',
'dashicons-wu-heart-outlined',
'dashicons-wu-help',
'dashicons-wu-help-with-circle',
'dashicons-wu-home',
'dashicons-wu-hour-glass',
'dashicons-wu-image',
'dashicons-wu-image-inverted',
'dashicons-wu-images',
'dashicons-wu-inbox',
'dashicons-wu-infinity',
'dashicons-wu-info',
'dashicons-wu-info-with-circle',
'dashicons-wu-install',
'dashicons-wu-key',
'dashicons-wu-keyboard',
'dashicons-wu-lab-flask',
'dashicons-wu-landline',
'dashicons-wu-language',
'dashicons-wu-laptop',
'dashicons-wu-layers',
'dashicons-wu-leaf',
'dashicons-wu-level-down',
'dashicons-wu-level-up',
'dashicons-wu-lifebuoy',
'dashicons-wu-light-bulb',
'dashicons-wu-light-down',
'dashicons-wu-light-up',
'dashicons-wu-line-graph',
'dashicons-wu-link',
'dashicons-wu-list',
'dashicons-wu-location',
'dashicons-wu-location-pin',
'dashicons-wu-lock',
'dashicons-wu-lock-open',
'dashicons-wu-login',
'dashicons-wu-log-out',
'dashicons-wu-loop',
'dashicons-wu-magnet',
'dashicons-wu-magnifying-glass',
'dashicons-wu-mail',
'dashicons-wu-man',
'dashicons-wu-map',
'dashicons-wu-mask',
'dashicons-wu-medal',
'dashicons-wu-megaphone',
'dashicons-wu-menu',
'dashicons-wu-message',
'dashicons-wu-mic',
'dashicons-wu-minus',
'dashicons-wu-mobile',
'dashicons-wu-modern-mic',
'dashicons-wu-moon',
'dashicons-wu-mouse',
'dashicons-wu-music',
'dashicons-wu-new',
'dashicons-wu-new-message',
'dashicons-wu-news',
'dashicons-wu-note',
'dashicons-wu-notification',
'dashicons-wu-number',
'dashicons-wu-old-mobile',
'dashicons-wu-old-phone',
'dashicons-wu-open-book',
'dashicons-wu-palette',
'dashicons-wu-paper-plane',
'dashicons-wu-pencil',
'dashicons-wu-pencil2',
'dashicons-wu-phone',
'dashicons-wu-pie-chart',
'dashicons-wu-pin',
'dashicons-wu-plus',
'dashicons-wu-popup',
'dashicons-wu-power-cord',
'dashicons-wu-power-plug',
'dashicons-wu-price-ribbon',
'dashicons-wu-price-tag',
'dashicons-wu-print',
'dashicons-wu-progress-empty',
'dashicons-wu-progress-full',
'dashicons-wu-progress-one',
'dashicons-wu-progress-two',
'dashicons-wu-publish',
'dashicons-wu-qrcode',
'dashicons-wu-quote',
'dashicons-wu-radio',
'dashicons-wu-remove-user',
'dashicons-wu-reply',
'dashicons-wu-reply-all',
'dashicons-wu-resize-100',
'dashicons-wu-resize-full-screen',
'dashicons-wu-retweet',
'dashicons-wu-rocket',
'dashicons-wu-round-brush',
'dashicons-wu-rss',
'dashicons-wu-ruler',
'dashicons-wu-save',
'dashicons-wu-scissors',
'dashicons-wu-select-arrows',
'dashicons-wu-share',
'dashicons-wu-shareable',
'dashicons-wu-share-alternitive',
'dashicons-wu-shield',
'dashicons-wu-shop',
'dashicons-wu-shopping-bag',
'dashicons-wu-shopping-basket',
'dashicons-wu-shopping-cart',
'dashicons-wu-shuffle',
'dashicons-wu-signal',
'dashicons-wu-sound',
'dashicons-wu-sound-mix',
'dashicons-wu-sound-mute',
'dashicons-wu-sports-club',
'dashicons-wu-spreadsheet',
'dashicons-wu-squared-cross',
'dashicons-wu-squared-minus',
'dashicons-wu-squared-plus',
'dashicons-wu-star',
'dashicons-wu-star-outlined',
'dashicons-wu-stopwatch',
'dashicons-wu-suitcase',
'dashicons-wu-swap',
'dashicons-wu-sweden',
'dashicons-wu-switch',
'dashicons-wu-tablet',
'dashicons-wu-tag',
'dashicons-wu-text',
'dashicons-wu-text-document',
'dashicons-wu-text-document-inverted',
'dashicons-wu-thermometer',
'dashicons-wu-thumbs-down',
'dashicons-wu-thumbs-up',
'dashicons-wu-thunder-cloud',
'dashicons-wu-ticket',
'dashicons-wu-ticket1',
'dashicons-wu-time-slot',
'dashicons-wu-toggle_on',
'dashicons-wu-tools',
'dashicons-wu-traffic-cone',
'dashicons-wu-trash',
'dashicons-wu-tree',
'dashicons-wu-triangle-down',
'dashicons-wu-triangle-left',
'dashicons-wu-triangle-right',
'dashicons-wu-triangle-up',
'dashicons-wu-trophy',
'dashicons-wu-tv',
'dashicons-wu-typing',
'dashicons-wu-uninstall',
'dashicons-wu-unread',
'dashicons-wu-untag',
'dashicons-wu-upload',
'dashicons-wu-upload-to-cloud',
'dashicons-wu-user',
'dashicons-wu-users',
'dashicons-wu-v-card',
'dashicons-wu-verified',
'dashicons-wu-video',
'dashicons-wu-vinyl',
'dashicons-wu-voicemail',
'dashicons-wu-wallet',
'dashicons-wu-warning',
'dashicons-wu-wp-ultimo'
);
$all_icons['Dashicons'] = array(
'dashicons-before dashicons-admin-appearance',
'dashicons-before dashicons-admin-collapse',
'dashicons-before dashicons-admin-comments',
'dashicons-before dashicons-admin-customizer',
'dashicons-before dashicons-admin-generic',
'dashicons-before dashicons-admin-home',
'dashicons-before dashicons-admin-links',
'dashicons-before dashicons-admin-media',
'dashicons-before dashicons-admin-multisite',
'dashicons-before dashicons-admin-network',
'dashicons-before dashicons-admin-page',
'dashicons-before dashicons-admin-plugins',
'dashicons-before dashicons-admin-post',
'dashicons-before dashicons-admin-settings',
// 'dashicons-before dashicons-admin-site-alt',
// 'dashicons-before dashicons-admin-site-alt2',
// 'dashicons-before dashicons-admin-site-alt3',
'dashicons-before dashicons-admin-site',
'dashicons-before dashicons-admin-tools',
'dashicons-before dashicons-admin-users',
'dashicons-before dashicons-album',
'dashicons-before dashicons-align-center',
'dashicons-before dashicons-align-left',
'dashicons-before dashicons-align-none',
'dashicons-before dashicons-align-right',
'dashicons-before dashicons-analytics',
'dashicons-before dashicons-archive',
'dashicons-before dashicons-arrow-down-alt',
'dashicons-before dashicons-arrow-down-alt2',
'dashicons-before dashicons-arrow-down',
'dashicons-before dashicons-arrow-left-alt',
'dashicons-before dashicons-arrow-left-alt2',
'dashicons-before dashicons-arrow-left',
'dashicons-before dashicons-arrow-right-alt',
'dashicons-before dashicons-arrow-right-alt2',
'dashicons-before dashicons-arrow-right',
'dashicons-before dashicons-arrow-up-alt',
'dashicons-before dashicons-arrow-up-alt2',
'dashicons-before dashicons-arrow-up',
'dashicons-before dashicons-art',
'dashicons-before dashicons-awards',
'dashicons-before dashicons-backup',
'dashicons-before dashicons-book-alt',
'dashicons-before dashicons-book',
'dashicons-before dashicons-buddicons-activity',
'dashicons-before dashicons-buddicons-bbpress-logo',
'dashicons-before dashicons-buddicons-buddypress-logo',
'dashicons-before dashicons-buddicons-community',
'dashicons-before dashicons-buddicons-forums',
'dashicons-before dashicons-buddicons-friends',
'dashicons-before dashicons-buddicons-groups',
'dashicons-before dashicons-buddicons-pm',
'dashicons-before dashicons-buddicons-replies',
'dashicons-before dashicons-buddicons-topics',
'dashicons-before dashicons-buddicons-tracking',
'dashicons-before dashicons-building',
'dashicons-before dashicons-businessman',
'dashicons-before dashicons-calendar-alt',
'dashicons-before dashicons-calendar',
'dashicons-before dashicons-camera',
'dashicons-before dashicons-carrot',
'dashicons-before dashicons-cart',
'dashicons-before dashicons-category',
'dashicons-before dashicons-chart-area',
'dashicons-before dashicons-chart-bar',
'dashicons-before dashicons-chart-line',
'dashicons-before dashicons-chart-pie',
'dashicons-before dashicons-clipboard',
'dashicons-before dashicons-clock',
'dashicons-before dashicons-cloud',
'dashicons-before dashicons-controls-back',
'dashicons-before dashicons-controls-forward',
'dashicons-before dashicons-controls-pause',
'dashicons-before dashicons-controls-play',
'dashicons-before dashicons-controls-repeat',
'dashicons-before dashicons-controls-skipback',
'dashicons-before dashicons-controls-skipforward',
'dashicons-before dashicons-controls-volumeoff',
'dashicons-before dashicons-controls-volumeon',
'dashicons-before dashicons-dashboard',
'dashicons-before dashicons-desktop',
'dashicons-before dashicons-dismiss',
'dashicons-before dashicons-download',
'dashicons-before dashicons-edit',
'dashicons-before dashicons-editor-aligncenter',
'dashicons-before dashicons-editor-alignleft',
'dashicons-before dashicons-editor-alignright',
'dashicons-before dashicons-editor-bold',
'dashicons-before dashicons-editor-break',
'dashicons-before dashicons-editor-code',
'dashicons-before dashicons-editor-contract',
'dashicons-before dashicons-editor-customchar',
'dashicons-before dashicons-editor-expand',
'dashicons-before dashicons-editor-help',
'dashicons-before dashicons-editor-indent',
'dashicons-before dashicons-editor-insertmore',
'dashicons-before dashicons-editor-italic',
'dashicons-before dashicons-editor-justify',
'dashicons-before dashicons-editor-kitchensink',
'dashicons-before dashicons-editor-ltr',
'dashicons-before dashicons-editor-ol',
'dashicons-before dashicons-editor-outdent',
'dashicons-before dashicons-editor-paragraph',
'dashicons-before dashicons-editor-paste-text',
'dashicons-before dashicons-editor-paste-word',
'dashicons-before dashicons-editor-quote',
'dashicons-before dashicons-editor-removeformatting',
'dashicons-before dashicons-editor-rtl',
'dashicons-before dashicons-editor-spellcheck',
'dashicons-before dashicons-editor-strikethrough',
'dashicons-before dashicons-editor-table',
'dashicons-before dashicons-editor-textcolor',
'dashicons-before dashicons-editor-ul',
'dashicons-before dashicons-editor-underline',
'dashicons-before dashicons-editor-unlink',
'dashicons-before dashicons-editor-video',
'dashicons-before dashicons-email-alt',
// 'dashicons-before dashicons-email-alt2',
'dashicons-before dashicons-email',
'dashicons-before dashicons-excerpt-view',
'dashicons-before dashicons-external',
'dashicons-before dashicons-facebook-alt',
'dashicons-before dashicons-facebook',
'dashicons-before dashicons-feedback',
'dashicons-before dashicons-filter',
'dashicons-before dashicons-flag',
'dashicons-before dashicons-format-aside',
'dashicons-before dashicons-format-audio',
'dashicons-before dashicons-format-chat',
'dashicons-before dashicons-format-gallery',
'dashicons-before dashicons-format-image',
'dashicons-before dashicons-format-quote',
'dashicons-before dashicons-format-status',
'dashicons-before dashicons-format-video',
'dashicons-before dashicons-forms',
'dashicons-before dashicons-googleplus',
'dashicons-before dashicons-grid-view',
'dashicons-before dashicons-groups',
'dashicons-before dashicons-hammer',
'dashicons-before dashicons-heart',
'dashicons-before dashicons-hidden',
'dashicons-before dashicons-id-alt',
'dashicons-before dashicons-id',
'dashicons-before dashicons-image-crop',
'dashicons-before dashicons-image-filter',
'dashicons-before dashicons-image-flip-horizontal',
'dashicons-before dashicons-image-flip-vertical',
'dashicons-before dashicons-image-rotate-left',
'dashicons-before dashicons-image-rotate-right',
'dashicons-before dashicons-image-rotate',
'dashicons-before dashicons-images-alt',
'dashicons-before dashicons-images-alt2',
'dashicons-before dashicons-index-card',
'dashicons-before dashicons-info',
'dashicons-before dashicons-laptop',
'dashicons-before dashicons-layout',
'dashicons-before dashicons-leftright',
'dashicons-before dashicons-lightbulb',
'dashicons-before dashicons-list-view',
'dashicons-before dashicons-location-alt',
'dashicons-before dashicons-location',
'dashicons-before dashicons-lock',
'dashicons-before dashicons-marker',
'dashicons-before dashicons-media-archive',
'dashicons-before dashicons-media-audio',
'dashicons-before dashicons-media-code',
'dashicons-before dashicons-media-default',
'dashicons-before dashicons-media-document',
'dashicons-before dashicons-media-interactive',
'dashicons-before dashicons-media-spreadsheet',
'dashicons-before dashicons-media-text',
'dashicons-before dashicons-media-video',
'dashicons-before dashicons-megaphone',
// 'dashicons-before dashicons-menu-alt',
'dashicons-before dashicons-menu',
'dashicons-before dashicons-microphone',
'dashicons-before dashicons-migrate',
'dashicons-before dashicons-minus',
'dashicons-before dashicons-money',
'dashicons-before dashicons-move',
'dashicons-before dashicons-nametag',
'dashicons-before dashicons-networking',
'dashicons-before dashicons-no-alt',
'dashicons-before dashicons-no',
'dashicons-before dashicons-palmtree',
'dashicons-before dashicons-paperclip',
'dashicons-before dashicons-performance',
'dashicons-before dashicons-phone',
'dashicons-before dashicons-playlist-audio',
'dashicons-before dashicons-playlist-video',
'dashicons-before dashicons-plus-alt',
'dashicons-before dashicons-plus-light',
'dashicons-before dashicons-plus',
'dashicons-before dashicons-portfolio',
'dashicons-before dashicons-post-status',
'dashicons-before dashicons-pressthis',
'dashicons-before dashicons-products',
'dashicons-before dashicons-randomize',
'dashicons-before dashicons-redo',
// 'dashicons-before dashicons-rest-api',
'dashicons-before dashicons-rss',
'dashicons-before dashicons-schedule',
'dashicons-before dashicons-screenoptions',
'dashicons-before dashicons-search',
'dashicons-before dashicons-share-alt',
'dashicons-before dashicons-share-alt2',
'dashicons-before dashicons-share',
'dashicons-before dashicons-shield-alt',
'dashicons-before dashicons-shield',
'dashicons-before dashicons-slides',
'dashicons-before dashicons-smartphone',
'dashicons-before dashicons-smiley',
'dashicons-before dashicons-sort',
'dashicons-before dashicons-sos',
'dashicons-before dashicons-star-empty',
'dashicons-before dashicons-star-filled',
'dashicons-before dashicons-star-half',
'dashicons-before dashicons-sticky',
'dashicons-before dashicons-store',
'dashicons-before dashicons-tablet',
'dashicons-before dashicons-tag',
'dashicons-before dashicons-tagcloud',
'dashicons-before dashicons-testimonial',
'dashicons-before dashicons-text',
'dashicons-before dashicons-thumbs-down',
'dashicons-before dashicons-thumbs-up',
'dashicons-before dashicons-tickets-alt',
'dashicons-before dashicons-tickets',
// 'dashicons-before dashicons-tide',
'dashicons-before dashicons-translation',
'dashicons-before dashicons-trash',
'dashicons-before dashicons-twitter',
'dashicons-before dashicons-undo',
'dashicons-before dashicons-universal-access-alt',
'dashicons-before dashicons-universal-access',
'dashicons-before dashicons-unlock',
'dashicons-before dashicons-update',
'dashicons-before dashicons-upload',
'dashicons-before dashicons-vault',
'dashicons-before dashicons-video-alt',
'dashicons-before dashicons-video-alt2',
'dashicons-before dashicons-video-alt3',
'dashicons-before dashicons-visibility',
'dashicons-before dashicons-warning',
'dashicons-before dashicons-welcome-add-page',
'dashicons-before dashicons-welcome-comments',
'dashicons-before dashicons-welcome-learn-more',
'dashicons-before dashicons-welcome-view-site',
'dashicons-before dashicons-welcome-widgets-menus',
'dashicons-before dashicons-welcome-write-blog',
'dashicons-before dashicons-wordpress-alt',
'dashicons-before dashicons-wordpress',
'dashicons-before dashicons-yes-alt',
'dashicons-before dashicons-yes',
);
return apply_filters('wu_icons_list', $all_icons);
} // end wu_get_icons_list;
/**
* Checks if the current theme is a block theme.
*
* @since 2.0.11
* @return boolean
*/
function wu_is_block_theme() {
if (function_exists('wp_is_block_theme')) {
return wp_is_block_theme();
} // end if;
return false;
} // end wu_is_block_theme;

View File

@ -0,0 +1,503 @@
<?php
/**
* Membership Functions
*
* @package WP_Ultimo\Functions
* @since 2.0.0
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
use \WP_Ultimo\Models\Membership;
use \WP_Ultimo\Models\Payment;
use \WP_Ultimo\Database\Payments\Payment_Status;
use \WP_Ultimo\Checkout\Cart;
/**
* Returns a membership.
*
* @since 2.0.0
*
* @param int $membership_id The ID of the membership.
* @return \WP_Ultimo\Models\Membership|false
*/
function wu_get_membership($membership_id) {
return Membership::get_by_id($membership_id);
} // end wu_get_membership;
/**
* Returns a single membership defined by a particular column and value.
*
* @since 2.0.0
*
* @param string $column The column name.
* @param mixed $value The column value.
* @return \WP_Ultimo\Models\Membership|false
*/
function wu_get_membership_by($column, $value) {
return Membership::get_by($column, $value);
} // end wu_get_membership_by;
/**
* Gets a membership based on the hash.
*
* @since 2.0.0
*
* @param string $hash The hash for the membership.
* @return \WP_Ultimo\Models\Membership|false
*/
function wu_get_membership_by_hash($hash) {
return Membership::get_by_hash($hash);
} // end wu_get_membership_by_hash;
/**
* Queries memberships.
*
* @since 2.0.0
*
* @param array $query Query arguments.
* @return Membership[]
*/
function wu_get_memberships($query = array()) {
if (!empty($query['search'])) {
$customer_ids = wu_get_customers(array(
'search' => $query['search'],
'fields' => 'ids',
));
if (!empty($customer_ids)) {
$query['customer_id__in'] = $customer_ids;
unset($query['search']);
} // end if;
} // end if;
return Membership::query($query);
} // end wu_get_memberships;
/**
* Creates a new membership.
*
* @since 2.0.0
*
* @param array $membership_data Membership data.
* @return \WP_Error|\WP_Ultimo\Models\Membership
*/
function wu_create_membership($membership_data) {
/*
* Why do we use shortcode atts here?
* Shortcode atts clean the array from not-allowed keys, so we don't need to worry much.
*/
$membership_data = shortcode_atts(array(
'customer_id' => false,
'user_id' => false,
'migrated_from_id' => 0,
'plan_id' => false,
'addon_products' => false,
'currency' => false,
'initial_amount' => false,
'recurring' => false,
'duration' => 1,
'duration_unit' => 'month',
'amount' => false,
'auto_renew' => false,
'times_billed' => 0,
'billing_cycles' => 0,
'gateway_customer_id' => false,
'gateway_subscription_id' => false,
'gateway' => '',
'signup_method' => '',
'upgraded_from' => false,
'disabled' => false,
'status' => 'pending',
'date_created' => wu_get_current_time('mysql', true),
'date_activate' => null,
'date_trial_end' => null,
'date_renewed' => null,
'date_modified' => wu_get_current_time('mysql', true),
'date_expiration' => wu_get_current_time('mysql', true),
'skip_validation' => false,
), $membership_data);
$membership_data['migrated_from_id'] = is_numeric($membership_data['migrated_from_id']) ? $membership_data['migrated_from_id'] : 0;
$membership = new Membership($membership_data);
$saved = $membership->save();
return is_wp_error($saved) ? $saved : $membership;
} // end wu_create_membership;
/**
* Get all customers with a specific membership using the product_id as reference.
*
* @since 2.0.0
*
* @param array $product_id Membership product.
* @return array With all users within the membership.
*/
function wu_get_membership_customers($product_id) {
global $wpdb;
is_multisite() && switch_to_blog(get_main_site_id());
$product_id = (int) $product_id;
$regex = "(\\\\{i:$product_id;i)|(\\\\{((i:[0-9]*;){2})+(i:$product_id;i:))";
$table = "{$wpdb->prefix}wu_memberships";
$query = "SELECT `customer_id` FROM $table WHERE `addon_products` REGEXP '$regex' OR `plan_id` = $product_id";
$results = $wpdb->get_results($query); // phpcs:ignore
$results = array_map(fn($result) => (int) $result->customer_id, $results);
is_multisite() && restore_current_blog();
return $results;
} // end wu_get_membership_customers;
/**
* Returns a membership based on the customer gateway ID.
*
* This is NOT a very reliable way of retrieving memberships
* as the same customer can have multiple memberships using
* the same gateway.
*
* As this is only used as a last ditch effort, mostly when
* trying to process payment-related webhooks,
* we always get pending memberships, and the last one
* created (order by ID DESC).
*
* @since 2.0.0
*
* @param string $customer_gateway_id The customer gateway id. E.g. cus_***.
* @param array $allowed_gateways List of allowed gateways.
* @param boolean $amount The amount. Increases accuracy.
* @return \WP_Ultimo\Models\Membership|false
*/
function wu_get_membership_by_customer_gateway_id($customer_gateway_id, $allowed_gateways = array(), $amount = false) {
$search_data = array(
'gateway__in' => $allowed_gateways,
'number' => 1,
'gateway_customer_id__in' => array($customer_gateway_id),
'status__in' => array('pending'),
'orderby' => 'id',
'order' => 'DESC',
);
if (!empty($amount)) {
$search_data['initial_amount'] = $amount;
} // end if;
$memberships = wu_get_memberships($search_data);
return !empty($memberships) ? current($memberships) : false;
} // end wu_get_membership_by_customer_gateway_id;
/**
* Returns the price for a product in a specific membership.
* This allow us to calculate the values for a product change considering taxes.
*
* @since 2.1.3
*
* @param Membership $membership The membership.
* @param int $product_id The product ID.
* @param int $quantity The amount of products.
* @param bool $only_recurring Whether to only get the recurring price.
* @return float|\WP_Error The price or error.
*/
function wu_get_membership_product_price($membership, $product_id, $quantity, $only_recurring = true) {
$address = $membership->get_billing_address();
// Create a Cart with this product
$cart = new Cart(array(
'duration' => $membership->get_duration(),
'duration_unit' => $membership->get_duration_unit(),
'country' => $address->billing_country,
'state' => $address->billing_state,
'city' => $address->billing_city,
));
$discount_code = $membership->get_discount_code();
if ($discount_code) {
$cart->add_discount_code($discount_code);
} // end if;
$added = $cart->add_product($product_id, $quantity);
if (!$added) {
return $cart->errors;
} // end if;
$payment_data = array_merge($cart->to_payment_data(), array(
'customer_id' => $membership->get_customer_id(),
'membership_id' => $membership->get_id(),
'gateway' => $membership->get_gateway(),
));
// create a temporary payment to see the price.
$temp_payment = wu_create_payment($payment_data, false);
if (is_wp_error($temp_payment)) {
return $temp_payment;
} // end if;
if ($only_recurring) {
$temp_payment->remove_non_recurring_items();
} // end if;
$temp_payment->recalculate_totals();
return $temp_payment->get_total();
} // end wu_get_membership_product_price;
/**
* Creates a new payment for a membership.
*
* This is used by gateways to create a new payment when necessary.
*
* @since 2.0.0
*
* @param Membership $membership The membership object.
* @param bool $should_cancel_pending_payments If we should cancel pending payments.
* @param bool $remove_non_recurring If we should remove the non recurring items.
* @param bool $save If we should save the created payment.
* @return \WP_Ultimo\Models\Payment|\WP_Error
*/
function wu_membership_create_new_payment($membership, $should_cancel_pending_payments = true, $remove_non_recurring = true, $save = true) {
/*
* If we should cancel the previous
* pending payment, do that.
*/
if ($should_cancel_pending_payments) {
$pending_payment = $membership->get_last_pending_payment();
/*
* Change pending payment to cancelled.
*/
if ($pending_payment) {
$pending_payment->set_status(Payment_Status::CANCELLED);
$pending_payment->save();
} // end if;
} // end if;
$cart = wu_get_membership_new_cart($membership);
$payment_data = array_merge($cart->to_payment_data(), array(
'customer_id' => $membership->get_customer_id(),
'membership_id' => $membership->get_id(),
'gateway' => $membership->get_gateway(),
));
// We will save the payment after we recalculate the totals.
$new_payment = wu_create_payment($payment_data, false);
if (is_wp_error($new_payment)) {
return $new_payment;
} // end if;
if ($remove_non_recurring) {
$new_payment->remove_non_recurring_items();
} // end if;
$new_payment->recalculate_totals();
if (!$save) {
return $new_payment;
} // end if;
$status = $new_payment->save();
if (is_wp_error($status)) {
return $status;
} // end if;
return $new_payment;
} // end wu_membership_create_new_payment;
/**
* Creates a full cart based on a membership.
*
* @since 2.1.3
*
* @param Membership $membership The membership object.
* @return Cart
*/
function wu_get_membership_new_cart($membership) {
$address = $membership->get_billing_address();
$cart = new Cart(array(
'duration' => $membership->get_duration(),
'duration_unit' => $membership->get_duration_unit(),
'country' => $address->billing_country,
'state' => $address->billing_state,
'city' => $address->billing_city,
));
$discount_code = $membership->get_discount_code();
if ($discount_code) {
$cart->add_discount_code($discount_code);
} // end if;
foreach ($membership->get_all_products() as $key => $product) {
$cart->add_product($product['product']->get_id(), $product['quantity']);
} // end foreach;
$difference = $membership->get_amount() - $cart->get_recurring_total();
if (round(abs($difference), wu_currency_decimal_filter()) > 0) {
$type_translate = $difference < 0 ? __('credit', 'wp-ultimo') : __('debit', 'wp-ultimo');
$line_item_params = array(
'hash' => 'ADJUSTMENT',
'type' => $difference < 0 ? 'credit' : 'fee',
// translators: %s is the type of adjustment (credit or debit).
'title' => sprintf(__('Adjustment %s', 'wp-ultimo'), $type_translate),
'description' => __('Amount adjustment based on previous deal.', 'wp-ultimo'),
'unit_price' => $difference,
'discountable' => false,
'taxable' => false,
'recurring' => true,
'quantity' => 1,
'duration' => $membership->get_duration(),
'duration_unit' => $membership->get_duration_unit(),
);
$adjustment_line_item = new \WP_Ultimo\Checkout\Line_Item($line_item_params);
$cart->add_line_item($adjustment_line_item);
} // end if;
if ($membership->get_initial_amount() !== $cart->get_total()) {
$t = $membership->get_initial_amount();
$y = $cart->get_total();
$difference = $membership->get_initial_amount() - $cart->get_total();
$type_translate = $difference < 0 ? __('credit', 'wp-ultimo') : __('debit', 'wp-ultimo');
$line_item_params = array(
'hash' => 'INITADJUSTMENT',
'type' => $difference < 0 ? 'credit' : 'fee',
// translators: %s is the type of adjustment (credit or debit).
'title' => sprintf(__('Adjustment %s', 'wp-ultimo'), $type_translate),
'description' => __('Initial amount adjustment based on previous deal.', 'wp-ultimo'),
'unit_price' => $difference,
'discountable' => false,
'taxable' => false,
'recurring' => false,
'quantity' => 1,
);
$adjustment_line_item = new \WP_Ultimo\Checkout\Line_Item($line_item_params);
$cart->add_line_item($adjustment_line_item);
} // end if;
$y = $cart->get_total();
$t = $cart->get_recurring_total();
return $cart;
} // end wu_get_membership_new_cart;
/**
* Generate the modal link to search for an upgrade path.
*
* @since 2.1
*
* @param Membership $membership The membership to get the url.
* @return string
*/
function wu_get_membership_update_url($membership) {
$checkout_pages = \WP_Ultimo\Checkout\Checkout_Pages::get_instance();
$url = $checkout_pages->get_page_url('update');
$membership_hash = $membership->get_hash();
if ($url) {
return add_query_arg(array(
'membership' => $membership_hash,
), $url);
} // end if;
if (!is_main_site()) {
return admin_url('admin.php?page=wu-checkout&membership=' . $membership_hash);
} // end if;
$sites = $membership->get_sites(false);
if (count($sites) > 0) {
return add_query_arg(array(
'page' => 'wu-checkout',
'membership' => $membership_hash,
), get_admin_url($sites[0]->get_id()));
} // end if;
// In last case we use the default register form
$url = $checkout_pages->get_page_url('register');
return add_query_arg(array(
'membership' => $membership_hash,
'wu_form' => 'wu-checkout',
), $url);
} // end wu_get_membership_update_url;

151
inc/functions/mock.php Normal file
View File

@ -0,0 +1,151 @@
<?php
/**
* Model Mocking Functions
*
* @package WP_Ultimo\Functions
* @since 2.0.0
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Returns a mock site object.
*
* @since 2.0.0
* @param string|int $seed Number used to return different site names and urls.
* @return \WP_Ultimo\Models\Site
*/
function wu_mock_site($seed = false) {
$atts = apply_filters('wu_mock_site', array(
'title' => __('Example Site', 'wp-ultimo'),
'description' => __('This is an example of a site description.', 'wp-ultimo'),
'domain' => __('examplesite.dev', 'wp-ultimo'),
'path' => '/',
));
if ($seed) {
$atts['title'] .= " {$seed}";
$atts['domain'] = str_replace('.dev', "{$seed}.dev", (string) $atts['domain']);
} // end if;
return new \WP_Ultimo\Models\Site($atts);
} // end wu_mock_site;
/**
* Returns a mock membership object.
*
* @since 2.0.0
* @return \WP_Ultimo\Models\Membership
*/
function wu_mock_membership() {
return new \WP_Ultimo\Models\Membership(array(
'billing_address' => new \WP_Ultimo\Objects\Billing_Address(array(
'company_name' => 'Company Co.',
'billing_email' => 'company@co.dev',
)),
));
} // end wu_mock_membership;
/**
* Returns a mock product object.
*
* @since 2.0.0
* @return \WP_Ultimo\Models\Product
*/
function wu_mock_product() {
$product = new \WP_Ultimo\Models\Product(array(
'name' => __('Test Product', 'wp-ultimo'),
));
$product->_mocked = true;
return $product;
} // end wu_mock_product;
/**
* Returns a mock customer object.
*
* @since 2.0.0
* @return \WP_Ultimo\Models\Customer
*/
function wu_mock_customer() {
$customer = new \WP_Ultimo\Models\Customer(array(
'billing_address' => new \WP_Ultimo\Objects\Billing_Address(array(
'company_name' => 'Company Co.',
'billing_email' => 'company@co.dev',
)),
));
$customer->_user = (object) array(
'data' => (object) array(
'ID' => '1',
'user_login' => 'mockeduser',
'user_pass' => 'passwordhash',
'user_nicename' => 'mockeduser',
'user_email' => 'mockeduser@dev.dev',
'user_url' => 'https://url.com',
'user_registered' => '2020-12-31 12:00:00',
'user_activation_key' => '',
'user_status' => '0',
'display_name' => 'John McMocked',
'spam' => '0',
'deleted' => '0',
),
);
return $customer;
} // end wu_mock_customer;
/**
* Returns a mock payment object.
*
* @since 2.0.0
* @return \WP_Ultimo\Models\Payment
*/
function wu_mock_payment() {
$payment = new \WP_Ultimo\Models\Payment();
$line_item = new \WP_Ultimo\Checkout\Line_Item(array(
'product' => wu_mock_product(),
));
$payment->set_line_items(array(
$line_item,
));
return $payment;
} // end wu_mock_payment;
/**
* Returns a mock domain object.
*
* @since 2.0.0
* @return \WP_Ultimo\Models\Payment
*/
function wu_mock_domain() {
$domain = new \WP_Ultimo\Models\Domain(array(
'blog_id' => 1,
'domain' => 'example.com',
'active' => true,
'primary_domain' => true,
'secure' => true,
'stage' => 'checking-dns',
));
return $domain;
} // end wu_mock_domain;

107
inc/functions/model.php Normal file
View File

@ -0,0 +1,107 @@
<?php
/**
* Model Helper Functions
*
* @package WP_Ultimo\Functions
* @since 2.0.0
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Cast a list of models to a list of arrays containing the model properties.
*
* @since 2.0.0
*
* @param \WP_Ultimo\Models\Base_Model $model The model to cast to array.
* @return array
*/
function wu_cast_model_to_array($model) {
if (is_a($model, '\\WP_Ultimo\\Models\\Base_Model')) {
$model = $model->to_array();
} // end if;
return $model;
} // end wu_cast_model_to_array;
/**
* Converts a list of Model objects to a list of ID => $label_field
*
* @since 2.0.0
*
* @param array $models The list of models to convert.
* @param string $label_field The name of the field to use.
* @return array
*/
function wu_models_to_options($models, $label_field = 'name') {
$options_list = array();
foreach ($models as $model) {
$options_list[$model->get_id()] = call_user_func(array($model, "get_{$label_field}"));
} // end foreach;
return $options_list;
} // end wu_models_to_options;
/**
* Get the schema of a particular model.
*
* @since 2.0.11
*
* @param string $class_name The fully qualified model name.
* @return array
*/
function wu_model_get_schema($class_name) {
$schema = array();
if (method_exists($class_name, 'get_schema')) {
$schema = $class_name::get_schema();
} // end if;
return $schema;
} // end wu_model_get_schema;
/**
* Returns a list of required fields form a model schema.
*
* @since 2.0.11
*
* @param string $class_name The fully qualified model name.
* @return array
*/
function wu_model_get_required_fields($class_name) {
$required_fields = array();
if (method_exists($class_name, 'validation_rules')) {
$validation_rules = (new $class_name)->validation_rules();
foreach ($validation_rules as $field => $validation_rule) {
if (strpos((string) $validation_rule, 'required|') !== false || $validation_rule === 'required') {
$required_fields[] = $field;
} // end if;
} // end foreach;
} // end if;
return $required_fields;
} // end wu_model_get_required_fields;

View File

@ -0,0 +1,67 @@
<?php
/**
* Number Helper Functions
*
* @package WP_Ultimo\Functions
* @since 2.0.11
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Extracts a int from a string of text.
*
* @since 2.0.0
*
* @param string $str The string to process.
* @return int
*/
function wu_extract_number($str) {
$matches = array();
preg_match_all('/\d+/', $str, $matches);
return isset($matches[0][0]) ? (int) $matches[0][0] : 0;
} // end wu_extract_number;
/**
* Converts formatted values back into floats.
*
* @since 2.0.0
*
* @param mixed $num Formatted number string.
* @param bool $decimal_separator The decimal separator.
* @return float
*/
function wu_to_float($num, $decimal_separator = false) {
if (is_float($num) || is_numeric($num)) {
return (float) $num;
} // end if;
if (empty($decimal_separator)) {
$decimal_separator = wu_get_setting('decimal_separator', '.');
} // end if;
if ($decimal_separator) {
$pattern = '/[^0-9\\' . $decimal_separator . '-]+/';
} else {
$pattern = '/[^0-9-]+/';
} // end if;
$val = preg_replace($pattern, '', (string) $num);
return floatval($val);
} // end wu_to_float;

53
inc/functions/options.php Normal file
View File

@ -0,0 +1,53 @@
<?php
/**
* Options Functions
*
* @package WP_Ultimo\Functions
* @since 2.0.11
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Get the value of a slugfied network option
*
* @since 1.9.6
* @param string $option_name Option name.
* @param mixed $default The default value.
* @return mixed
*/
function wu_get_option($option_name = 'settings', $default = array()) {
$option_value = get_network_option(null, wu_slugify($option_name), $default);
return apply_filters('wu_get_option', $option_value, $option_name, $default);
} // end wu_get_option;
/**
* Save slugfied network option
*
* @since 1.9.6
* @param string $option_name The option name to save.
* @param mixed $value The new value of the option.
* @return boolean
*/
function wu_save_option($option_name = 'settings', $value = false) {
return update_network_option(null, wu_slugify($option_name), $value);
} // end wu_save_option;
/**
* Delete slugfied network option
*
* @since 1.9.6
* @param string $option_name The option name to delete.
* @return boolean
*/
function wu_delete_option($option_name) {
return delete_network_option(null, wu_slugify($option_name));
} // end wu_delete_option;

145
inc/functions/pages.php Normal file
View File

@ -0,0 +1,145 @@
<?php
/**
* Pages Functions
*
* @package WP_Ultimo\Functions
* @since 2.0.11
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Guess the id of the registration page.
*
* @since 2.1.0
* @return int|false
*/
function wu_guess_registration_page() {
return wu_switch_blog_and_run(function() {
$saved_register_page_id = wu_get_setting('default_registration_page', 0);
$page = get_post($saved_register_page_id);
if ($page) {
return $page->ID;
}
$maybe_register_page = get_page_by_path('register');
if ($maybe_register_page && has_shortcode($maybe_register_page->post_content, 'wu_checkout') && $maybe_register_page->post_status === 'publish') {
wu_save_setting('default_registration_page', $maybe_register_page->ID);
function_exists('flush_rewrite_rules') && flush_rewrite_rules(true);
return $maybe_register_page->ID;
}
return false;
});
} // end wu_guess_registration_page;
/**
* Checks if the current post is a registration page.
*
* @since 2.0.0
* @return boolean
*/
function wu_is_registration_page() {
/** @var \WP_Post|null $post */
global $post;
if (!is_main_site()) {
return false;
} // end if;
if (!is_a($post, '\WP_Post')) {
return false;
} // end if;
return absint(wu_guess_registration_page()) === $post->ID;
} // end wu_is_registration_page;
/**
* Checks if the current post is a update page.
*
* @since 2.0.21
* @return boolean
*/
function wu_is_update_page() {
global $post;
if (!is_main_site()) {
return false;
} // end if;
if (!is_a($post, '\WP_Post')) {
return false;
} // end if;
return absint(wu_get_setting('default_update_page', 0)) === $post->ID;
} // end wu_is_update_page;
/**
* Checks if the current post is a new site page.
*
* @since 2.0.21
* @return boolean
*/
function wu_is_new_site_page() {
global $post;
if (!is_main_site()) {
return false;
} // end if;
if (!is_a($post, '\WP_Post')) {
return false;
} // end if;
return absint(wu_get_setting('default_new_site_page', 0)) === $post->ID;
} // end wu_is_new_site_page;
/**
* Checks if the current page is a login page.
*
* @since 2.0.11
* @return bool
*/
function wu_is_login_page() {
global $pagenow;
$is_login_element_present = \WP_Ultimo\UI\Login_Form_Element::get_instance()->is_actually_loaded();
$is_default_wp_login = $pagenow === 'wp-login.php';
return $is_login_element_present || $is_default_wp_login;
} // end wu_is_login_page;

178
inc/functions/payment.php Normal file
View File

@ -0,0 +1,178 @@
<?php
/**
* Payment Functions
*
* @package WP_Ultimo\Functions
* @since 2.0.0
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
use \WP_Ultimo\Models\Payment;
use \WP_Ultimo\Database\Payments\Payment_Status;
/**
* Returns a payment.
*
* @since 2.0.0
*
* @param int $payment_id The ID of the payment.
* @return \WP_Ultimo\Models\Payment|false
*/
function wu_get_payment($payment_id) {
return \WP_Ultimo\Models\Payment::get_by_id($payment_id);
} // end wu_get_payment;
/**
* Queries payments.
*
* @since 2.0.0
*
* @param array $query Query arguments.
* @return \WP_Ultimo\Models\Payment[]
*/
function wu_get_payments($query = array()) {
return \WP_Ultimo\Models\Payment::query($query);
} // end wu_get_payments;
/**
* Returns a line-item.
*
* @since 2.0.0
*
* @param int $line_item_id The ID of the line item id.
* @param int $payment_id The ID of the payment.
* @return \WP_Ultimo\Checkout\Line_Item|false
*/
function wu_get_line_item($line_item_id, $payment_id) {
$payment = wu_get_payment($payment_id);
if (!$payment) {
return false;
} // end if;
$line_items = $payment->get_line_items();
return wu_get_isset($line_items, $line_item_id, false);
} // end wu_get_line_item;
/**
* Gets a payment based on the hash.
*
* @since 2.0.0
*
* @param string $hash The hash for the payment.
* @return \WP_Ultimo\Models\Payment|false
*/
function wu_get_payment_by_hash($hash) {
return \WP_Ultimo\Models\Payment::get_by_hash($hash);
} // end wu_get_payment_by_hash;
/**
* Returns a single payment defined by a particular column and value.
*
* @since 2.0.0
*
* @param string $column The column name.
* @param mixed $value The column value.
* @return \WP_Ultimo\Models\Payment|false
*/
function wu_get_payment_by($column, $value) {
return \WP_Ultimo\Models\Payment::get_by($column, $value);
} // end wu_get_payment_by;
/**
* Creates a new payment.
*
* @since 2.0.0
*
* @param array $payment_data Payment data.
* @param bool $save Whether to save the payment or not.
* @return \WP_Error|\WP_Ultimo\Models\Payment
*/
function wu_create_payment($payment_data, $save = true) {
/**
* Why do we use shortcode atts here?
* Shortcode atts clean the array from not-allowed keys, so we don't need to worry much.
*/
$payment_data = shortcode_atts(array(
'line_items' => array(),
'meta' => array(),
'customer_id' => false,
'membership_id' => false,
'parent_id' => '',
'product_id' => false,
'currency' => wu_get_setting('currency_symbol', 'USD'),
'discount_code' => '',
'subtotal' => 0.00,
'discount_total' => 0.00,
'tax_total' => 0.00,
'total' => 0.00,
'status' => Payment_Status::COMPLETED,
'gateway' => '',
'gateway_payment_id' => '',
'date_created' => wu_get_current_time('mysql', true),
'date_modified' => wu_get_current_time('mysql', true),
'migrated_from_id' => 0,
'skip_validation' => false,
), $payment_data);
$payment = new Payment($payment_data);
if (!$save) {
return $payment;
} // end if;
$saved = $payment->save();
return is_wp_error($saved) ? $saved : $payment;
} // end wu_create_payment;
/**
* Returns a list of the refundable payment types.
*
* Can be filtered if new payment types that
* can be refunded are added by developers.
*
* @since 2.0.0
* @return array
*/
function wu_get_refundable_payment_types() {
$refundable_payment_types = array(
Payment_Status::COMPLETED,
Payment_Status::PARTIAL_REFUND,
);
return apply_filters('wu_get_refundable_payment_type', $refundable_payment_types);
} // end wu_get_refundable_payment_types;
/**
* Returns the icon classes for a payment status.
*
* @since 2.0.0
*
* @param string $payment_status The payment status.
* @return string
*/
function wu_get_payment_icon_classes($payment_status) {
$payment_status_instance = new Payment_Status($payment_status);
return $payment_status_instance->get_icon_classes();
} // end wu_get_payment_icon_classes;

219
inc/functions/product.php Normal file
View File

@ -0,0 +1,219 @@
<?php
/**
* Product Functions
*
* @package WP_Ultimo\Functions
* @since 2.0.0
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
use \WP_Ultimo\Models\Product;
/**
* Returns a product.
*
* @since 2.0.0
*
* @param null|int|string $product_id_or_slug The ID or slug of the product.
* @return Product|false
*/
function wu_get_product($product_id_or_slug) {
if (is_numeric($product_id_or_slug) === false) {
return wu_get_product_by_slug($product_id_or_slug);
} // end if;
return Product::get_by_id($product_id_or_slug);
} // end wu_get_product;
/**
* Queries products.
*
* @since 2.0.0
*
* @param array $query Query arguments.
* @return Product[]
*/
function wu_get_products($query = array()) {
return Product::query($query);
} // end wu_get_products;
/**
* Queries plans.
*
* @since 2.0.0
*
* @param array $query Query arguments.
* @return Product[]
*/
function wu_get_plans($query = array()) {
$query['type'] = 'plan';
/*
* Fixes the order.
*/
$query['order'] = 'ASC';
$query['orderby'] = 'list_order';
return Product::query($query);
} // end wu_get_plans;
/**
* Returns the list of plans as ID -> Name.
*
* @since 2.0.0
* @return array
*/
function wu_get_plans_as_options() {
$options = array();
foreach (wu_get_plans() as $plan) {
$options[$plan->get_id()] = $plan->get_name();
} // end foreach;
return $options;
} // end wu_get_plans_as_options;
/**
* Returns a product based on slug.
*
* @since 2.0.0
*
* @param string $product_slug The slug of the product.
* @return Product|false
*/
function wu_get_product_by_slug($product_slug) {
return Product::get_by('slug', $product_slug);
} // end wu_get_product_by_slug;
/**
* Returns a single product defined by a particular column and value.
*
* @since 2.0.0
*
* @param string $column The column name.
* @param mixed $value The column value.
* @return \WP_Ultimo\Models\Product|false
*/
function wu_get_product_by($column, $value) {
return Product::get_by($column, $value);
} // end wu_get_product_by;
/**
* Creates a new product.
*
* @since 2.0.0
*
* @param array $product_data Product data.
* @return Product|\WP_Error
*/
function wu_create_product($product_data) {
$product_data = wp_parse_args($product_data, array(
'name' => false,
'description' => false,
'currency' => false,
'pricing_type' => false,
'setup_fee' => false,
'parent_id' => 0,
'slug' => false,
'recurring' => false,
'trial_duration' => 0,
'trial_duration_unit' => 'day',
'duration' => 1,
'duration_unit' => 'day',
'amount' => false,
'billing_cycles' => false,
'active' => false,
'type' => false,
'featured_image_id' => 0,
'list_order' => 0,
'date_created' => wu_get_current_time('mysql', true),
'date_modified' => wu_get_current_time('mysql', true),
'migrated_from_id' => 0,
'meta' => array(),
'available_addons' => array(),
'group' => '',
));
$product = new Product($product_data);
$saved = $product->save();
return is_wp_error($saved) ? $saved : $product;
} // end wu_create_product;
/**
* Returns a list of available product groups.
*
* @since 2.0.0
*/
function wu_get_product_groups(): array {
global $wpdb;
$query = "SELECT DISTINCT `product_group` FROM {$wpdb->base_prefix}wu_products WHERE `product_group` <> ''";
$results = array_column($wpdb->get_results($query, ARRAY_A), 'product_group'); // phpcs:ignore
return array_combine($results, $results);
} // end wu_get_product_groups;
/**
* Takes a list of product objects and separates them into plan and addons.
*
* @since 2.0.0
*
* @param Product[] $products List of products.
* @return array first element is the first plan found, the second is an array with all the other products.
*/
function wu_segregate_products($products) {
$results = array(false, array());
foreach ($products as $product) {
if (is_a($product, Product::class) === false) {
$product = wu_get_product($product);
if (!$product) {
continue;
} // end if;
} // end if;
if ($product->get_type() === 'plan' && $results[0] === false) {
$results[0] = $product;
} else {
$results[1][] = $product;
} // end if;
} // end foreach;
return $results;
} // end wu_segregate_products;

View File

@ -0,0 +1,154 @@
<?php
/**
* Reflection Functions
*
* @package WP_Ultimo\Functions
* @since 2.0.11
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
use \WP_Ultimo\Dependencies\phpDocumentor\Reflection\DocBlockFactory;
/**
* Creates the REST API schema blueprint for an object based on setters.
*
* @since 2.0.12
*
* @param string $class_name The model/object class name.
* @return array
*/
function wu_reflection_parse_object_arguments($class_name) {
$base_schema = wu_reflection_parse_arguments_from_setters($class_name, true);
if (wu_are_code_comments_available() === false) {
/*
* @todo add a logger.
*/
return $base_schema;
} // end if;
$reflector = new \ReflectionClass($class_name);
$doc_block_factory = DocBlockFactory::createInstance();
$arguments = array();
/**
* Tries to fetch the database schema, if one exists.
*/
$db_schema = method_exists($class_name, 'get_schema') ? $class_name::get_schema() : false;
foreach ($base_schema as $column) {
try {
$doc_block = $doc_block_factory->create($reflector->getMethod("set_{$column['name']}")->getDocComment());
} catch (\Throwable $exception) {
/**
* Something went wrong trying to parse the doc-blocks.
*/
continue;
} // end try;
$param = $doc_block->getTagsByName('param');
if (isset($param[0]) && is_object($param[0])) {
$arguments[$column['name']] = array(
'description' => (string) $param[0]->getDescription(),
'type' => (string) $param[0]->getType(),
'required' => false, // Actual value set later
);
if ($db_schema) {
$db_column = wu_array_find_first_by($db_schema, 'name', $column['name']);
if ($db_column && wu_get_isset($db_column, 'type') && preg_match('/^ENUM/', (string) $db_column['type'])) {
preg_match_all("/'(.*?)'/", (string) $db_column['type'], $matches);
if (isset($matches[1])) {
$arguments[$column['name']]['enum'] = array_map('strtolower', $matches[1]);
} // end if;
} // end if;
} // end if;
$option = $doc_block->getTagsByName('options');
if (isset($option[0])) {
$description = (string) $option[0]->getDescription();
if (strpos($description, '\\WP_Ultimo\\') !== false) {
$enum_options = new $description();
$arguments[$column['name']]['enum'] = array_map('strtolower', array_keys(array_flip($enum_options->get_options())));
} else {
$arguments[$column['name']]['enum'] = explode(',', strtolower($description));
} // end if;
} // end if;
} // end if;
} // end foreach;
return $arguments;
} // end wu_reflection_parse_object_arguments;
/**
* Use php reflection to generate the documentation for the REST API.
*
* @since 2.0.11
*
* @param string $class_name The class name of the endpoint object.
* @param boolean $return_schema If we should return the schame or just a key => value.
* @return array
*/
function wu_reflection_parse_arguments_from_setters($class_name, $return_schema = true) {
$arguments = array();
foreach (get_class_methods($class_name) as $setter_name) {
if (preg_match('/^set_/', $setter_name)) {
$argument = str_replace('set_', '', $setter_name);
if ($return_schema) {
$arguments[] = array(
'name' => $argument,
'type' => '',
);
} else {
$arguments[] = $argument;
} // end if;
} // end if;
} // end foreach;
return $arguments;
} // end wu_reflection_parse_arguments_from_setters;

133
inc/functions/rest.php Normal file
View File

@ -0,0 +1,133 @@
<?php
/**
* REST API Functions
*
* @package WP_Ultimo\Functions
* @since 2.0.11
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Get a endpoint nice-name from a class name.
*
* Example: '\WP_Ultimo\Models\Product' will return 'product'.
*
* @since 2.0.11
*
* @param string $class_name The class name. The class needs to exist.
* @return string
*/
function wu_rest_get_endpoint_from_class_name($class_name) {
$endpoint = $class_name;
if (class_exists($class_name)) {
$last_segment = explode('\\', $class_name);
$endpoint = strtolower(end($last_segment));
} // end if;
return $endpoint;
} // end wu_rest_get_endpoint_from_class_name;
/**
* Searches the hard-coded schemas for a arguments list.
*
* @since 2.0.11
*
* @param string $class_name The class name. The class needs to exist.
* @param string $context The context. One of two values - create or update.
* @param boolean $force_generate If we should try to generate the args when nothing is found.
* @return array
*/
function wu_rest_get_endpoint_schema($class_name, $context = 'create', $force_generate = false) {
$from_cache = false;
$schema = array();
$endpoint = wu_rest_get_endpoint_from_class_name($class_name);
$schema_file = wu_path("inc/api/schemas/$endpoint-$context.php");
if (file_exists($schema_file) && apply_filters('wu_rest_get_endpoint_schema_use_cache', true)) {
$schema = include $schema_file;
$from_cache = true;
} // end if;
if (empty($schema) && $from_cache === false && $force_generate) {
$schema = wu_rest_generate_schema($class_name, $context);
} // end if;
return $schema;
} // end wu_rest_get_endpoint_schema;
/**
* Generates the rest schema for a class name.
*
* @since 2.0.11
*
* @param string $class_name The class name of the model.
* @param string $context The context. Can be create or update.
* @return array
*/
function wu_rest_generate_schema($class_name, $context = 'create') {
$required_fields = wu_model_get_required_fields($class_name);
$schema = wu_reflection_parse_object_arguments($class_name);
foreach ($schema as $argument_name => &$argument) {
$argument['type'] = wu_rest_treat_argument_type($argument['type']);
$argument['required'] = $context === 'create' ? in_array($argument_name, $required_fields, true) : false;
$schema[$argument_name] = $argument;
} // end foreach;
return $schema;
} // end wu_rest_generate_schema;
/**
* Treat argument types to perform additional validations.
*
* @since 2.0.11
*
* @param string $type The type detected.
* @return string
*/
function wu_rest_treat_argument_type($type) {
$type = (string) $type;
if ($type === 'bool') {
$type = 'boolean';
} elseif ($type === 'int') {
$type = 'integer';
} elseif ($type === 'float') {
$type = 'number';
} // end if;
return $type;
} // end wu_rest_treat_argument_type;

183
inc/functions/scheduler.php Normal file
View File

@ -0,0 +1,183 @@
<?php
/**
* Scheduler Functions
*
* @package WP_Ultimo\Functions
* @since 2.0.0
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Returns how much time it takes until the next queue. In seconds.
*
* @since 2.0.0
* @return int
*/
function wu_get_next_queue_run() {
if (class_exists('ActionScheduler')) {
return wu_switch_blog_and_run(fn() => ActionScheduler::lock()->get_expiration('async-request-runner') - time());
} // end if;
return 0;
} // end wu_get_next_queue_run;
/**
* Enqueue an action to run one time, as soon as possible.
*
* @see https://actionscheduler.org/api/#function-reference--as_enqueue_async_action
*
* @param string $hook The hook to trigger.
* @param array $args Arguments to pass when the hook triggers.
* @param string $group The group to assign this job to.
* @return int The action ID.
*/
function wu_enqueue_async_action($hook, $args = array(), $group = '') {
return wu_switch_blog_and_run(fn() => as_enqueue_async_action($hook, $args, $group));
} // end wu_enqueue_async_action;
/**
* Schedule an action to run one time.
*
* @see https://actionscheduler.org/api/#function-reference--as_schedule_single_action
*
* @param int $timestamp When the job will run.
* @param string $hook The hook to trigger.
* @param array $args Arguments to pass when the hook triggers.
* @param string $group The group to assign this job to.
*
* @return int The action ID.
*/
function wu_schedule_single_action($timestamp, $hook, $args = array(), $group = '') {
return wu_switch_blog_and_run(fn() => as_schedule_single_action($timestamp, $hook, $args, $group));
} // end wu_schedule_single_action;
/**
* Schedule a recurring action.
*
* @see https://actionscheduler.org/api/#function-reference--as_schedule_recurring_action
*
* @param int $timestamp When the first instance of the job will run.
* @param int $interval_in_seconds How long to wait between runs.
* @param string $hook The hook to trigger.
* @param array $args Arguments to pass when the hook triggers.
* @param string $group The group to assign this job to.
*
* @return int The action ID.
*/
function wu_schedule_recurring_action($timestamp, $interval_in_seconds, $hook, $args = array(), $group = '') {
return wu_switch_blog_and_run(fn() => as_schedule_recurring_action($timestamp, $interval_in_seconds, $hook, $args, $group));
} // end wu_schedule_recurring_action;
/**
* Schedule an action that recurs on a cron-like schedule.
*
* @see https://actionscheduler.org/api/#function-reference--as_schedule_cron_action
*
* @param int $timestamp The first instance of the action will be scheduled.
* to run at a time calculated after this timestamp matching the cron
* expression. This can be used to delay the first instance of the action.
* @param string $schedule A cron-link schedule string.
* @see http://en.wikipedia.org/wiki/Cron
* * * * * * *
* ┬ ┬ ┬ ┬ ┬ ┬
* | | | | | |
* | | | | | + year [optional]
* | | | | +----- day of week (0 - 7) (Sunday=0 or 7)
* | | | +---------- month (1 - 12)
* | | +--------------- day of month (1 - 31)
* | +-------------------- hour (0 - 23)
* +------------------------- min (0 - 59)
* @param string $hook The hook to trigger.
* @param array $args Arguments to pass when the hook triggers.
* @param string $group The group to assign this job to.
*
* @return int The action ID.
*/
function wu_schedule_cron_action($timestamp, $schedule, $hook, $args = array(), $group = '') {
return wu_switch_blog_and_run(fn() => as_schedule_cron_action($timestamp, $schedule, $hook, $args, $group));
} // end wu_schedule_cron_action;
/**
* Cancel the next occurrence of a scheduled action.
*
* @see https://actionscheduler.org/api/#function-reference--as_unschedule_action
*
* @param string $hook The hook that the job will trigger.
* @param array $args Args that would have been passed to the job.
* @param string $group The group the job is assigned to.
*
* @return string|null The scheduled action ID if a scheduled action was found, or null if no matching action found.
*/
function wu_unschedule_action($hook, $args = array(), $group = '') {
return wu_switch_blog_and_run(fn() => as_unschedule_action($hook, $args, $group));
} // end wu_unschedule_action;
/**
* Cancel all occurrences of a scheduled action.
*
* @see https://actionscheduler.org/api/#function-reference--as_unschedule_all_actions
*
* @param string $hook The hook that the job will trigger.
* @param array $args Args that would have been passed to the job.
* @param string $group The group the job is assigned to.
*/
function wu_unschedule_all_actions($hook, $args = array(), $group = '' ) {
return wu_switch_blog_and_run(fn() => as_unschedule_all_actions($hook, $args, $group));
} // end wu_unschedule_all_actions;
/**
* Check if there is an existing action in the queue with a given hook, args and group combination.
*
* An action in the queue could be pending, in-progress or async. If the is pending for a time in
* future, its scheduled date will be returned as a timestamp. If it is currently being run, or an
* async action sitting in the queue waiting to be processed, in which case boolean true will be
* returned. Or there may be no async, in-progress or pending action for this hook, in which case,
* boolean false will be the return value.
*
* @see https://actionscheduler.org/api/#function-reference--as_next_scheduled_action
*
* @param string $hook The hook that the job will trigger.
* @param array $args Args that would have been passed to the job.
* @param string $group The group the job is assigned to.
*
* @return int|bool The timestamp for the next occurrence of a pending scheduled action, true for an async or in-progress action or false if there is no matching action.
*/
function wu_next_scheduled_action($hook, $args = null, $group = '') {
return wu_switch_blog_and_run(fn() => as_next_scheduled_action($hook, $args, $group));
} // end wu_next_scheduled_action;
/**
* Find scheduled actions.
*
* @see https://actionscheduler.org/api/#function-reference--as_get_scheduled_actions
*
* @param array $args Possible arguments, with their default values.
* @param string $return_format OBJECT, ARRAY_A, or ids.
*
* @return array
*/
function wu_get_scheduled_actions($args = array(), $return_format = OBJECT) {
return wu_switch_blog_and_run(fn() => as_get_scheduled_actions($args, $return_format));
} // end wu_get_scheduled_actions;

38
inc/functions/session.php Normal file
View File

@ -0,0 +1,38 @@
<?php
/**
* Session Functions
*
* @package WP_Ultimo\Functions
* @since 2.0.0
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Gets or creates a Session object.
*
* @since 2.0.0
*
* @param string $session_key The session key.
* @return \WP_Ultimo\Contracts\Session
*/
function wu_get_session($session_key) {
global $wu_session;
$wu_session = (array) $wu_session;
$session = wu_get_isset($wu_session, $session_key, false);
if ($session && is_a( $session, \WP_Ultimo\Session_Cookie::class)) {
return $session;
} // end if;
$wu_session[$session_key] = new \WP_Ultimo\Session_Cookie($session_key);
return $wu_session[$session_key];
} // end wu_get_session;

186
inc/functions/settings.php Normal file
View File

@ -0,0 +1,186 @@
<?php
/**
* Settings Functions
*
* @package WP_Ultimo\Functions
* @since 2.0.0
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Loads dependencies: the option apis.
*/
require_once wu_path('inc/functions/options.php');
/**
* Returns an array with all the WP Ultimo settings.
*
* @since 2.0.0
* @return array
*/
function wu_get_all_settings() {
return WP_Ultimo()->settings->get_all();
} // end wu_get_all_settings;
/**
* Get a specific settings from the plugin.
*
* @since 2.0.0
*
* @param string $setting Settings name to return.
* @param mixed $default Default value for the setting if it doesn't exist.
* @return mixed The value of that setting
*/
function wu_get_setting($setting, $default = false) {
return WP_Ultimo()->settings->get_setting($setting, $default);
} // end wu_get_setting;
/**
* Saves a specific setting into the database.
*
* @since 2.0.0
*
* @param string $setting Option key to save.
* @param mixed $value New value of the option.
* @return boolean
*/
function wu_save_setting($setting, $value) {
return WP_Ultimo()->settings->save_setting($setting, $value);
} // end wu_save_setting;
/**
* Adds a new settings section.
*
* Sections are a way to organize correlated settings into one cohesive unit.
* Developers should be able to add their own sections, if they need to.
* This is the purpose of this APIs.
*
* @since 2.0.0
*
* @param string $section_slug ID of the Section. This is used to register fields to this section later.
* @param array $atts Section attributes such as title, description and so on.
* @return void
*/
function wu_register_settings_section($section_slug, $atts) {
WP_Ultimo()->settings->add_section($section_slug, $atts);
} // end wu_register_settings_section;
/**
* Adds a new field to a settings section.
*
* Fields are settings that admins can actually change.
* This API allows developers to add new fields to a given settings section.
*
* @since 2.0.0
*
* @param string $section_slug Section to which this field will be added to.
* @param string $field_slug ID of the field. This is used to later retrieve the value saved on this setting.
* @param array $atts Field attributes such as title, description, tooltip, default value, etc.
* @return void
*/
function wu_register_settings_field($section_slug, $field_slug, $atts) {
WP_Ultimo()->settings->add_field($section_slug, $field_slug, $atts);
} // end wu_register_settings_field;
/**
* Adds a help side-panel to the settings page.
*
* @since 2.0.0
*
* @param string $section_slug Section to which this field will be added to.
* @param array $atts Side-panel attributes.
* @return void
*/
function wu_register_settings_side_panel($section_slug, $atts) {
if (wu_request('tab', 'general') !== $section_slug && $section_slug !== 'all') {
return;
} // end if;
$atts = wp_parse_args($atts, array(
'title' => __('Side Panel', 'wp-ultimo'),
'render' => '__return_false',
'show' => '__return_true',
));
$callback = wu_get_isset($atts, 'show', '__return_true');
$should_display = is_callable($callback) && call_user_func($callback);
if (!$should_display) {
return;
} // end if;
$id = sanitize_title($atts['title']);
add_meta_box("wp-ultimo-{$id}", $atts['title'], function() use ($atts) {
call_user_func($atts['render']);
}, 'wu_settings_admin_page', 'side', 'low');
} // end wu_register_settings_side_panel;
/**
* Retrieve the network custom logo.
*
* @param string $size The size of the logo. It could be Thumbnail, Medium, Large or Full.
* @return string With the logo's url.
*/
function wu_get_network_logo($size = 'full') {
switch_to_blog(wu_get_main_site_id());
$settings_logo = wp_get_attachment_image_src(wu_get_setting('company_logo'), $size); // phpcs:ignore
restore_current_blog();
if ($settings_logo) {
return $settings_logo[0];
} // end if;
$logo = wu_get_asset('logo.png', 'img');
$custom_logo = wp_get_attachment_image_src(get_theme_mod('custom_logo'), $size);
if (!empty($custom_logo)) {
$logo = $custom_logo[0];
} // end if;
return apply_filters('wu_get_logo', $logo);
} // end wu_get_network_logo;
/**
* Retrieve the network custom icon.
*
* @param string $size The size of the icon in pixels.
* @return string With the logo's url.
*/
function wu_get_network_favicon($size = '48') {
$custom_icon = get_site_icon_url($size, wu_get_asset('badge.png', 'img'), wu_get_main_site_id());
return $custom_icon;
} // end wu_get_network_favicon;

View File

@ -0,0 +1,37 @@
<?php
/**
* Site Context Functions
*
* @package WP_Ultimo\Functions
* @since 2.0.0
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Tries to switch to a site to run the callback, before returning.
*
* @since 2.0.0
*
* @param callable $callback Callable to run.
* @param int|false $site_id Site to switch to. Defaults to main site.
* @return mixed
*/
function wu_switch_blog_and_run($callback, $site_id = false) {
if (!$site_id) {
$site_id = wu_get_main_site_id();
} // end if;
is_multisite() && switch_to_blog($site_id);
$result = call_user_func($callback); // phpcs:ignore
is_multisite() && restore_current_blog();
return $result;
} // end wu_switch_blog_and_run;

209
inc/functions/site.php Normal file
View File

@ -0,0 +1,209 @@
<?php
/**
* Site Functions
*
* @package WP_Ultimo\Functions
* @since 2.0.0
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Returns the current site.
*
* @since 2.0.0
* @return \WP_Ultimo\Models\Site
*/
function wu_get_current_site() {
return new \WP_Ultimo\Models\Site(get_blog_details());
} // end wu_get_current_site;
/**
* Returns the site object
*
* @since 2.0.0
*
* @param int $id The id of the site.
* @return \WP_Ultimo\Models\Site
*/
function wu_get_site($id) {
return \WP_Ultimo\Models\Site::get_by_id($id);
} // end wu_get_site;
/**
* Gets a site based on the hash.
*
* @since 2.0.0
*
* @param string $hash The hash for the payment.
* @return \WP_Ultimo\Models\Site|false
*/
function wu_get_site_by_hash($hash) {
return \WP_Ultimo\Models\Site::get_by_hash($hash);
} // end wu_get_site_by_hash;
/**
* Queries sites.
*
* @since 2.0.0
*
* @param array $query Query arguments.
* @return \WP_Ultimo\Models\Site[]
*/
function wu_get_sites($query = array()) {
if (!empty($query['search'])) {
$domain_ids = wu_get_domains(array(
'number' => -1,
'search' => '*' . $query['search'] . '*',
'fields' => array('blog_id'),
));
$domain_ids = array_column($domain_ids, 'blog_id');
if (!empty($domain_ids)) {
$query['blog_id__in'] = $domain_ids;
unset($query['search']);
} // end if;
} // end if;
return \WP_Ultimo\Models\Site::query($query);
} // end wu_get_sites;
/**
* Returns the list of Site Templates.
*
* @since 2.0.0
*
* @param array $query Query arguments.
* @return array
*/
function wu_get_site_templates($query = array()) {
$query = wp_parse_args($query, array(
'number' => 9999, // By default, we try to get ALL available templates.
));
return \WP_Ultimo\Models\Site::get_all_by_type('site_template', $query);
} // end wu_get_site_templates;
/**
* Parses a URL and breaks it into different parts
*
* @since 2.0.0
*
* @param string $domain The domain to break up.
* @return object
*/
function wu_handle_site_domain($domain) {
global $current_site;
if (strpos($domain, 'http') === false) {
$domain = "https://{$domain}";
} // end if;
$parsed = parse_url($domain);
return (object) $parsed;
} // end wu_handle_site_domain;
/**
* Creates a new site.
*
* @since 2.0.0
*
* @param array $site_data Site data.
* @return \WP_Error|\WP_Ultimo\Models\Site
*/
function wu_create_site($site_data) {
$current_site = get_current_site();
$site_data = wp_parse_args($site_data, array(
'domain' => $current_site->domain,
'path' => '/',
'title' => false,
'type' => false,
'template_id' => false,
'featured_image_id' => 0,
'duplication_arguments' => false,
'public' => true,
));
$site = new \WP_Ultimo\Models\Site($site_data);
$site->set_public($site_data['public']);
$saved = $site->save();
return is_wp_error($saved) ? $saved : $site;
} // end wu_create_site;
/**
* Returns the correct domain/path combination when creating a new site.
*
* @since 2.0.0
*
* @param string $path_or_subdomain The site path.
* @param string|bool $base_domain The domain selected.
* @return object Object with a domain and path properties.
*/
function wu_get_site_domain_and_path($path_or_subdomain = '/', $base_domain = false) {
global $current_site;
$path_or_subdomain = trim($path_or_subdomain, '/');
$domain = $base_domain ? $base_domain : $current_site->domain;
$d = new \stdClass;
if (is_multisite() && is_subdomain_install()) {
/*
* Treat for the www. case.
*/
$domain = str_replace('www.', '', (string) $domain);
$d->domain = "{$path_or_subdomain}.{$domain}";
$d->path = '/';
return $d;
} // end if;
$d->domain = $domain;
$d->path = "/{$path_or_subdomain}";
/**
* Allow developers to manipulate the domain/path pairs.
*
* This can be useful for a number of things, such as implementing some
* sort of staging solution, different servers, etc.
*
* @since 2.0.0
* @param object $d The current object containing a domain and path keys.
* @param string $path_or_subdomain The original path/subdomain passed to the function.
* @return object An object containing a domain and path keys.
*/
return apply_filters('wu_get_site_domain_and_path', $d, $path_or_subdomain);
} // end wu_get_site_domain_and_path;

74
inc/functions/sort.php Normal file
View File

@ -0,0 +1,74 @@
<?php
/**
* Sort Helper Functions
*
* @package WP_Ultimo\Functions
* @since 2.0.11
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Sort arrays based on a particular column.
*
* @since 2.0.0
*
* @param array $a The first array.
* @param array $b The second array.
* @param string $column The column to compare.
* @return int
*/
function wu_sort_by_column($a, $b, $column = 'order') {
$a[$column] = isset($a[$column]) ? (int) $a[$column] : 50;
$b[$column] = isset($b[$column]) ? (int) $b[$column] : 50;
return $a[$column] - $b[$column];
} // end wu_sort_by_column;
/**
* Sorts the fields.
*
* @param array $a The first array containing a order key.
* @param array $b The second array containing a order key.
* @return int
*/
function wu_sort_by_order($a, $b) {
return wu_sort_by_column($a, $b, 'order');
} // end wu_sort_by_order;
/**
* Loops through the list items and adds a order key if none is set, based on the index.
*
* @since 2.0.7
*
* @param array $list The list of sortable elements.
* @param string $order_key The order key.
* @return array
*/
function wu_set_order_from_index($list, $order_key = 'order') {
$index = 1;
foreach ($list as &$item) {
if (isset($item[$order_key]) === false) {
$index = $index ? $index : 1; // phpcs:ignore
$item[$order_key] = $index * 10;
$index++;
} // end if;
} // end foreach;
return $list;
} // end wu_set_order_from_index;

View File

@ -0,0 +1,89 @@
<?php
/**
* String Helper Functions
*
* @package WP_Ultimo\Functions
* @since 2.0.11
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Converts a string (e.g. 'yes' or 'no' or '1' or '0') to a bool.
*
* @since 2.0.0
*
* @param string $string The string to convert.
* @return bool
*/
function wu_string_to_bool($string) {
return is_bool($string) ? $string : ('on' === strtolower($string) || 'yes' === strtolower($string) || 1 === $string || 'true' === strtolower($string) || '1' === $string);
} // end wu_string_to_bool;
/**
* Converts a slug to a name.
*
* This function turns discount_code into Discount Code, by removing _- and using ucwords.
*
* @since 2.0.0
*
* @param string $slug The slug to convert.
* @return string
*/
function wu_slug_to_name($slug) {
$slug = str_replace(array('-', '_'), ' ', $slug);
return ucwords($slug);
} // end wu_slug_to_name;
/**
* Replaces dashes with underscores on strings.
*
* @since 2.0.0
*
* @param string $str String to replace dashes in.
* @return string
*/
function wu_replace_dashes($str) {
return str_replace('-', '_', $str);
} // end wu_replace_dashes;
/**
* Get the initials for a string.
*
* E.g. Brazilian People will return BP.
*
* @since 2.0.0
*
* @param string $string String to process.
* @param integer $max_size Number of initials to return.
* @return string
*/
function wu_get_initials($string, $max_size = 2) {
$words = explode(' ', $string);
$initials = '';
for ($i = 0; $i < $max_size; $i++) {
if (!isset($words[$i])) {
break;
} // end if;
$initials .= substr($words[$i], 0, 1);
} // end for;
return strtoupper($initials);
} // end wu_get_initials;

141
inc/functions/sunrise.php Normal file
View File

@ -0,0 +1,141 @@
<?php
/**
* Sunrise Functions
*
* @package WP_Ultimo\Functions
* @since 2.0.0
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* General helper functions for sunrise.
*
* @author Arindo Duque
* @category Admin
* @package WP_Ultimo/Sunrise
* @version 2.0.11
*/
function wu_should_load_sunrise() {
return \WP_Ultimo\Sunrise::should_load_sunrise();
} // end wu_should_load_sunrise;
/**
* Get a setting value, when te normal APIs are not available.
*
* Should only be used if we're running in sunrise.
*
* @since 2.0.0
*
* @param string $setting Setting to get.
* @param mixed $default Default value.
* @return mixed
*/
function wu_get_setting_early($setting, $default = false) {
if (did_action('wp_ultimo_load')) {
_doing_it_wrong('wu_get_setting_early', __('Regular setting APIs are already available. You should use wu_get_setting() instead.', 'wp-ultimo'), '2.0.0');
} // end if;
$settings_key = \WP_Ultimo\Settings::KEY;
$settings = get_network_option(null, 'wp-ultimo_' . $settings_key);
return wu_get_isset($settings, $setting, $default);
} // end wu_get_setting_early;
/**
* Set a setting value, when te normal APIs are not available.
*
* Should only be used if we're running in sunrise.
*
* @since 2.0.20
*
* @param string $key Setting to save.
* @param mixed $value Setting value.
*/
function wu_save_setting_early($key, $value) {
if (did_action('wp_ultimo_load')) {
_doing_it_wrong('wu_save_setting_early', __('Regular setting APIs are already available. You should use wu_save_setting() instead.', 'wp-ultimo'), '2.0.20');
} // end if;
$settings_key = \WP_Ultimo\Settings::KEY;
$settings = get_network_option(null, 'wp-ultimo_' . $settings_key);
$settings[$key] = $value;
return update_network_option(null, 'wp-ultimo_' . $settings_key, $settings);
} // end wu_save_setting_early;
/**
* Get the security mode key used to disable security mode
*
* @since 2.0.20
*/
function wu_get_security_mode_key(): string {
$hash = md5((string) get_network_option(null, 'admin_email'));
return substr($hash, 0, 6);
} // end wu_get_security_mode_key;
/**
* Load te dev tools, if they exist.
*
* @since 2.0.11
*
* @param boolean $load If we should load it or not.
* @return string The path to the dev tools folder.
*/
function wu_load_dev_tools($load = true) {
if (defined('WP_ULTIMO_SUNRISE_FILE')) {
/*
* If the vendor folder exists, we are
* for sure, inside a dev environment.
*/
$autoload_file = dirname((string) WP_ULTIMO_SUNRISE_FILE, 2) . '/vendor/autoload.php';
if (file_exists($autoload_file)) {
$load && require_once $autoload_file;
return $autoload_file;
} // end if;
} // end if;
return '';
} // end wu_load_dev_tools;
/**
* Early substitute for wp_kses_data before it exists.
*
* Sanitize content with allowed HTML KSES rules.
*
* This function expects unslashed data.
*
* @since 2.1.0
*
* @param string $data Content to filter, expected to not be escaped.
* @return string Filtered content.
*/
function wu_kses_data($data) {
return function_exists('wp_kses_data') ? wp_kses_data($data) : $data;
} // end wu_kses_data;

229
inc/functions/tax.php Normal file
View File

@ -0,0 +1,229 @@
<?php
/**
* Tax-related Functions
*
* @package WP_Ultimo\Functions
* @since 2.0.0
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
use \WP_Ultimo\Tax\Tax;
/**
* Checks if WP Ultimo should collect taxes.
*
* @since 2.0.0
* @return bool
*/
function wu_should_collect_taxes() {
return (bool) wu_get_setting('enable_taxes', false);
} // end wu_should_collect_taxes;
/**
* Returns the tax categories.
*
* @since 2.0.0
* @return array
*/
function wu_get_tax_categories() {
return Tax::get_instance()->get_tax_rates();
} // end wu_get_tax_categories;
/**
* Returns a given tax category
*
* @since 2.0.0
* @param string $tax_category The tax category to retrieve.
* @return array
*/
function wu_get_tax_category($tax_category = 'default') {
$tax_categories = wu_get_tax_categories();
return wu_get_isset($tax_categories, $tax_category, array(
'rates' => array(),
));
} // end wu_get_tax_category;
/**
* Returns the tax categories as a slug => name array.
*
* @since 2.0.0
*/
function wu_get_tax_categories_as_options(): array {
return array_map(fn($item) => $item['name'], wu_get_tax_categories());
} // end wu_get_tax_categories_as_options;
/**
* Calculates the tax value.
*
* @since 2.0.0
*
* @param float $base_price Original price to calculate based upon.
* @param float $amount Tax amount.
* @param string $type Type of the tax, can be percentage or absolute.
* @param boolean $format If we should format the results or not.
* @param boolean $inclusive If we should calculate taxes as inclusive.
* @return float|string
*/
function wu_get_tax_amount($base_price, $amount, $type, $format = true, $inclusive = false) {
/*
* If the tax is an absolute (type == absolute) value, there's nothing
* to do, pretty much.
*/
$tax_total = $amount;
if ($type === 'percentage') {
if (!$inclusive) {
/**
* Exclusive tax
*
* Calculates tax to be ADDED to the order.
*/
$tax_total = $base_price * ($amount / 100);
} else {
/**
* Inclusive tax
*
* Calculates the tax value inside the total price.
*/
$tax_total = $base_price - ($base_price / (1 + ($amount / 100)));
} // end if;
} // end if;
/*
* Return results
*/
if (!$format) {
return round($tax_total, 2);
} // end if;
return number_format((float) $tax_total, 2);
} // end wu_get_tax_amount;
/**
* Searches for applicable tax rates based on the country.
*
* @todo This can be greatly improved and should support multiple rates
* in the future.
*
* @since 2.0.0
*
* @param string $country The country to search for.
* @param string $tax_category The tax category of the product.
* @param string $state The state to filter by.
* @param string $city The city to filter by.
* @return array
*/
function wu_get_applicable_tax_rates($country, $tax_category = 'default', $state = '*', $city = '*') {
if (!$country) {
return array();
} // end if;
$tax_category = wu_get_tax_category($tax_category);
$results = array();
foreach ($tax_category['rates'] as &$rate) {
/*
* Step 0: Prepare.
*/
$rate['state'] = explode(',', (string) $rate['state']);
$rate['city'] = explode(',', (string) $rate['city']);
$keys_of_interest = array_intersect_key($rate, array(
'country' => 1,
'state' => 1,
'city' => 1,
));
$priority = 0;
foreach ($keys_of_interest as $key => $value) {
$value = is_array($value) ? array_filter($value) : trim((string) $value);
/*
* Step 1: The country.
*/
if ($key === 'country' && $rate['country'] === $country) {
$priority += 10;
} // end if;
/*
* Step 2: The state / province
*/
if ($key === 'state' && $state !== '*') {
if (in_array($state, $value, true)) {
$priority += 1;
} elseif (empty($value) || in_array('*', $value, true)) {
$priority += 0.5;
} // end if;
} // end if;
/*
* Step 3: The city
*/
if ($key === 'city' && $city !== '*') {
if (in_array($city, $value, true)) {
/*
* If it's a full match, gives 1 point.
*/
$priority += 1;
} elseif (empty($value) || in_array('*', $value, true)) {
/*
* If it is a wildcard, award half a point.
*/
$priority += 0.5;
} // end if;
} // end if;
} // end foreach;
if ($priority >= 10) {
$rate['order'] = $priority;
$results[$rate['id']] = $rate;
} // end if;
} // end foreach;
uasort($results, 'wu_sort_by_order');
return array_values($results);
} // end wu_get_applicable_tax_rates;

View File

@ -0,0 +1,96 @@
<?php
/**
* Broadcast Functions
*
* @package WP_Ultimo\Functions
* @since 2.0.0
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Alias function to be used on the templates
*
* @param string $view Template to be get.
* @param array $args Arguments to be parsed and made available inside the template file.
* @param string|false $default_view View to be used if the view passed is not found. Used as fallback.
* @return void
*/
function wu_get_template($view, $args = array(), $default_view = false) {
/**
* Allow plugin developers to add extra variable to the render context globally.
*
* @since 2.0.0
* @param array $args Array containing variables passed by the render call.
* @param string $view Name of the view to be rendered.
* @param string $default_view Name of the fallback_view
* @return array
*/
$args = apply_filters('wp_ultimo_render_vars', $args, $view, $default_view);
$template = wu_path("views/$view.php");
// Make passed variables available
if (is_array($args)) {
extract($args); // phpcs:ignore
} // end if;
/**
* Allows developers to add additional folders to the replaceable list.
*
* Be careful, as allowing additional folders might cause
* out-of-date copies to be loaded instead of the WP Ultimo versions.
*
* @since 2.0.0
* @param array $replaceable_views List of allowed folders.
* @return array
*/
$replaceable_views = apply_filters('wu_view_override_replaceable_views', array(
'signup',
'emails',
'forms',
'checkout'
));
/*
* Only allow template for emails and signup for now
*/
if (preg_match('/(' . implode('\/?|', $replaceable_views) . '\/?' . ')\w+/', $view)) {
$template = apply_filters('wu_view_override', $template, $view, $default_view);
} // end if;
if (!file_exists($template) && $default_view) {
$template = wu_path("views/$default_view.php");
} // end if;
// Load our view
include $template;
} // end wu_get_template;
/**
* Alias function to be used on the templates;
* Rather than directly including the template, it returns the contents inside a variable
*
* @param string $view Template to be get.
* @param array $args Arguments to be parsed and made available inside the template file.
* @param string|false $default_view View to be used if the view passed is not found. Used as fallback.
* @return string
*/
function wu_get_template_contents($view, $args = array(), $default_view = false) {
ob_start();
wu_get_template($view, $args, $default_view); // phpcs:ignore
return ob_get_clean();
} // end wu_get_template_contents;

View File

@ -0,0 +1,34 @@
<?php
/**
* Translation Functions
*
* @package WP_Ultimo\Functions
* @since 2.0.11
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Get the translatable version of a string.
*
* @since 2.0.5
*
* @param string $string The string to get.
* @return string
*/
function wu_get_translatable_string($string) {
if (is_string($string) === false) {
return $string;
} // end if;
$translatable_strings = include WP_ULTIMO_PLUGIN_DIR . '/data/translatable-strings.php';
$translatable_strings = apply_filters('wu_translatable_strings', $translatable_strings, $string);
return wu_get_isset($translatable_strings, $string, $string);
} // end wu_get_translatable_string;

107
inc/functions/url.php Normal file
View File

@ -0,0 +1,107 @@
<?php
/**
* URL Helper Functions
*
* @package WP_Ultimo\Functions
* @since 2.0.0
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Returns the current URL.
*
* @since 2.0.0
* @return string
*/
function wu_get_current_url() {
/*
* When doing ajax requests, we don't want the admin-ajax URL, but
* the initiator URL.
*/
if (wp_doing_ajax() && isset($_SERVER['HTTP_REFERER'])) {
return $_SERVER['HTTP_REFERER'];
} // end if;
return (is_ssl() ? 'https://' : 'http://') . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
} // end wu_get_current_url;
/**
* Replaces or removes the scheme from a URL.
*
* @since 2.0.0
*
* @param string $url The URL to process.
* @param string $new_scheme An empty string, https, or http.
* @return string
*/
function wu_replace_scheme($url, $new_scheme = '') {
return preg_replace('(^https?://)', $new_scheme, $url);
} // end wu_replace_scheme;
/**
* Wrapper to the network_admin_url function for WP Ultimo admin urls.
*
* @since 2.0.0
*
* @param string $path WP Ultimo page.
* @param array $query URL query parameters.
* @return string
*/
function wu_network_admin_url($path, $query = array()) {
$path = sprintf('admin.php?page=%s', $path);
$url = network_admin_url($path);
return add_query_arg($query, $url);
} // end wu_network_admin_url;
/**
* Get the light ajax implementation URL.
*
* @since 2.0.0
*
* @param null|string $when The wu-when parameter to be used, defaults to plugins_loaded.
* @param array $query_args List of additional query args to add to the final URL.
* @param int $site_id The site to use as a base.
* @param null|string $scheme URL scheme. Follows the same rules as the scheme param of get_home_url.
* @return string
*/
function wu_ajax_url($when = null, $query_args = array(), $site_id = false, $scheme = null) {
if (empty($site_id)) {
$site_id = get_current_blog_id();
} // end if;
$base_url = get_home_url($site_id, '', $scheme);
if (!is_array($query_args)) {
$query_args = array();
} // end if;
$query_args['wu-ajax'] = 1;
$query_args['r'] = wp_create_nonce('wu-ajax-nonce');
if ($when) {
$query_args['wu-when'] = base64_encode($when);
} // end if;
$url = add_query_arg($query_args, $base_url);
return apply_filters('wu_ajax_url', $url, $query_args, $when, $site_id);
} // end wu_ajax_url;

45
inc/functions/user.php Normal file
View File

@ -0,0 +1,45 @@
<?php
/**
* User Helper Functions
*
* @package WP_Ultimo\Functions
* @since 2.0.0
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Returns a list of valid selectable roles.
*
* @since 2.0.0
* @param boolean $add_default_option Adds a new default option.
* @return array
*/
function wu_get_roles_as_options($add_default_option = false) {
if (!function_exists('get_editable_roles')) {
require_once(ABSPATH . 'wp-admin/includes/user.php');
} // end if;
$roles = array();
if ($add_default_option) {
$roles['default'] = __('Use WP Ultimo default', 'wp-ultimo');
} // end if;
$editable_roles = get_editable_roles();
foreach ($editable_roles as $role => $details) {
$roles[esc_attr($role)] = translate_user_role($details['name']);
} // end foreach;
return $roles;
} // end wu_get_roles_as_options;

71
inc/functions/webhook.php Normal file
View File

@ -0,0 +1,71 @@
<?php
/**
* Webhooks Functions
*
* @package WP_Ultimo\Functions
* @since 2.0.0
*/
// Exit if accessed directly
defined('ABSPATH') || exit;
use \WP_Ultimo\Models\Webhook;
/**
* Queries webhook.
*
* @since 2.0.0
*
* @param array $query Query arguments.
* @return \WP_Ultimo\Models\Webhook[]
*/
function wu_get_webhooks($query = array()) {
return \WP_Ultimo\Models\Webhook::query($query);
} // end wu_get_webhooks;
/**
* Gets a webhook on the ID.
*
* @since 2.0.0
*
* @param integer $webhook_id ID of the webhook to retrieve.
* @return \WP_Ultimo\Models\Webhook|false
*/
function wu_get_webhook($webhook_id) {
return \WP_Ultimo\Models\Webhook::get_by_id($webhook_id);
} // end wu_get_webhook;
/**
* Creates a new webhook.
*
* Check the wp_parse_args below to see what parameters are necessary.
*
* @since 2.0.0
*
* @param array $webhook_data Webhook attributes.
* @return \WP_Error|\WP_Ultimo\Models\Webhook
*/
function wu_create_webhook($webhook_data) {
$webhook_data = wp_parse_args($webhook_data, array(
'name' => false,
'webhook_url' => false,
'event' => false,
'active' => false,
'event_count' => 0,
'date_created' => wu_get_current_time('mysql', true),
'date_modified' => wu_get_current_time('mysql', true),
'migrated_from_id' => 0,
));
$webhook = new Webhook($webhook_data);
$saved = $webhook->save();
return is_wp_error($saved) ? $saved : $webhook;
} // end wu_create_webhook;