Initial Commit

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

View File

@ -0,0 +1,27 @@
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
background: #f1f1f1;
padding-top: 100px;
padding-left: 20%;
padding-right: 20%;
font-size: 0.85rem; }
body::before {
width: 200px;
content: " ";
position: absolute;
top: 30;
background: url("../../../assets/img/logo.png");
background-size: contain;
height: 40px;
background-position: left center;
background-repeat: no-repeat; }
#listeners {
list-style: none;
margin: 0;
padding: 0; }
#listeners a {
color: #333;
text-decoration: none;
padding: 5px 0;
display: inline-block; }

View File

@ -0,0 +1,43 @@
body {
font-family:
-apple-system,
BlinkMacSystemFont,
"Segoe UI",
Roboto,
Oxygen,
Ubuntu,
Cantarell,
"Open Sans",
"Helvetica Neue",
sans-serif;
background: #f1f1f1;
padding-top: 100px;
padding-left: 20%;
padding-right: 20%;
font-size: 0.85rem;
&::before {
width: 200px;
content: " ";
position: absolute;
top: 30;
background: url("../../../assets/img/logo.png");
background-size: contain;
height: 40px;
background-position: left center;
background-repeat: no-repeat;
}
}
#listeners {
list-style: none;
margin: 0;
padding: 0;
a {
color: #333;
text-decoration: none;
padding: 5px 0;
display: inline-block;
}
}

View File

@ -0,0 +1,48 @@
<?php
/**
* Development Bootstrap File
*
* This file loads some of the tooling we use to develop WP Ultimo.
* It is not part of the final zip file we ship, so there's no need to worry
* about things added in here.
*
* @package Development
* @since 2.1.0
*/
use \Rarst\wps\Plugin as Whoops;
return;
/**
* Give an option to disable whoops automatically via a get query string (whoops-disable)
* or by setting the constant we used to have on previous versions.
*/
if (isset($_GET['whoops-disable']) || (defined('WP_ULTIMO_DISABLE_WHOOPS') && WP_ULTIMO_DISABLE_WHOOPS)) {
return;
} // end if;
$wu_whoops = new Whoops();
/**
* Adds VSCode as the editor, so file paths can be opened
* directly inside VS Code, for debugging and fixes.
*/
$wu_whoops['handler.pretty']->setEditor('vscode');
/**
* Silence Notices and Warnings in general.
*/
$wu_whoops['run']->silenceErrorsInPaths('~.*~', E_NOTICE | E_WARNING);
/**
* Silence known WordPress Core deprecation notices.
*/
$wu_whoops['run']->silenceErrorsInPaths('~/Requests/Cookie/Jar.php', E_DEPRECATED);
/**
* Installs the Whoops handler.
*/
$wu_whoops->run();

View File

@ -0,0 +1,528 @@
<?php
/**
* Development Toolkit
*
* @package WP_Ultimo
* @subpackage Development
* @since 2.0.11
*/
namespace WP_Ultimo\Development;
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Toolkit API Helpers
*
* @since 2.0.11
*/
class Toolkit {
use \WP_Ultimo\Traits\Singleton;
/**
* The parameter used to activate sandbox.
*/
const LISTENER_PARAM = 'development';
/**
* List of registered WordPress hooks.
*
* @since 2.0.11
* @var array
*/
protected $wp_hooks = array();
/**
* Listeners registered.
*
* @since 2.0.11
* @var array
*/
protected $listeners = array();
/**
* Keeps track of number of listeners run.
*
* @since 2.0.11
* @var integer
*/
protected $run = 0;
/**
* If we should die or not.
*
* @since 2.0.11
* @var boolean
*/
protected $should_die = false;
/**
* Keeps track if we already displayed the footer.
*
* @since 2.0.11
* @var boolean
*/
protected $displayed_footer = false;
/**
* Initialize the development hooks and the sandbox.
*
* @since 2.0.11
* @return void
*/
public function init() {
$this->register_default_listeners();
$this->load_sandbox();
add_filter('qm/collectors', array($this, 'register_collector_overview'), 1, 2);
add_filter('qm/outputter/html', array($this, 'add_overview_panel'), 50, 2);
} // end init;
/**
* Registers the default listeners.
*
* @since 2.0.11
* @return void
*/
protected function register_default_listeners() {
/**
* In the case of an empty listener name (?development)
* adds the listener link.
*/
$this->listen('index', array($this, 'render_listeners_menu'), 'init');
/**
* Saves the rest endpoints to the mpb data folder
* on the listener save-rest-arguments.
*/
$this->listen('save-rest-arguments', '__return_false', 'wu_rest_get_endpoint_schema_use_cache');
$this->listen('save-rest-arguments', array($this, 'save_route_arguments'), 'wu_rest_register_routes_general');
$this->listen('save-rest-arguments', array($this, 'save_route_arguments'), 'wu_rest_register_routes_with_id');
} // end register_default_listeners;
/**
* Save route arguments to files to deal with opcache.
*
* @since 2.0.11
*
* @param array $routes Routes passed to WordPress.
* @param string $path The rest api route path.
* @param string $context The context. Can be either 'create' or 'update'.
* @param \WP_Ultimo\Traits\Rest_Api $manager The model manager instance.
* @return void
*/
public function save_route_arguments($routes, $path, $context, $manager) {
$class_name = str_replace('_', '-', strtolower($path));
$args = $manager->get_arguments_schema($context === 'update');
file_put_contents(wu_path("/mpb/data/endpoint/.endpoint-$class_name-$context"), json_encode($args)); // phpcs:ignore
} // end save_route_arguments;
/**
* Adds a listener for development purposes.
*
* @since 2.0.11
*
* @param string $hook The name of the listener hook.
* @param callable $callback The callback to be run.
* @param string $wp_hook The WordPress hook to add this listener to.
* @param integer $order The order to be run.
* @return mixed
*/
public function listen($hook, $callback, $wp_hook = 'wp_ultimo_load', $order = 1) {
$this->listeners[$hook] = ($this->listeners[$hook] ?? 0) + 1;
$this->wp_hooks[$wp_hook] = 1;
$action = $this->get_action($hook, $wp_hook);
$order = $this->get_order($hook, $order);
add_action($action, function(...$arguments) use ($callback, $action, $order) {
$timing_id = sprintf('%s_%s_%s', $action, $this->run + 1, $order);
// phpcs:ignore
do_action('qm/start', $timing_id);
$result = call_user_func_array($callback, $arguments);
// phpcs:ignore
do_action('qm/stop', $timing_id);
$this->run++;
return $result;
}, $order, 100);
return $this;
} // end listen;
/**
* Sets flags for the development environment.
*
* @since 2.0.11
*
* @param array $configs The config constants.
* @return void
*/
public function config($configs = array()) {
$allowed_configs = array(
'QM_DARK_MODE',
'QM_DB_EXPENSIVE',
'QM_DISABLED',
'QM_DISABLE_ERROR_HANDLER',
'QM_ENABLE_CAPS_PANEL',
'QM_HIDE_CORE_ACTIONS',
'QM_HIDE_SELF',
'QM_NO_JQUERY',
'QM_SHOW_ALL_HOOKS',
);
foreach ($configs as $constant_name => $constant_value) {
if (in_array($constant_name, $allowed_configs, true)) {
// phpcs:ignore
defined($constant_name) === false && define($constant_name, $constant_value);
} // end if;
} // end foreach;
} // end config;
/**
* Marks the development environment to finish execution after all listeners are run.
*
* @since 2.0.11
*
* @param string|bool $should_die False to prevent it from dying, or a WordPress hook to wait before dying.
* @return void
*/
public function die($should_die = true) {
if ($should_die === true) {
$should_die = is_admin() ? 'admin_enqueue_scripts' : 'wp_enqueue_scripts';
} // end if;
$this->should_die = $should_die;
} // end die;
/**
* Run a registered listener.
*
* @since 2.0.11
*
* @param string $wp_hook The WordPress hook to run.
* @param array $arguments The arguments passed to the WordPress hook.
* @return mixed
*/
public function run_listener($wp_hook, $arguments = array()) {
$listener = wu_request(self::LISTENER_PARAM, 'no-dev-param');
if ($listener === 'no-dev-param') {
return current($arguments);
} elseif ($listener === '') {
$listener = 'index';
} // end if;
$action = $this->get_action($listener, $wp_hook);
return do_action_ref_array($action, $arguments); // phpcs:ignore
} // end run_listener;
/**
* Loads the sandbox environment.
*
* Checks for the existence of a development.php file
* inside the root folder and loads it if it does.
*
* @since 2.0.11
* @return void
*/
protected function load_sandbox() {
$dev_file = wu_path_join(dirname((string) WP_ULTIMO_SUNRISE_FILE, 2), 'development.php');
if (file_exists($dev_file)) {
/**
* Make the $toolkit variable available
* to the development.php file.
*/
$toolkit = $this;
include $dev_file;
} // end if;
$wp_hooks = array_keys($this->wp_hooks);
foreach ($wp_hooks as $wp_hook) {
add_action($wp_hook, fn(...$arguments) => $this->run_listener($wp_hook, $arguments), 0, 100);
} // end foreach;
add_action('shutdown', array($this, 'setup_query_monitor'));
if ($this->should_die) {
$this->dump_and_die(end($wp_hooks));
} // end if;
} // end load_sandbox;
/**
* Setups the query monitor integration.
*
* @since 2.0.11
* @return void
*/
public function setup_query_monitor() {
if (class_exists('\QM_Dispatchers')) {
// phpcs:ignore
do_action('qm/debug', sprintf('Actions with listeners: %s', $this->get_wp_hooks_list()));
// phpcs:ignore
do_action('qm/debug', sprintf('Listeners: %s', $this->get_listeners_list()));
// phpcs:ignore
$dispatcher = \QM_Dispatchers::get('html');
if (!$dispatcher) {
return;
} // end if;
$dispatcher->did_footer = true;
if ($this->should_die && $this->run) {
$this->enqueue_scripts($dispatcher);
} // end if;
} // end if;
} // end setup_query_monitor;
/**
* Registers the collector overview.
*
* @since 2.0.11
*
* @param array $collectors The collectors array.
* @param \QueryMonitor $qm The Query Monitor instance.
* @return array
*/
public function register_collector_overview(array $collectors, \QueryMonitor $qm) {
$collectors['wp-ultimo'] = new Query_Monitor\Collectors\Collector_Overview();
return $collectors;
} // end register_collector_overview;
/**
* Adds the overview panel.
*
* @since 2.0.11
*
* @param array $output Array containing all registered output-generators.
* @return array
*/
public function add_overview_panel($output) {
$collector = \QM_Collectors::get('wp-ultimo');
$output['wp-ultimo'] = new Query_Monitor\Panel\Overview($collector);
return $output;
} // end add_overview_panel;
/**
* Manually enqueues query monitor and WP Ultimo styles.
*
* @since 2.0.11
*
* @param \QM_Dispatcher $dispatcher The Query Monitor dispatcher object.
* @return void
*/
protected function enqueue_scripts($dispatcher) {
echo sprintf('<link rel="stylesheet" id="toolkit" href="%s" type="text/css" media="all">', wu_url('inc/development/assets/development.css'));
wp_print_styles(array(
'wu-admin',
));
$dispatcher->manually_print_assets(); // phpcs:ignore
} // end enqueue_scripts;
/**
* Returns a comma-separated list of listeners.
*
* @since 2.0.11
*/
protected function get_listeners_list(): string {
$listener_names = array_keys($this->listeners);
return implode(', ', $listener_names);
} // end get_listeners_list;
/**
* Returns a comma-separated list of WordPress hooks.
*
* @since 2.0.11
*/
protected function get_wp_hooks_list(): string {
$wp_hook_names = array_keys($this->wp_hooks);
return implode(', ', $wp_hook_names);
} // end get_wp_hooks_list;
/**
* Dumps the development content and kill the execution.
*
* @since 2.0.11
*
* @param string $hook Hook to die on.
* @return void
*/
protected function dump_and_die($hook) {
add_action($hook, function() use ($hook) {
if (did_action($this->should_die) && $this->run) {
$this->render_listeners_menu();
do_action('shutdown'); // phpcs:ignore
$message = sprintf('Execution killed on %s.', $hook);
do_action('qm/info', $message); // phpcs:ignore
die();
} else {
return $this->dump_and_die($this->should_die);
} // end if;
}, 110);
} // end dump_and_die;
/**
* Get the order of a newly added listener.
*
* @since 2.0.11
*
* @param string $hook The listener action name.
* @param integer $order The order of execution.
* @return integer
*/
protected function get_order($hook, $order = 1) {
return 10 + (absint($this->listeners[$hook]) * $order * 10) + 5;
} // end get_order;
/**
* Get the action name based on the listener hook and WP action.
*
* @since 2.0.11
*
* @param string $hook The listener action name.
* @param string $wp_hook The WordPress hook.
*/
protected function get_action($hook, $wp_hook): string {
$hook = str_replace('-', '_', $hook);
return sprintf('wu_sandbox_run_%s_%s', $hook, $wp_hook);
} // end get_action;
/**
* Render the list of listeners with links.
*
* @since 2.0.11
* @return void
*/
public function render_listeners_menu() {
/**
* Make sure we display it only once.
*/
if ($this->displayed_footer) {
return;
} // end if;
// phpcs:disable
echo '
<div class="wu-styling">
<strong class="wu-block wu-mb-2 wu-mt-10">Listeners</strong>
<ul id="listeners">';
foreach (array_keys($this->listeners) as $listener) {
echo sprintf(
'<li><a href="%s">→ Listener "%s"</a></li>',
add_query_arg(self::LISTENER_PARAM, $listener),
$listener
);
} // end foreach;
echo '
</ul>
</div>'; // phpcs: enable
$this->displayed_footer = true;
} // end render_listeners_menu;
} // end class Toolkit;

View File

@ -0,0 +1,68 @@
<?php
/**
* WP Ultimo overview collector.
*
* @package query-monitor
* @since 2.0.11
*/
namespace WP_Ultimo\Development\Query_Monitor\Collectors;
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Every QM Panel needs a collector.
*
* @since 2.0.11
*/
class Collector_Overview extends \QM_Collector {
/**
* Sets the id of the collector.
*
* @since 2.0.11
* @var string
*/
public $id = 'wp-ultimo';
/**
* Set-up routines.
*
* @since 2.0.11
* @return void
*/
public function set_up() {
parent::set_up();
} // end set_up;
/**
* Tear down routines.
*
* @since 2.0.11
* @return void
*/
public function tear_down() {
parent::tear_down();
} // end tear_down;
/**
* Process the collection.
*
* Here, we just need to add items to the
* data property array.
*
* @since 2.0.11
* @return void
*/
public function process() {
$this->data = $_REQUEST;
} // end process;
} // end class Collector_Overview;

View File

@ -0,0 +1,120 @@
<?php
/**
* The WP Ultimo Overview QM Panel
*
* @package WP_Ultimo
* @subpackage Development\Query_Monitor\Panel
* @since 2.0.11
*/
namespace WP_Ultimo\Development\Query_Monitor\Panel;
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* The WP Ultimo Overview QM Panel
*
* @since 2.0.11
*/
class Overview extends \QM_Output_Html {
/**
* Initializes the panel.
*
* @since 2.0.11
*
* @param \QM_Collector $collector The collector associated with the panel.
*/
public function __construct($collector) {
parent::__construct($collector);
add_filter('qm/output/menus', array($this, 'admin_menu'), 1000);
add_filter('qm/output/panel_menus', array($this, 'panel_menu'), 1000);
} // end __construct;
/**
* The name of the panel.
*
* @since 2.0.11
* @return string
*/
public function name() {
return __('WP Ultimo', 'wp-ultimo');
} // end name;
/**
* Output the contents of the panel.
*
* @since 2.0.11
* @return void
*/
public function output() {
$data = $this->collector->get_data();
$this->before_tabular_output(); // phpcs:disable ?>
<thead>
<th>Header 1</th>
<th>Header 2</th>
</thead>
<tbody>
<td>Value Title</td>
<td>Value</td>
</tbody>
<?php // phpcs:enable
$this->after_tabular_output();
$this->before_non_tabular_output();
$data = $this->collector->get_data();
$this->after_non_tabular_output();
} // end output;
/**
* Adds the panel to the admin panel.
*
* @since 2.0.11
*
* @param array $menu The original menu.
* @return array
*/
public function admin_menu(array $menu) {
return $menu;
} // end admin_menu;
/**
* Adds a panel menu for the panel.
*
* @since 2.0.11
*
* @param array $menu The admin panel menu.
* @return array
*/
public function panel_menu(array $menu) {
$new_menu = array(
'wp-ultimo' => $this->menu(array(
'title' => esc_html__('WP Ultimo', 'wp-ultimo'),
'id' => 'wp-ultimo',
)),
);
return $new_menu + $menu;
} // end panel_menu;
} // end class Overview;