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,400 @@
<?php
/**
* Handles limitations to post types, uploads and more.
*
* @package WP_Ultimo
* @subpackage Limits
* @since 2.0.0
*/
namespace WP_Ultimo\Limits;
// Exit if accessed directly
defined('ABSPATH') || exit;
/**
* Handles limitations to post types, uploads and more.
*
* @since 2.0.0
*/
class Theme_Limits {
use \WP_Ultimo\Traits\Singleton;
/**
* List of themes that are not available.
*
* @since 2.0.0
* @var array
*/
protected $themes_not_available = array();
/**
* Keep a cache of the results as the check is costly.
*
* @since 2.1.2
* @var null|false|string
*/
protected $forced_theme_stylesheet = null;
/**
* Keep a cache of the template results as the check is costly.
*
* @since 2.1.2
* @var null|false|string
*/
protected $forced_theme_template = null;
/**
* Runs on the first and only instantiation.
*
* @since 2.0.0
* @return void
*/
public function init() {
/**
* We need to bail if we're inside the WP CLI context and the
* `skip-plugins` flag is present.
*
* This is due to the fact that without WP Ultimo being loaded,
* the functions and classes we'll need to perform any kind of proper
* checks won't be available. To validate if we're being loaded or not,
* we check for the function `wu_get_product`.
*
* @since 2.1.0
*/
if (wu_cli_is_plugin_skipped('wp-ultimo')) {
return;
}
add_action('wu_sunrise_loaded', array($this, 'load_limitations'));
} // end init;
/**
* Apply limitations if they are available.
*
* @since 2.0.0
* @return void
*/
public function load_limitations() {
if (wu_get_current_site()->has_limitations()) {
add_filter('stylesheet', array($this, 'force_active_theme_stylesheet'));
add_filter('template', array($this, 'force_active_theme_template'));
add_filter('allowed_themes', array($this, 'add_extra_available_themes'));
add_filter('site_allowed_themes', array($this, 'add_extra_available_themes'));
add_filter('wp_prepare_themes_for_js', array($this, 'maybe_remove_activate_button'));
add_action('admin_enqueue_scripts', array($this, 'hacky_remove_activate_button'));
add_action('admin_footer-themes.php', array($this, 'modify_backbone_template'));
add_action('customize_changeset_save_data', array($this, 'prevent_theme_activation_on_customizer'), 99, 2);
} // end if;
} // end load_limitations;
/**
* Prevents sub-site admins from switching to locked themes inside the customizer.
*
* @since 2.0.10
*
* @param array $data The changeset array being saved.
* @param array $context The context array with tons of info about the current customizer session.
* @return array|void
*/
public function prevent_theme_activation_on_customizer($data, $context) {
if (wu_get_current_site()->has_limitations() === false) {
return $data;
} // end if;
$pending_theme_switch = $context['manager']->is_theme_active() === false;
if ($pending_theme_switch === false) {
return $data;
} // end if;
$new_theme = $context['manager']->theme()->stylesheet;
$theme_limitations = wu_get_current_site()->get_limitations()->themes;
if ($theme_limitations->allowed($new_theme, 'not_available')) {
$response = array(
'code' => 'not-available',
'message' => __('This theme is not available on your current plan.', 'wp-ultimo'),
);
wp_send_json($response, 'not-available');
exit;
} // end if;
return $data;
} // end prevent_theme_activation_on_customizer;
/**
* Removes the activate button from not available themes.
*
* This uses a very hack-y approach due to a bug on WordPress
* Core. The problem is that the WP code assumes that no one
* with the capability of activating themes would be unable
* to activate a theme (in cases of external factors for example).
*
* @todo Send patch to WordPress core.
* @since 2.0.0
* @return void
*/
public function hacky_remove_activate_button() {
global $pagenow;
if (!function_exists('wu_generate_upgrade_to_unlock_url')) {
return;
} // end if;
if ($pagenow !== 'themes.php') {
return;
} // end if;
$membership = wu_get_current_site()->get_membership();
if (!$membership) {
return;
} // end if;
$upgrade_button = wu_generate_upgrade_to_unlock_button(__('Upgrade to unlock', 'wp-ultimo'), array(
'module' => 'themes',
'type' => 'EXTENSION',
'classes' => 'button',
));
wp_localize_script('theme', 'wu_theme_settings', array(
'themes_not_available' => $this->themes_not_available,
'replacement_message' => $upgrade_button,
));
} // end hacky_remove_activate_button;
/**
* Modifies the default WordPress theme page template.
*
* @since 2.0.0
* @return void
*/
public function modify_backbone_template() { // phpcs:disable ?>
<script type="text/javascript">
if (typeof wu_theme_settings !== 'undefined') {
let content = document.getElementById("tmpl-theme").innerHTML;
content = content.replace(new RegExp('(<a class="button activate".*<\/a>)', 'g'), '<# if ( !wu_theme_settings.themes_not_available.includes(data.id) ) { #>$1<# } else { #> {{{ wu_theme_settings.replacement_message.replace("EXTENSION", data.id) }}} <# } #>');
document.getElementById("tmpl-theme").innerHTML = content;
} // end if;
</script>
<?php // phpcs:enable
} // end modify_backbone_template;
/**
* Checks if a theme needs to have the activate button removed.
*
* @since 2.0.0
*
* @param array $themes The list of themes available.
* @return array
*/
public function maybe_remove_activate_button($themes) {
if (is_main_site()) {
return $themes;
} // end if;
$theme_limitations = wu_get_current_site()->get_limitations()->themes;
foreach ($themes as $stylesheet => &$data) {
$data['notAvailable'] = false;
if ($theme_limitations->allowed($stylesheet, 'not_available')) {
$data['actions']['activate'] = '';
/*
* Hack solution due to core WP
* not allowing us to filter out the button.
*/
$data['notAvailable'] = true;
/*
* Adds to the not available list
* for our hack-y solution.
*/
$this->themes_not_available[] = $stylesheet;
} // end if;
} // end foreach;
return $themes;
} // end maybe_remove_activate_button;
/**
* Force the activation of one particularly selected theme.
*
* @since 2.0.0
*
* @param string $stylesheet The default theme being used.
* @return string
*/
public function force_active_theme_stylesheet($stylesheet) {
if (is_main_site()) {
return $stylesheet;
} // end if;
$forced_stylesheet = $this->get_forced_theme_stylesheet();
return $forced_stylesheet ? $forced_stylesheet : $stylesheet;
} // end force_active_theme_stylesheet;
/**
* Force the activation of one particularly selected theme.
*
* @since 2.1.2
*
* @param string $template The default theme being used.
* @return string
*/
public function force_active_theme_template($template) {
if (is_main_site()) {
return $template;
} // end if;
$forced_template = $this->get_forced_theme_template();
return $forced_template ? $forced_template : $template;
} // end force_active_theme_template;
/**
* Deactivates the plugins that people are not allowed to use.
*
* @since 2.0.0
*
* @param array $themes Array with the plugins activated.
* @return array
*/
public function add_extra_available_themes($themes) {
/*
* Bail on network admin =)
*/
if (is_network_admin()) {
return $themes;
} // end if;
$theme_limitations = wu_get_current_site()->get_limitations()->themes;
$_themes = $theme_limitations->get_all_themes();
foreach ($_themes as $theme_stylesheet) {
$should_appear = $theme_limitations->allowed($theme_stylesheet, 'visible');
if (!$should_appear && isset($themes[$theme_stylesheet])) {
unset($themes[$theme_stylesheet]);
} elseif ($should_appear && !isset($themes[$theme_stylesheet])) {
$themes[] = $theme_stylesheet;
} // end if;
} // end foreach;
return $themes;
} // end add_extra_available_themes;
/**
* Get the stylesheet of the theme that is forced to be active.
*
* @since 2.1.2
*
* @return string|bool The stylesheet of the theme that is forced to be active or false.
*/
protected function get_forced_theme_stylesheet() {
if ($this->forced_theme_stylesheet === null) {
$this->forced_theme_stylesheet = wu_get_current_site()->get_limitations()->themes->get_forced_active_theme();
} // end if;
return $this->forced_theme_stylesheet;
} // end get_forced_theme_stylesheet;
/**
* Get the template of the theme that is forced to be active.
*
* @since 2.1.2
*
* @return string|bool The template of the theme that is forced to be active or false.
*/
protected function get_forced_theme_template() {
if ($this->forced_theme_template === null) {
$stylesheet = $this->get_forced_theme_stylesheet();
$this->forced_theme_template = $stylesheet ? wp_get_theme($stylesheet)->get_template() : false;
} // end if;
return $this->forced_theme_template;
} // end get_forced_theme_template;
} // end class Theme_Limits;