PluginProbe
Hostinger Tools / 3.0.39
Hostinger Tools v3.0.39
3.0.77 3.0.76 3.0.75 3.0.74 3.0.73 3.0.72 3.0.71 3.0.70 3.0.69 3.0.68 3.0.67 3.0.66 1.8.1 1.8.2 1.8.3 1.9.1 1.9.4 1.9.5 1.9.6 1.9.7 1.9.8 1.9.9 2.0.0 2.0.1 2.0.4 All 108 releases
hostinger / includes / LlmsTxtGenerator / LlmsTxtGenerator.php

LlmsTxtGenerator.php in Hostinger Tools 3.0.39, at includes/LlmsTxtGenerator/LlmsTxtGenerator.php

185 lines 5.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Hostinger\LlmsTxtGenerator;
4
5 use Hostinger\Admin\PluginSettings;
6
7 defined( 'ABSPATH' ) || exit;
8
9 class LlmsTxtGenerator {
10
11 public const HOSTINGER_LLMSTXT_SIGNATURE = '[comment]: # (Generated by Hostinger Tools Plugin)';
12 protected const UTF8_BOM = "\xEF\xBB\xBF";
13 protected const HOSTINGER_LLMSTXT_SUPPORTED_POST_TYPES = array(
14 'post',
15 'page',
16 'product',
17 );
18
19 /**
20 * Activation and deactivation hooks appears too early,
21 * so the plugin status is not available yet.
22 *
23 * That's why we use a flag this->woocommerce_status to know the plugin status.
24 *
25 * @var string|null
26 */
27 protected ?string $woocommerce_status = null;
28 protected PluginSettings $plugin_settings;
29 protected LlmsTxtFileHelper $file_helper;
30
31 public function __construct( PluginSettings $plugin_settings, LlmsTxtFileHelper $llmstxt_file_helper ) {
32 $this->plugin_settings = $plugin_settings;
33 $this->file_helper = $llmstxt_file_helper;
34 add_action( 'init', array( $this, 'init' ) );
35 }
36
37 public function on_woocommerce_activation(): void {
38 $this->woocommerce_status = 'active';
39 $this->generate();
40 }
41
42 public function on_woocommerce_deactivation(): void {
43 $this->woocommerce_status = 'inactive';
44 $this->generate();
45 }
46
47 public function init(): void {
48 if ( wp_doing_ajax() || wp_doing_cron() || ! current_user_can( 'manage_options' ) ) {
49 return;
50 }
51
52 $settings = $this->plugin_settings->get_plugin_settings();
53
54 if ( $settings->get_enable_llms_txt() && ! $this->file_helper->llmstxt_file_exists() ) {
55 $this->generate();
56 }
57
58 $this->init_hooks();
59 }
60
61 public function on_settings_update( bool $is_enabled ): void {
62 if ( $is_enabled ) {
63 $this->generate();
64 } else {
65 $this->delete();
66 }
67 }
68
69 public function on_post_status_change( string $new_status, string $old_status, \WP_Post $post ): void {
70 if ( ! $this->is_post_type_supported( $post->post_type ) ) {
71 return;
72 }
73
74 if ( $new_status === 'publish' || $old_status === 'publish' ) {
75 $this->generate();
76 }
77 }
78
79 public function on_blog_change( mixed $old_value, mixed $new_value ): void {
80 if ( $old_value !== $new_value ) {
81 $this->generate();
82 }
83 }
84
85 public function get_content(): string {
86 $content = self::UTF8_BOM;
87 $content .= $this->inject_title();
88 $content .= $this->inject_site_description();
89 $content .= $this->inject_items( $this->get_by_post_type( 'post' ), 'Posts' );
90 $content .= $this->inject_items( $this->get_by_post_type( 'page' ), 'Pages' );
91 $content .= $this->maybe_inject_woocommerce_products();
92 $content .= $this->inject_signature();
93
94 return $content;
95 }
96
97 public function init_hooks(): void {
98 add_action( 'transition_post_status', array( $this, 'on_post_status_change' ), 10, 3 );
99 add_action( 'hostinger_tools_setting_enable_llms_txt_update', array( $this, 'on_settings_update' ) );
100 add_action( 'update_option_blogname', array( $this, 'on_blog_change' ), 10, 2 );
101 add_action( 'update_option_blogdescription', array( $this, 'on_blog_change' ), 10, 2 );
102 add_action( 'activate_woocommerce/woocommerce.php', array( $this, 'on_woocommerce_activation' ) );
103 add_action( 'deactivate_woocommerce/woocommerce.php', array( $this, 'on_woocommerce_deactivation' ) );
104 }
105
106 protected function generate(): void {
107 $this->file_helper->create( $this->get_content() );
108 }
109
110 protected function delete(): void {
111 $this->file_helper->delete();
112 }
113
114 protected function is_post_type_supported( string $post_type ): bool {
115 return in_array( $post_type, self::HOSTINGER_LLMSTXT_SUPPORTED_POST_TYPES, true );
116 }
117
118 protected function get_by_post_type( string $post_type, int $limit = 100 ): array {
119 $args = array(
120 'post_type' => $post_type,
121 'post_status' => 'publish',
122 'fields' => 'ids',
123 'posts_per_page' => apply_filters( 'hostinger_llmstext_item_limit', $limit, $post_type ),
124 );
125
126 return get_posts( $args );
127 }
128
129 protected function is_woocommerce_active(): bool {
130 return ( is_null( $this->woocommerce_status ) && ( is_plugin_active( 'woocommerce/woocommerce.php' ) || $this->woocommerce_status === 'active' ) );
131 }
132
133 protected function inject_site_description(): string {
134 $description = get_bloginfo( 'description' );
135
136 return $description ? "> $description\n\n" : '';
137 }
138
139 protected function inject_title(): string {
140 $title = get_bloginfo( 'name' ) ? get_bloginfo( 'name' ) : site_url();
141
142 return "# $title\n\n";
143 }
144
145 protected function inject_signature(): string {
146 return "\n\n" . self::HOSTINGER_LLMSTXT_SIGNATURE;
147 }
148
149 protected function maybe_inject_woocommerce_products(): string {
150 if ( ! $this->is_woocommerce_active() ) {
151 return '';
152 }
153
154 return $this->inject_items( $this->get_by_post_type( 'product' ), 'Products' );
155 }
156
157 protected function inject_items( array $items, string $title ): string {
158 if ( empty( $items ) ) {
159 return '';
160 }
161
162 $content = "\n## $title\n\n";
163
164 foreach ( $items as $item ) {
165 $post = get_post( $item );
166 $title = $post->post_title;
167 $permalink = get_permalink( $post );
168 $excerpt = $this->prepare_excerpt( $post );
169
170 $content .= "- [$title]($permalink)";
171 if ( $excerpt ) {
172 $content .= ": $excerpt";
173 }
174
175 $content .= "\n";
176 }
177
178 return $content;
179 }
180
181 protected function prepare_excerpt( \WP_Post $item ): string {
182 return html_entity_decode( wp_trim_excerpt( $item->post_excerpt, $item ) );
183 }
184 }
185