Initial commit: Atomaste website

This commit is contained in:
2025-12-10 12:17:30 -05:00
commit 0b9e5d1605
19260 changed files with 5206382 additions and 0 deletions

View File

@@ -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;
}

View File

@@ -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 );
}

View File

@@ -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;
}
}

View File

@@ -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();
}
}
}

View File

@@ -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();
}

View File

@@ -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 );
}
}

View File

@@ -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;
}
}
}