Initial commit: Atomaste website
This commit is contained in:
@@ -0,0 +1,209 @@
|
||||
<?php
|
||||
|
||||
namespace Hostinger\Admin;
|
||||
|
||||
use Hostinger\Admin\Menu;
|
||||
use Hostinger\LlmsTxtGenerator\LlmsTxtFileHelper;
|
||||
use Hostinger\WpMenuManager\Menus;
|
||||
use Hostinger\Helper;
|
||||
use Hostinger\WpHelper\Utils;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Class Hostinger_Admin_Assets
|
||||
*
|
||||
* Handles the enqueueing of styles and scripts for the Hostinger admin pages.
|
||||
*/
|
||||
class Assets {
|
||||
/**
|
||||
* @var Helper Instance of the Hostinger_Helper class.
|
||||
*/
|
||||
private Helper $helper;
|
||||
|
||||
/**
|
||||
* @var LlmsTxtFileHelper
|
||||
*/
|
||||
private LlmsTxtFileHelper $llms_txt_file_helper;
|
||||
|
||||
/**
|
||||
* @var Utils
|
||||
*/
|
||||
private Utils $utils;
|
||||
|
||||
public function __construct() {
|
||||
$this->llms_txt_file_helper = new LlmsTxtFileHelper();
|
||||
$this->helper = new Helper();
|
||||
$this->utils = new Utils();
|
||||
$admin_path = parse_url( admin_url(), PHP_URL_PATH );
|
||||
|
||||
// Load assets only on Hostinger admin pages.
|
||||
if ( $this->utils->isThisPage( $admin_path . 'admin.php?page=' . Menu::MENU_SLUG ) || $this->utils->isThisPage( $admin_path . 'admin.php?page=' . Menus::MENU_SLUG ) ) {
|
||||
add_action( 'admin_enqueue_scripts', array( $this, 'admin_styles' ) );
|
||||
add_action( 'admin_enqueue_scripts', array( $this, 'admin_scripts' ) );
|
||||
}
|
||||
if ( is_admin() ) {
|
||||
add_action( 'admin_enqueue_scripts', array( $this, 'global_styles' ) );
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueues styles for the Hostinger admin pages.
|
||||
*/
|
||||
public function admin_styles(): void {
|
||||
// Vue frontend styles.
|
||||
wp_enqueue_style(
|
||||
'hostinger_tools_styles',
|
||||
HOSTINGER_VUE_ASSETS_URL . '/main.css',
|
||||
array(),
|
||||
HOSTINGER_VERSION
|
||||
);
|
||||
|
||||
// Plugin rating styles.
|
||||
wp_enqueue_style(
|
||||
'hostinger_rating_styles',
|
||||
HOSTINGER_ASSETS_URL . '/css/plugin-rating.min.css',
|
||||
array(),
|
||||
HOSTINGER_VERSION
|
||||
);
|
||||
}
|
||||
|
||||
public function global_styles(): void {
|
||||
wp_enqueue_style(
|
||||
'hostinger_tools_global_styles',
|
||||
HOSTINGER_ASSETS_URL . 'css/hostinger-global.min.css',
|
||||
array(),
|
||||
HOSTINGER_VERSION
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Enqueues scripts for the Hostinger admin pages.
|
||||
*/
|
||||
public function admin_scripts(): void {
|
||||
global $wp_version;
|
||||
|
||||
wp_enqueue_script(
|
||||
'hostinger_tools_main_scripts',
|
||||
HOSTINGER_VUE_ASSETS_URL . '/main.js',
|
||||
array(
|
||||
'jquery',
|
||||
'wp-i18n',
|
||||
),
|
||||
HOSTINGER_VERSION,
|
||||
false
|
||||
);
|
||||
|
||||
wp_localize_script(
|
||||
'hostinger_tools_main_scripts',
|
||||
'hostinger_tools_data',
|
||||
array(
|
||||
'home_url' => home_url(),
|
||||
'site_url' => get_site_url(),
|
||||
'plugin_url' => $this->helper->get_hostinger_plugin_url(),
|
||||
'asset_url' => HOSTINGER_PLUGIN_URL,
|
||||
'hplatform' => ! empty( $_SERVER['H_PLATFORM'] ) ? 1 : 0,
|
||||
'edit_site_url' => $this->helper->get_edit_site_url(),
|
||||
'llmstxt_file_url' => $this->llms_txt_file_helper->get_llmstxt_file_url(),
|
||||
'llmstxt_file_user_generated' => $this->llms_txt_file_helper->is_user_generated_file(),
|
||||
'translations' => array(
|
||||
'routes_tools' => __( 'Tools', 'hostinger' ),
|
||||
'hostinger_tools_open_guide' => __( 'Open guide', 'hostinger' ),
|
||||
'hostinger_tools_preview_site' => __( 'Preview site', 'hostinger' ),
|
||||
'hostinger_tools_edit_site' => __( 'Edit site', 'hostinger' ),
|
||||
'hostinger_tools_disable_public_access' => __( 'Disable public access to the site (WordPress admins will still be able to access)', 'hostinger' ),
|
||||
'hostinger_tools_skip_link_maintenance_mode' => __( 'Skip-link that bypasses the maintenance mode', 'hostinger' ),
|
||||
'hostinger_tools_reset_link' => __( 'Reset link', 'hostinger' ),
|
||||
'hostinger_tools_disable_xml_rpc' => __( 'Disable XML-RPC', 'hostinger' ),
|
||||
'hostinger_tools_xml_rpc_description' => __( 'XML-RPC allows apps to connect to your WordPress site, but might expose your site\'s security. Disable this feature if you don\'t need it', 'hostinger' ),
|
||||
'hostinger_tools_disable_authentication_password' => __( 'Disable application passwords', 'hostinger' ),
|
||||
'hostinger_tools_authentication_password_description' => __( 'WordPress application passwords allow users to authenticate API requests without using their main login credentials, allowing for third-party integrations.', 'hostinger' ),
|
||||
|
||||
'hostinger_tools_force_https' => __( 'Force HTTPS', 'hostinger' ),
|
||||
'hostinger_tools_force_https_description' => __( 'Redirects all HTTP URLs to HTTPS sites', 'hostinger' ),
|
||||
'hostinger_tools_force_www' => __( 'Force WWW', 'hostinger' ),
|
||||
'hostinger_tools_force_www_description' => __( 'Redirects all WWW URLs to non-WWW ones', 'hostinger' ),
|
||||
'hostinger_tools_force_www_description_not_available' => __( 'WWW and non-WWW domain records are not pointing to the same host. Redirect not possible.', 'hostinger' ),
|
||||
'hostinger_tools_php_version' => __( 'PHP version', 'hostinger' ),
|
||||
'hostinger_tools_wordpress_version' => __( 'WordPress version', 'hostinger' ),
|
||||
'hostinger_tools_php_version_description' => __( 'Various updates and fixes available in the newest version.', 'hostinger' ),
|
||||
'hostinger_tools_running_latest_version' => __( 'Running the latest version', 'hostinger' ),
|
||||
'hostinger_tools_update' => __( 'Update', 'hostinger' ),
|
||||
'hostinger_tools_update_to' => __( 'Update to', 'hostinger' ),
|
||||
'hostinger_tools_update_to_recommended' => __( 'is recommended', 'hostinger' ),
|
||||
'hostinger_tools_update_to_wordpress_version_description' => __( 'For improved security, ensure you use the latest version of WordPress', 'hostinger' ),
|
||||
'hostinger_tools_maintenance' => __( 'Maintenance', 'hostinger' ),
|
||||
'hostinger_tools_preview_my_website' => __( 'Preview my website', 'hostinger' ),
|
||||
'hostinger_tools_security' => __( 'Security', 'hostinger' ),
|
||||
'hostinger_tools_redirects' => __( 'Redirects', 'hostinger' ),
|
||||
'hostinger_tools_ai' => __( 'AI Tools', 'hostinger' ),
|
||||
'hostinger_tools_llms' => __( 'LLM Optimization', 'hostinger' ),
|
||||
'hostinger_tools_enable_llms_txt' => __( 'Create LLMs.txt file', 'hostinger' ),
|
||||
'hostinger_tools_llms_txt_description' => __( 'Let AI explore, understand, and interact with your WordPress site.', 'hostinger' ),
|
||||
'hostinger_tools_optin_mcp' => __( 'Web2Agent', 'hostinger' ),
|
||||
'hostinger_tools_optin_mcp_description' => __( 'Make your website easier for AI tools to understand. Website content updates will be tracked to keep the AI discovery service up to date.', 'hostinger' ),
|
||||
'hostinger_tools_llms_txt_learn_more' => __( 'Learn more', 'hostinger' ),
|
||||
'hostinger_tools_llms_txt_check_validity' => __( 'Check validity', 'hostinger' ),
|
||||
'hostinger_tools_llms_txt_llmstxt' => __( 'LLMS.txt', 'hostinger' ),
|
||||
'hostinger_tools_llms_txt_external_file_found' => __( 'An external LLMs.txt file was found. Switching on the toggle will replace it with a new one.', 'hostinger' ),
|
||||
'hostinger_tools_llms_txt_modal_title' => __( 'Create new LLMs.txt file?', 'hostinger' ),
|
||||
'hostinger_tools_llms_txt_modal_description' => __( 'This will replace the existing LLMs.txt file with a new one by Hostinger Tools. The original file can’t be restored.', 'hostinger' ),
|
||||
'hostinger_tools_llms_txt_modal_cancel' => __( 'Cancel', 'hostinger' ),
|
||||
'hostinger_tools_llms_txt_modal_create_file' => __( 'Create file', 'hostinger' ),
|
||||
'hostinger_tools_maintenance_mode' => __( 'Maintenance mode', 'hostinger' ),
|
||||
'hostinger_tools_bypass_link' => __( 'Bypass link', 'hostinger' ),
|
||||
'xml_security_modal_description' => __( ' Turning on XML-RPC might make your site less secure. Do you want to proceed?', 'hostinger' ),
|
||||
'xml_security_modal_title' => __( 'Disclaimer', 'hostinger' ),
|
||||
'xml_security_modal_cancel' => __( 'Cancel', 'hostinger' ),
|
||||
'xml_security_modal_proceed_anyway' => __( 'Proceed anyway', 'hostinger' ),
|
||||
'bypass_link_reset_modal_title' => __( 'Bypass link reset', 'hostinger' ),
|
||||
'bypass_link_reset_modal_description' => __( 'This will invalidate the currently generated link in use. This action cannot be undone, are you sure you want to proceed?', 'hostinger' ),
|
||||
'bypass_link_reset_modal_cancel' => __( 'Cancel', 'hostinger' ),
|
||||
'bypass_link_reset_modal_reset_link' => __( 'Reset link', 'hostinger' ),
|
||||
'bypass_link_reset_success' => __( 'Link has been reset', 'hostinger' ),
|
||||
'hostinger_tools_settings_updated' => __( 'Your settings have been updated', 'hostinger' ),
|
||||
'hostinger_tools_settings_error' => __( 'It was an error updating your settings', 'hostinger' ),
|
||||
'hostinger_tools_mcp_choice' => __( 'Allow Kodee to manage your site', 'hostinger' ),
|
||||
'hostinger_tools_mcp_description' => __( 'Let Kodee manage your site on your behalf. This allows Kodee to perform actions like creating pages or updating settings. We will install and pre-configure the WordPress MCP plugin for you.', 'hostinger' ),
|
||||
'hostinger_tools_copied_successfully' => __( 'Copied successfully', 'hostinger' ),
|
||||
'hostinger_tools_text_copied_successfully' => __( 'Text has been copied successfully', 'hostinger' ),
|
||||
'hostinger_tools_free_domain_llm_unavailable' => __( 'LLM optimization features are not available for temporary subdomains. Connect a domain to unlock these features.', 'hostinger' ),
|
||||
'hostinger_tools_connect_domain_cta' => __( 'Connect domain', 'hostinger' ),
|
||||
),
|
||||
'rest_base_url' => esc_url_raw( rest_url() ),
|
||||
'nonce' => wp_create_nonce( 'wp_rest' ),
|
||||
'wp_version' => $wp_version,
|
||||
'php_version' => phpversion(),
|
||||
'recommended_php_version' => $this->helper->get_recommended_php_version(),
|
||||
'mcp_choice' => get_option( 'hostinger_mcp_choice', 0 ),
|
||||
'ai_plugin_compatibility' => $this->check_ai_mcp_compatibility(),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public function check_ai_mcp_compatibility(): bool {
|
||||
if ( ! function_exists( 'is_plugin_active' ) ) {
|
||||
require_once ABSPATH . 'wp-admin/includes/plugin.php';
|
||||
}
|
||||
|
||||
$plugin_path = 'hostinger-ai-assistant/hostinger-ai-assistant.php';
|
||||
$required_version = '3.0.0';
|
||||
|
||||
if ( is_plugin_active( $plugin_path ) ) {
|
||||
$plugin_file = WP_PLUGIN_DIR . '/' . $plugin_path;
|
||||
if ( file_exists( $plugin_file ) ) {
|
||||
$plugin_data = get_plugin_data( $plugin_file, false, false );
|
||||
$active_version = isset( $plugin_data['Version'] ) ? $plugin_data['Version'] : '';
|
||||
|
||||
if ( $active_version && version_compare( $active_version, $required_version, '>=' ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace Hostinger\Admin;
|
||||
|
||||
use Hostinger\Helper;
|
||||
use Hostinger\WpHelper\Utils;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
class Hooks {
|
||||
/**
|
||||
* @var Helper
|
||||
*/
|
||||
private Helper $helper;
|
||||
|
||||
/**
|
||||
* @var Utils
|
||||
*/
|
||||
private Utils $utils;
|
||||
|
||||
public function __construct( $utils ) {
|
||||
$this->helper = new Helper();
|
||||
$this->utils = $utils ?? new Utils();
|
||||
add_action( 'admin_footer', array( $this, 'rate_plugin' ) );
|
||||
add_filter( 'wp_kses_allowed_html', array( $this, 'custom_kses_allowed_html' ), 10, 1 );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function rate_plugin(): void {
|
||||
$admin_path = parse_url( admin_url(), PHP_URL_PATH );
|
||||
|
||||
if ( ! $this->utils->isThisPage( $admin_path . 'admin.php?page=' . Menu::MENU_SLUG ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
require_once HOSTINGER_ABSPATH . 'includes/Admin/Views/Partials/RateUs.php';
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function custom_kses_allowed_html( $allowed ) {
|
||||
$allowed['svg'] = array(
|
||||
'xmlns' => true,
|
||||
'width' => true,
|
||||
'height' => true,
|
||||
'viewBox' => true,
|
||||
'fill' => true,
|
||||
'style' => true,
|
||||
'class' => true,
|
||||
);
|
||||
$allowed['path'] = array(
|
||||
'd' => true,
|
||||
'fill' => true,
|
||||
);
|
||||
|
||||
return $allowed;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
namespace Hostinger\Admin\Jobs;
|
||||
|
||||
use Hostinger\LlmsTxtGenerator\LlmsTxtParser;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
abstract class AbstractBatchedJob extends AbstractJob {
|
||||
|
||||
public function init(): void {
|
||||
add_action( $this->get_create_batch_hook(), array( $this, 'handle_create_batch_action' ), 10, 2 );
|
||||
parent::init();
|
||||
}
|
||||
|
||||
protected function get_create_batch_hook(): string {
|
||||
return "{$this->get_hook_base_name()}create_batch";
|
||||
}
|
||||
|
||||
public function schedule( array $args = array() ): void {
|
||||
$this->schedule_create_batch_action( 1, $args );
|
||||
}
|
||||
|
||||
public function handle_create_batch_action( int $batch_number, array $args ): void {
|
||||
$items = $this->get_batch( $batch_number, $args );
|
||||
|
||||
if ( empty( $items ) ) {
|
||||
$this->handle_complete( $batch_number, $args );
|
||||
} else {
|
||||
$this->schedule_process_action( $items, $args );
|
||||
$this->schedule_create_batch_action( $batch_number + 1, $args );
|
||||
}
|
||||
}
|
||||
|
||||
protected function get_batch_size(): int {
|
||||
return apply_filters( 'hostinger_batch_item_limit', LlmsTxtParser::DEFAULT_LIMIT );
|
||||
}
|
||||
|
||||
protected function get_query_offset( int $batch_number ): int {
|
||||
return $this->get_batch_size() * ( $batch_number - 1 );
|
||||
}
|
||||
|
||||
protected function schedule_create_batch_action( int $batch_number, array $args ): void {
|
||||
if ( $this->can_schedule( array( $batch_number ) ) ) {
|
||||
$this->action_scheduler->schedule_immediate(
|
||||
$this->get_create_batch_hook(),
|
||||
array(
|
||||
$batch_number,
|
||||
$args,
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
protected function schedule_process_action( array $items = array(), array $args = array() ): void {
|
||||
$job_data = array(
|
||||
'items' => $items,
|
||||
'args' => $args,
|
||||
);
|
||||
if ( ! $this->is_processing( $job_data ) ) {
|
||||
$this->action_scheduler->schedule_immediate( $this->get_process_item_hook(), array( $job_data ) );
|
||||
}
|
||||
}
|
||||
|
||||
protected function is_processing( array $args = array() ): bool {
|
||||
return $this->action_scheduler->has_scheduled_action( $this->get_process_item_hook(), array( $args ) );
|
||||
}
|
||||
|
||||
protected function handle_complete( int $final_batch_number, array $args ): void {
|
||||
return;
|
||||
}
|
||||
|
||||
abstract protected function get_batch( int $batch_number, array $args ): array;
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
declare( strict_types=1 );
|
||||
|
||||
namespace Hostinger\Admin\Jobs;
|
||||
|
||||
use Exception;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
abstract class AbstractJob implements JobInterface {
|
||||
|
||||
protected ActionScheduler $action_scheduler;
|
||||
|
||||
public function __construct( ActionScheduler $action_scheduler ) {
|
||||
$this->action_scheduler = $action_scheduler;
|
||||
}
|
||||
|
||||
public function init(): void {
|
||||
add_action( $this->get_process_item_hook(), array( $this, 'handle_process_items_action' ) );
|
||||
add_action(
|
||||
$this->get_start_hook(),
|
||||
function ( $args ) {
|
||||
$this->schedule( $args );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public function can_schedule( $args = array() ): bool {
|
||||
return ! $this->is_running( $args );
|
||||
}
|
||||
|
||||
public function handle_process_items_action( array $args = array() ): void {
|
||||
$this->process_items( $args );
|
||||
}
|
||||
|
||||
public function get_process_item_hook(): string {
|
||||
return "{$this->get_hook_base_name()}process_item";
|
||||
}
|
||||
|
||||
public function get_start_hook(): string {
|
||||
return $this->get_name();
|
||||
}
|
||||
|
||||
protected function is_running( ?array $args = array() ): bool {
|
||||
return $this->action_scheduler->has_scheduled_action( $this->get_process_item_hook(), array( $args ) );
|
||||
}
|
||||
|
||||
protected function get_hook_base_name(): string {
|
||||
return "{$this->action_scheduler->get_group()}/jobs/{$this->get_name()}/";
|
||||
}
|
||||
|
||||
abstract public function get_name(): string;
|
||||
abstract protected function process_items( array $args );
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace Hostinger\Admin\Jobs;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
class ActionScheduler {
|
||||
|
||||
public const STATUS_PENDING = 'pending';
|
||||
public const STATUS_COMPLETE = 'complete';
|
||||
public const STATUS_FAILED = 'failed';
|
||||
|
||||
public function get_group(): string {
|
||||
return defined( 'HOSTINGER_PLUGIN_SETTINGS_OPTION' ) ? HOSTINGER_PLUGIN_SETTINGS_OPTION : 'hostinger_tools';
|
||||
}
|
||||
|
||||
public function schedule_single( int $timestamp, string $hook, $args = array() ): int {
|
||||
if ( ! function_exists( 'as_schedule_single_action' ) ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return as_schedule_single_action( $timestamp, $hook, $args, $this->get_group() );
|
||||
}
|
||||
|
||||
public function schedule_immediate( string $hook, $args = array() ): int {
|
||||
if ( ! function_exists( 'as_schedule_single_action' ) ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return as_schedule_single_action( gmdate( 'U' ) - 1, $hook, $args, $this->get_group() );
|
||||
}
|
||||
|
||||
public function has_scheduled_action( string $hook, $args = array() ): bool {
|
||||
if ( ! function_exists( 'as_next_scheduled_action' ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return as_next_scheduled_action( $hook, $args, $this->get_group() ) !== false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace Hostinger\Admin\Jobs;
|
||||
|
||||
use Hostinger\Admin\PluginSettings;
|
||||
use Hostinger\Admin\Proxy;
|
||||
use Hostinger\LlmsTxtGenerator\LlmsTxtFileHelper;
|
||||
use Hostinger\LlmsTxtGenerator\LlmsTxtParser;
|
||||
use Hostinger\Mcp\EventHandlerFactory;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
class JobInitializer {
|
||||
|
||||
public function __construct( Proxy $proxy ) {
|
||||
$jobs = array();
|
||||
$jobs[] = new NotifyMcpJob( new ActionScheduler(), new EventHandlerFactory( $proxy ) );
|
||||
$jobs[] = new LlmsTxtInjectContentJob( new ActionScheduler(), new LlmsTxtParser(), new LlmsTxtFileHelper(), new PluginSettings() );
|
||||
|
||||
foreach ( $jobs as $job ) {
|
||||
$job->init();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Hostinger\Admin\Jobs;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
interface JobInterface {
|
||||
public function get_name(): string;
|
||||
public function get_process_item_hook(): string;
|
||||
public function get_start_hook(): string;
|
||||
public function can_schedule( array $args = array() ): bool;
|
||||
public function schedule( array $args = array() );
|
||||
public function init();
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
namespace Hostinger\Admin\Jobs;
|
||||
|
||||
use Hostinger\Admin\PluginSettings;
|
||||
use Hostinger\LlmsTxtGenerator\LlmsTxtFileHelper;
|
||||
use Hostinger\LlmsTxtGenerator\LlmsTxtGenerator;
|
||||
use Hostinger\LlmsTxtGenerator\LlmsTxtParser;
|
||||
|
||||
class LlmsTxtInjectContentJob extends AbstractBatchedJob {
|
||||
|
||||
public const JOB_NAME = 'generate_llmstxt';
|
||||
|
||||
protected LlmsTxtParser $llms_txt_parser;
|
||||
protected LlmsTxtFileHelper $llms_txt_file_helper;
|
||||
protected PluginSettings $plugin_settings;
|
||||
|
||||
public function __construct( ActionScheduler $action_scheduler, LlmsTxtParser $llms_txt_parser, LlmsTxtFileHelper $llms_txt_file_helper, PluginSettings $plugin_settings ) {
|
||||
parent::__construct( $action_scheduler );
|
||||
$this->llms_txt_parser = $llms_txt_parser;
|
||||
$this->llms_txt_file_helper = $llms_txt_file_helper;
|
||||
$this->plugin_settings = $plugin_settings;
|
||||
}
|
||||
|
||||
protected function get_batch( int $batch_number, $args ): array {
|
||||
if ( ! isset( $args['post_type'] ) ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$offset = $this->get_query_offset( $batch_number );
|
||||
$limit = $this->get_batch_size();
|
||||
|
||||
return $this->llms_txt_parser->get_by_post_type( $args['post_type'], $limit, $offset );
|
||||
}
|
||||
|
||||
public function get_name(): string {
|
||||
return self::JOB_NAME;
|
||||
}
|
||||
|
||||
protected function process_items( array $args = array() ): void {
|
||||
if ( ! $this->is_llms_txt_enabled() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$items = $args['items'] ?? array();
|
||||
$job_args = $args['args'] ?? array();
|
||||
|
||||
if ( ! isset( $job_args['post_type'] ) || empty( $items ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$content = $this->llms_txt_parser->get_items( $items );
|
||||
$this->inject_content( $job_args['post_type'], $content );
|
||||
}
|
||||
|
||||
public function schedule( array $args = array() ): void {
|
||||
// Initiate as 2, as the first batch will be created when the user toggles on the option.
|
||||
$this->schedule_create_batch_action( 2, $args );
|
||||
}
|
||||
|
||||
public function can_schedule( $args = array() ): bool {
|
||||
return parent::can_schedule( $args ) && $this->is_llms_txt_enabled();
|
||||
}
|
||||
|
||||
public function is_llms_txt_enabled(): bool {
|
||||
$settings = $this->plugin_settings->get_plugin_settings();
|
||||
return $settings->get_enable_llms_txt();
|
||||
}
|
||||
|
||||
public function inject_content( $post_type, $new_content ): void {
|
||||
$content = $this->llms_txt_file_helper->get_content();
|
||||
$section = LlmsTxtGenerator::HOSTINGER_LLMSTXT_SUPPORTED_POST_TYPES[ $post_type ];
|
||||
$header = "## $section\n\n";
|
||||
$header_position = strpos( $content, $header );
|
||||
$header_length = strlen( $header );
|
||||
if ( $header_position === false ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$before_injection_slot = substr( $content, 0, $header_position + $header_length );
|
||||
$after_injection_slot = substr( $content, $header_position + $header_length );
|
||||
|
||||
$final_content = $before_injection_slot . $new_content . $after_injection_slot;
|
||||
$this->llms_txt_file_helper->create( $final_content );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace Hostinger\Admin\Jobs;
|
||||
use Hostinger\Mcp\EventHandlerFactory;
|
||||
use Hostinger\Mcp\Handlers\EventHandler;
|
||||
use PHPUnit\Exception;
|
||||
|
||||
class NotifyMcpJob extends AbstractJob implements JobInterface {
|
||||
|
||||
public const JOB_NAME = 'notify_mcp';
|
||||
|
||||
private EventHandlerFactory $event_handler_factory;
|
||||
|
||||
public function __construct( ActionScheduler $action_scheduler, EventHandlerFactory $event_handler_factory ) {
|
||||
$this->event_handler_factory = $event_handler_factory;
|
||||
parent::__construct( $action_scheduler );
|
||||
}
|
||||
|
||||
public function get_name(): string {
|
||||
return self::JOB_NAME;
|
||||
}
|
||||
|
||||
public function event_handler( string $event ): EventHandler {
|
||||
return $this->event_handler_factory->get_handler( $event );
|
||||
}
|
||||
|
||||
public function process_items( array $args = array() ): void {
|
||||
$handler = $this->event_handler( $args['event'] );
|
||||
$handler->send( $args );
|
||||
}
|
||||
|
||||
public function schedule( array $args = array() ): void {
|
||||
if ( $this->can_schedule( $args ) ) {
|
||||
$this->action_scheduler->schedule_immediate( $this->get_process_item_hook(), array( $args ) );
|
||||
}
|
||||
}
|
||||
|
||||
public function can_schedule( $args = array() ): bool {
|
||||
if ( ! parent::can_schedule( $args ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
$handler = $this->event_handler( $args['event'] );
|
||||
return $handler->can_send( $args );
|
||||
} catch ( Exception $e ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
namespace Hostinger\Admin;
|
||||
|
||||
use Hostinger\Admin\PluginSettings;
|
||||
use Hostinger\WpHelper\Utils;
|
||||
use Hostinger\WpMenuManager\Menus;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
class Menu {
|
||||
public const MENU_SLUG = 'hostinger-tools';
|
||||
|
||||
public function __construct() {
|
||||
add_filter( 'hostinger_admin_menu_bar_items', array( $this, 'add_admin_bar_items' ) );
|
||||
add_filter( 'hostinger_menu_subpages', array( $this, 'sub_menu' ) );
|
||||
}
|
||||
|
||||
public function add_admin_bar_items( $menu_items ): array {
|
||||
$menu_items[] = array(
|
||||
'id' => 'hostinger-tools-admin-bar',
|
||||
'title' => __( 'Tools', 'hostinger' ),
|
||||
'href' => admin_url( 'admin.php?page=' . self::MENU_SLUG ),
|
||||
);
|
||||
|
||||
return $menu_items;
|
||||
}
|
||||
|
||||
public function sub_menu( $submenus ): array {
|
||||
$tools_submenu = array(
|
||||
'page_title' => __( 'Tools', 'hostinger' ),
|
||||
'menu_title' => __( 'Tools', 'hostinger' ),
|
||||
'capability' => 'manage_options',
|
||||
'menu_slug' => self::MENU_SLUG,
|
||||
'callback' => array( $this, 'render_tools_menu_page' ),
|
||||
'menu_order' => 10,
|
||||
);
|
||||
|
||||
$submenus[] = $tools_submenu;
|
||||
|
||||
return $submenus;
|
||||
}
|
||||
|
||||
public function render_tools_menu_page(): void {
|
||||
echo wp_kses( Menus::renderMenuNavigation(), 'post' );
|
||||
?>
|
||||
<div id="hostinger-tools-vue-app"/>
|
||||
|
||||
|
||||
<?php
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
<?php
|
||||
namespace Hostinger\Admin\Options;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
die;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class for handling plugin options
|
||||
*/
|
||||
class PluginOptions {
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private bool $maintenance_mode = false;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private string $bypass_code = '';
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private bool $disable_xml_rpc = false;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private bool $force_https = false;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private bool $force_www = false;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private bool $disable_authentication_password = false;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private bool $enable_llms_txt = false;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private bool $optin_mcp = false;
|
||||
|
||||
/**
|
||||
* @param array $settings plugin settings array.
|
||||
*/
|
||||
public function __construct( array $settings = array() ) {
|
||||
$this->maintenance_mode = ! empty( $settings['maintenance_mode'] );
|
||||
$this->bypass_code = ! empty( $settings['bypass_code'] ) ? $settings['bypass_code'] : '';
|
||||
$this->disable_xml_rpc = ! empty( $settings['disable_xml_rpc'] );
|
||||
$this->force_https = ! empty( $settings['force_https'] );
|
||||
$this->force_www = ! empty( $settings['force_www'] );
|
||||
$this->disable_authentication_password = ! empty( $settings['disable_authentication_password'] );
|
||||
$this->enable_llms_txt = ! empty( $settings['enable_llms_txt'] );
|
||||
$this->optin_mcp = ! empty( $settings['optin_mcp'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function get_maintenance_mode(): bool {
|
||||
return $this->maintenance_mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $maintenance_mode
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function set_maintenance_mode( bool $maintenance_mode ): void {
|
||||
$this->maintenance_mode = $maintenance_mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function get_bypass_code(): string {
|
||||
return $this->bypass_code;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $bypass_code
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function set_bypass_code( string $bypass_code ): void {
|
||||
$this->bypass_code = $bypass_code;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function get_disable_xml_rpc(): bool {
|
||||
return $this->disable_xml_rpc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $disable_xml_rpc
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function set_disable_xml_rpc( bool $disable_xml_rpc ): void {
|
||||
$this->disable_xml_rpc = $disable_xml_rpc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function get_force_https(): bool {
|
||||
return $this->force_https;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $force_https
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function set_force_https( bool $force_https ): void {
|
||||
$this->force_https = $force_https;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function get_force_www(): bool {
|
||||
return $this->force_www;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $force_www
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function set_force_www( bool $force_www ): void {
|
||||
$this->force_www = $force_www;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function get_disable_authentication_password(): bool {
|
||||
return $this->disable_authentication_password;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $authentication_password
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function set_disable_authentication_password( bool $authentication_password ): void {
|
||||
$this->disable_authentication_password = $authentication_password;
|
||||
}
|
||||
|
||||
public function get_enable_llms_txt(): bool {
|
||||
return $this->enable_llms_txt;
|
||||
}
|
||||
|
||||
public function set_enable_llms_txt( bool $llmstxt_enabled ): void {
|
||||
$this->enable_llms_txt = $llmstxt_enabled;
|
||||
}
|
||||
|
||||
public function get_optin_mcp(): bool {
|
||||
return $this->optin_mcp;
|
||||
}
|
||||
|
||||
public function set_optin_mcp( bool $optin_mcp ): void {
|
||||
$this->optin_mcp = $optin_mcp;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function to_array(): array {
|
||||
return array(
|
||||
'maintenance_mode' => $this->get_maintenance_mode(),
|
||||
'bypass_code' => $this->get_bypass_code(),
|
||||
'disable_xml_rpc' => $this->get_disable_xml_rpc(),
|
||||
'force_https' => $this->get_force_https(),
|
||||
'force_www' => $this->get_force_www(),
|
||||
'disable_authentication_password' => $this->get_disable_authentication_password(),
|
||||
'enable_llms_txt' => $this->get_enable_llms_txt(),
|
||||
'optin_mcp' => $this->get_optin_mcp(),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
/**
|
||||
* Avoid possibility to get file accessed directly
|
||||
*/
|
||||
|
||||
namespace Hostinger\Admin;
|
||||
|
||||
use Hostinger\Admin\Options\PluginOptions;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
die;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class for handling Settings
|
||||
*/
|
||||
class PluginSettings {
|
||||
|
||||
/**
|
||||
* @var PluginOptions|null
|
||||
*/
|
||||
private ?PluginOptions $plugin_options = null;
|
||||
|
||||
/**
|
||||
* @param PluginOptions|null $plugin_options
|
||||
*/
|
||||
public function __construct( ?PluginOptions $plugin_options = null ) {
|
||||
if ( ! is_null( $plugin_options ) ) {
|
||||
$this->plugin_options = $plugin_options;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return plugin settings
|
||||
*
|
||||
* @return PluginOptions
|
||||
*/
|
||||
public function get_plugin_settings(): PluginOptions {
|
||||
|
||||
if ( ! empty( $this->plugin_options ) ) {
|
||||
$settings = $this->plugin_options;
|
||||
} else {
|
||||
$settings = get_option(
|
||||
HOSTINGER_PLUGIN_SETTINGS_OPTION,
|
||||
array()
|
||||
);
|
||||
|
||||
$settings = new PluginOptions( $settings );
|
||||
}
|
||||
|
||||
return $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param PluginOptions $plugin_options plugin settings.
|
||||
*
|
||||
* @return PluginOptions
|
||||
*/
|
||||
public function save_plugin_settings( PluginOptions $plugin_options ): PluginOptions {
|
||||
$existing_settings = $this->get_plugin_settings();
|
||||
|
||||
$update = update_option( HOSTINGER_PLUGIN_SETTINGS_OPTION, $plugin_options->to_array(), false );
|
||||
|
||||
return ! empty( $update ) ? $plugin_options : $existing_settings;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
namespace Hostinger\Admin;
|
||||
|
||||
use Hostinger\Mcp\EventHandlerFactory;
|
||||
use Hostinger\WpHelper\Requests\Client;
|
||||
use Hostinger\WpHelper\Utils;
|
||||
use WP_Error;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
class Proxy {
|
||||
|
||||
public const HOSTINGER_FREE_SUBDOMAIN_URL = 'hostingersite.com';
|
||||
public const HOSTINGER_DEV_FREE_SUBDOMAIN_URL = 'hostingersite.dev';
|
||||
|
||||
|
||||
private Client $client;
|
||||
private Utils $utils;
|
||||
private string $rest_base;
|
||||
|
||||
public function __construct( Client $client, Utils $utils ) {
|
||||
$this->client = $client;
|
||||
$this->utils = $utils;
|
||||
$this->rest_base = '/api/v1/events/trigger';
|
||||
}
|
||||
|
||||
public function trigger_event( string $event, array $params = array() ): array|WP_Error {
|
||||
if ( $this->is_free_subdomain() || ! $_SERVER['H_PLATFORM'] ) {
|
||||
return new WP_Error( 'domain-not_allowed', 'This domain is not eligible for triggering Hostinger events' );
|
||||
}
|
||||
|
||||
$args = array(
|
||||
'domain' => $this->remove_www( $this->utils->getHostInfo() ),
|
||||
'event' => array(
|
||||
'name' => $event,
|
||||
'params' => $params,
|
||||
),
|
||||
);
|
||||
|
||||
return $this->client->post( $this->rest_base, $args );
|
||||
}
|
||||
|
||||
private function is_free_subdomain(): bool {
|
||||
return str_contains( $this->utils->getHostInfo(), self::HOSTINGER_FREE_SUBDOMAIN_URL ) ||
|
||||
str_contains( $this->utils->getHostInfo(), self::HOSTINGER_DEV_FREE_SUBDOMAIN_URL );
|
||||
}
|
||||
|
||||
private function remove_www( string $url ): string {
|
||||
if ( str_starts_with( $url, 'www.' ) ) {
|
||||
return substr( $url, 4 );
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace Hostinger\Admin;
|
||||
|
||||
use Hostinger\Settings;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
class Redirects {
|
||||
private string $platform;
|
||||
public const PLATFORM_HPANEL = 'hpanel';
|
||||
|
||||
public function __construct() {
|
||||
|
||||
if ( ! Settings::get_setting( 'first_login_at' ) ) {
|
||||
Settings::update_setting( 'first_login_at', gmdate( 'Y-m-d H:i:s' ) );
|
||||
}
|
||||
/** PHPCS:disable WordPress.Security.NonceVerification.Recommended */
|
||||
if ( ! isset( $_GET['platform'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->platform = sanitize_text_field( $_GET['platform'] );
|
||||
$this->login_redirect();
|
||||
/** PHPCS:enable */
|
||||
}
|
||||
|
||||
public function login_redirect(): void {
|
||||
if ( $this->platform === self::PLATFORM_HPANEL ) {
|
||||
add_action(
|
||||
'init',
|
||||
static function () {
|
||||
$redirect_url = admin_url( 'admin.php?page=hostinger' );
|
||||
wp_safe_redirect( $redirect_url );
|
||||
exit;
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
<div class="hostinger hsr-plugin-rating">
|
||||
<p><?php echo esc_html__( 'Rate this plugin', 'hostinger' ); ?></p>
|
||||
<div class="hsr-rate-stars">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M12 17.27L18.18 21L16.54 13.97L22 9.24L14.81 8.63L12 2L9.19 8.63L2 9.24L7.46 13.97L5.82 21L12 17.27Z"
|
||||
fill="#673DE6"/>
|
||||
</svg>
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M12 17.27L18.18 21L16.54 13.97L22 9.24L14.81 8.63L12 2L9.19 8.63L2 9.24L7.46 13.97L5.82 21L12 17.27Z"
|
||||
fill="#673DE6"/>
|
||||
</svg>
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M12 17.27L18.18 21L16.54 13.97L22 9.24L14.81 8.63L12 2L9.19 8.63L2 9.24L7.46 13.97L5.82 21L12 17.27Z"
|
||||
fill="#673DE6"/>
|
||||
</svg>
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M12 17.27L18.18 21L16.54 13.97L22 9.24L14.81 8.63L12 2L9.19 8.63L2 9.24L7.46 13.97L5.82 21L12 17.27Z"
|
||||
fill="#673DE6"/>
|
||||
</svg>
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
d="M12 17.27L18.18 21L16.54 13.97L22 9.24L14.81 8.63L12 2L9.19 8.63L2 9.24L7.46 13.97L5.82 21L12 17.27Z"
|
||||
fill="#673DE6"/>
|
||||
</svg>
|
||||
</div>
|
||||
<p>
|
||||
<?php
|
||||
echo wp_kses(
|
||||
__(
|
||||
'on <a href="https://wordpress.org/support/plugin/hostinger/reviews/#new-post" target="_blank" rel="noopener noreferrer">WordPress.org</a>',
|
||||
'hostinger'
|
||||
),
|
||||
array(
|
||||
'a' => array(
|
||||
'href' => array(),
|
||||
'target' => array(),
|
||||
'rel' => array(),
|
||||
),
|
||||
),
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
Reference in New Issue
Block a user