feat(mu-plugins): introduce HostForge systems module for platform-managed WordPress behavior
This commit is contained in:
17
code/wp-content/mu-plugins/hostforge-systems.php
Normal file
17
code/wp-content/mu-plugins/hostforge-systems.php
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
/**
|
||||
* Plugin Name: HostForge Systems
|
||||
* Description: Required HostForge system integrations and platform-enforced WordPress behavior.
|
||||
* Author: HostForge
|
||||
* Version: 1.0.0
|
||||
*/
|
||||
|
||||
if (! defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
$hostforge_bootstrap = __DIR__ . '/hostforge-systems/bootstrap.php';
|
||||
|
||||
if (file_exists($hostforge_bootstrap)) {
|
||||
require_once $hostforge_bootstrap;
|
||||
}
|
||||
60
code/wp-content/mu-plugins/hostforge-systems/bootstrap.php
Normal file
60
code/wp-content/mu-plugins/hostforge-systems/bootstrap.php
Normal file
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
if (! defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the HostForge Systems base path.
|
||||
*/
|
||||
if (! defined('HOSTFORGE_SYSTEMS_PATH')) {
|
||||
define('HOSTFORGE_SYSTEMS_PATH', __DIR__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the HostForge Systems base URL.
|
||||
*/
|
||||
if (! defined('HOSTFORGE_SYSTEMS_URL')) {
|
||||
define('HOSTFORGE_SYSTEMS_URL', content_url('mu-plugins/hostforge-systems'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the required HostForge Systems core files.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function hostforge_systems_load_core_files()
|
||||
{
|
||||
$files = [
|
||||
HOSTFORGE_SYSTEMS_PATH . '/src/Core/Module_Interface.php',
|
||||
HOSTFORGE_SYSTEMS_PATH . '/src/Core/Notice.php',
|
||||
HOSTFORGE_SYSTEMS_PATH . '/src/Core/Loader.php',
|
||||
HOSTFORGE_SYSTEMS_PATH . '/src/Modules/CoreUpdates/Disable_Core_Updates.php',
|
||||
];
|
||||
|
||||
foreach ($files as $file) {
|
||||
if (file_exists($file)) {
|
||||
require_once $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hostforge_systems_load_core_files();
|
||||
|
||||
/**
|
||||
* Boot the HostForge Systems loader.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function hostforge_systems_boot()
|
||||
{
|
||||
$loader = new \HostForgeSystems\Core\Loader();
|
||||
|
||||
$loader->register_module(
|
||||
new \HostForgeSystems\Modules\CoreUpdates\Disable_Core_Updates()
|
||||
);
|
||||
|
||||
$loader->boot();
|
||||
}
|
||||
|
||||
hostforge_systems_boot();
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
namespace HostForgeSystems\Core;
|
||||
|
||||
if (! defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers and boots HostForge Systems modules.
|
||||
*/
|
||||
class Loader
|
||||
{
|
||||
/**
|
||||
* Registered HostForge Systems modules.
|
||||
*
|
||||
* @var array<int, \HostForgeSystems\Core\Module_Interface>
|
||||
*/
|
||||
protected array $modules = [];
|
||||
|
||||
/**
|
||||
* Register a module instance.
|
||||
*
|
||||
* @param \HostForgeSystems\Core\Module_Interface $module Module instance.
|
||||
* @return void
|
||||
*/
|
||||
public function register_module(Module_Interface $module): void
|
||||
{
|
||||
$this->modules[] = $module;
|
||||
}
|
||||
|
||||
/**
|
||||
* Boot all registered modules.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function boot(): void
|
||||
{
|
||||
foreach ($this->modules as $module) {
|
||||
$module->register();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace HostForgeSystems\Core;
|
||||
|
||||
if (! defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the contract for all HostForge Systems modules.
|
||||
*/
|
||||
interface Module_Interface
|
||||
{
|
||||
/**
|
||||
* Register WordPress hooks for the module.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register(): void;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace HostForgeSystems\Core;
|
||||
|
||||
if (! defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides reusable helpers for rendering WordPress admin notices.
|
||||
*/
|
||||
class Notice
|
||||
{
|
||||
/**
|
||||
* Render a WordPress admin notice.
|
||||
*
|
||||
* @param string $message Notice message.
|
||||
* @param string $type Notice type: info, success, warning, error.
|
||||
* @return void
|
||||
*/
|
||||
public static function render(string $message, string $type = 'info'): void
|
||||
{
|
||||
$allowed_types = ['info', 'success', 'warning', 'error'];
|
||||
|
||||
if (! in_array($type, $allowed_types, true)) {
|
||||
$type = 'info';
|
||||
}
|
||||
|
||||
printf(
|
||||
'<div class="notice notice-%1$s"><p>%2$s</p></div>',
|
||||
esc_attr($type),
|
||||
wp_kses_post($message)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
<?php
|
||||
|
||||
namespace HostForgeSystems\Modules\CoreUpdates;
|
||||
|
||||
use HostForgeSystems\Core\Module_Interface;
|
||||
use HostForgeSystems\Core\Notice;
|
||||
use stdClass;
|
||||
|
||||
if (! defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables WordPress core updates inside wp-admin.
|
||||
*
|
||||
* WordPress core updates must be managed through the HostForge Dashboard.
|
||||
*/
|
||||
class Disable_Core_Updates implements Module_Interface
|
||||
{
|
||||
/**
|
||||
* Register WordPress hooks for this module.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register(): void
|
||||
{
|
||||
add_filter('auto_update_core', '__return_false');
|
||||
add_filter('allow_dev_auto_core_updates', '__return_false');
|
||||
add_filter('allow_minor_auto_core_updates', '__return_false');
|
||||
add_filter('allow_major_auto_core_updates', '__return_false');
|
||||
|
||||
add_filter('pre_site_transient_update_core', [$this, 'filter_core_update_transient']);
|
||||
|
||||
add_action('admin_init', [$this, 'remove_core_update_nag']);
|
||||
add_action('admin_init', [$this, 'block_manual_core_upgrade']);
|
||||
add_action('admin_notices', [$this, 'render_updates_screen_notice']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Override the WordPress core update transient.
|
||||
*
|
||||
* This makes WordPress behave as if no core updates are available
|
||||
* from wp-admin.
|
||||
*
|
||||
* @param mixed $transient Existing transient value.
|
||||
* @return \stdClass
|
||||
*/
|
||||
public function filter_core_update_transient($transient): stdClass
|
||||
{
|
||||
if (! is_object($transient)) {
|
||||
$transient = new stdClass();
|
||||
}
|
||||
|
||||
$transient->updates = [];
|
||||
$transient->version_checked = get_bloginfo('version');
|
||||
$transient->last_checked = time();
|
||||
|
||||
return $transient;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the default WordPress update nag from the admin area.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function remove_core_update_nag(): void
|
||||
{
|
||||
remove_action('admin_notices', 'update_nag', 3);
|
||||
}
|
||||
|
||||
/**
|
||||
* Block manual WordPress core upgrade attempts from wp-admin.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function block_manual_core_upgrade(): void
|
||||
{
|
||||
if (! is_admin()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (! current_user_can('update_core')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$page = isset($_GET['page']) ? sanitize_text_field(wp_unslash($_GET['page'])) : '';
|
||||
$action = isset($_GET['action']) ? sanitize_text_field(wp_unslash($_GET['action'])) : '';
|
||||
|
||||
$is_core_upgrade_request =
|
||||
$action === 'do-core-upgrade' ||
|
||||
$page === 'update-core.php' ||
|
||||
(isset($_SERVER['PHP_SELF']) && str_contains(wp_unslash($_SERVER['PHP_SELF']), 'update-core.php'));
|
||||
|
||||
if (! $is_core_upgrade_request) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($action !== 'do-core-upgrade') {
|
||||
return;
|
||||
}
|
||||
|
||||
wp_die(
|
||||
esc_html__(
|
||||
'WordPress core updates are disabled in wp-admin. Please use the HostForge Dashboard to manage core updates.',
|
||||
'hostforge-systems'
|
||||
),
|
||||
esc_html__('Core Updates Disabled', 'hostforge-systems'),
|
||||
['response' => 403]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a HostForge notice on the Updates screen.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function render_updates_screen_notice(): void
|
||||
{
|
||||
if (! $this->is_updates_screen()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Notice::render(
|
||||
'<strong>HostForge Notice:</strong> WordPress core updates are managed through the HostForge Dashboard and are disabled in wp-admin.',
|
||||
'info'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the current screen is the Updates screen.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function is_updates_screen(): bool
|
||||
{
|
||||
if (! is_admin() || ! function_exists('get_current_screen')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$screen = get_current_screen();
|
||||
|
||||
if (! $screen || empty($screen->id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $screen->id === 'update-core';
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Plugin Name: HostForge Platform
|
||||
*/
|
||||
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
function hf_config($key, $default = null) {
|
||||
return defined($key) ? constant($key) : $default;
|
||||
}
|
||||
|
||||
add_action('init', function () {
|
||||
if (hf_config('HOSTFORGE_ENABLE_TELEMETRY', false)) {
|
||||
// later: send telemetry
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user