This commit is contained in:
Javier Casares 2026-02-19 11:15:55 +00:00
commit f7702f2872
25 changed files with 6453 additions and 0 deletions

View file

@ -0,0 +1,247 @@
<?php
/**
* Main Plugin Class
*
* Orchestrates plugin initialization and component integration.
*
* @package ROBOTSTXT_OG
* @since 1.0.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
/**
* Class Robotstxt_OG_Image_Fallback
*
* Main plugin class using singleton pattern.
*
* @since 1.0.0
*/
class Robotstxt_OG_Image_Fallback {
/**
* Single instance of the class.
*
* @since 1.0.0
* @var Robotstxt_OG_Image_Fallback|null
*/
private static ?Robotstxt_OG_Image_Fallback $instance = null;
/**
* Image resolver instance.
*
* @since 1.0.0
* @var Robotstxt_OG_Image_Resolver
*/
private Robotstxt_OG_Image_Resolver $resolver;
/**
* OG tags generator instance.
*
* @since 1.0.0
* @var Robotstxt_OG_Tags
*/
private Robotstxt_OG_Tags $tags;
/**
* Admin settings instance.
*
* @since 1.0.0
* @var Robotstxt_OG_Admin_Settings|null
*/
private ?Robotstxt_OG_Admin_Settings $admin_settings = null;
/**
* REST API instance.
*
* @since 1.0.0
* @var Robotstxt_OG_REST_API
*/
private Robotstxt_OG_REST_API $rest_api;
/**
* Meta box instance.
*
* @since 1.2.0
* @var Robotstxt_OG_Meta_Box
*/
private Robotstxt_OG_Meta_Box $meta_box;
/**
* Get singleton instance.
*
* @since 1.0.0
*
* @return Robotstxt_OG_Image_Fallback
*/
public static function get_instance(): Robotstxt_OG_Image_Fallback {
if ( null === self::$instance ) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Constructor.
*
* Private to enforce singleton pattern.
*
* @since 1.0.0
*/
private function __construct() {
// Constructor is private.
}
/**
* Initialize the plugin.
*
* @since 1.0.0
*
* @return void
*/
public function init(): void {
// Load dependencies.
$this->load_dependencies();
// Initialize components.
$this->resolver = new Robotstxt_OG_Image_Resolver();
$this->tags = new Robotstxt_OG_Tags( $this->resolver );
// Initialize OG tags generator.
$this->tags->init();
// Initialize REST API.
$this->rest_api = new Robotstxt_OG_REST_API( $this->resolver );
$this->rest_api->init();
// Initialize meta box (registers post meta for REST + editor UI).
$this->meta_box = new Robotstxt_OG_Meta_Box();
$this->meta_box->init();
// Initialize admin settings if in admin context.
if ( is_admin() ) {
$this->admin_settings = new Robotstxt_OG_Admin_Settings( $this->resolver );
$this->admin_settings->init();
}
// Register WP-CLI commands.
if ( defined( 'WP_CLI' ) && WP_CLI ) {
WP_CLI::add_command( 'og-fallback', new Robotstxt_OG_CLI( $this->resolver ) );
}
// Auto-regenerate cache when featured image changes.
add_action( 'updated_post_meta', array( $this, 'handle_thumbnail_change' ), 10, 4 );
add_action( 'deleted_post_meta', array( $this, 'handle_thumbnail_change' ), 10, 4 );
// Register activation and deactivation hooks.
register_activation_hook( ROBOTSTXT_OG_PATH . 'robotstxt-og.php', array( $this, 'activate' ) );
register_deactivation_hook( ROBOTSTXT_OG_PATH . 'robotstxt-og.php', array( $this, 'deactivate' ) );
}
/**
* Load plugin dependencies.
*
* @since 1.0.0
*
* @return void
*/
private function load_dependencies(): void {
require_once ROBOTSTXT_OG_PATH . 'includes/class-robotstxt-og-image-resolver.php';
require_once ROBOTSTXT_OG_PATH . 'includes/class-robotstxt-og-tags.php';
require_once ROBOTSTXT_OG_PATH . 'includes/class-robotstxt-og-rest-api.php';
require_once ROBOTSTXT_OG_PATH . 'includes/class-robotstxt-og-meta-box.php';
// Load admin class if in admin context.
if ( is_admin() ) {
require_once ROBOTSTXT_OG_PATH . 'admin/class-robotstxt-og-admin-settings.php';
}
// Load WP-CLI class if running in CLI context.
if ( defined( 'WP_CLI' ) && WP_CLI ) {
require_once ROBOTSTXT_OG_PATH . 'includes/class-robotstxt-og-cli.php';
}
}
/**
* Activation hook callback.
*
* Runs when the plugin is activated.
*
* @since 1.0.0
*
* @return void
*/
public function activate(): void {
// Set default options if they don't exist.
if ( false === get_option( 'robotstxt_og_fallback_image' ) ) {
add_option( 'robotstxt_og_fallback_image', '' );
}
if ( false === get_option( 'robotstxt_og_delete_data_on_uninstall' ) ) {
add_option( 'robotstxt_og_delete_data_on_uninstall', false );
}
// Flush rewrite rules (if needed in future).
flush_rewrite_rules();
}
/**
* Deactivation hook callback.
*
* Runs when the plugin is deactivated.
*
* @since 1.0.0
*
* @return void
*/
public function deactivate(): void {
// Flush rewrite rules (if needed in future).
flush_rewrite_rules();
}
/**
* Clear fallback cache when a post's featured image is changed or removed.
*
* Hooked to `updated_post_meta` and `deleted_post_meta` for `_thumbnail_id`.
*
* @since 1.0.0
*
* @param int $meta_id ID of the meta data entry.
* @param int $post_id Post ID.
* @param string $meta_key Meta key being updated.
* @param mixed $meta_value New meta value (unused).
* @return void
*/
public function handle_thumbnail_change( int $meta_id, int $post_id, string $meta_key, $meta_value = null ): void { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed
if ( '_thumbnail_id' !== $meta_key ) {
return;
}
$this->resolver->clear_cache( $post_id );
}
/**
* Get image resolver instance.
*
* @since 1.0.0
*
* @return Robotstxt_OG_Image_Resolver
*/
public function get_resolver(): Robotstxt_OG_Image_Resolver {
return $this->resolver;
}
/**
* Get OG tags generator instance.
*
* @since 1.0.0
*
* @return Robotstxt_OG_Tags
*/
public function get_tags(): Robotstxt_OG_Tags {
return $this->tags;
}
}