Plugin language). * Names are shown in their own language, so they are not translated. */ public const array LANGUAGES = array( 'en_US' => 'English', 'es_ES' => 'Español', 'de_DE' => 'Deutsch', 'fr_FR' => 'Français', 'pt_BR' => 'Português (Brasil)', 'ru_RU' => 'Русский', 'tr_TR' => 'Türkçe', 'hy' => 'Հայերեն', 'ja' => '日本語', 'zh_CN' => '简体中文', ); /** * @var Plugin|null */ private static $instance = null; /** * @var Settings */ public $settings; /** * @var Admin */ public $admin; /** * @var REST */ public $rest; /** * Singleton. * * @return Plugin */ public static function instance() { if ( null === self::$instance ) { self::$instance = new self(); self::$instance->init(); } return self::$instance; } /** * Init hooks. */ public function init() { $this->settings = new Settings(); $this->admin = new Admin( $this->settings ); $this->rest = new REST( $this->settings ); add_action( 'init', array( $this, 'maybe_upgrade' ), 1 ); add_action( 'admin_init', array( $this, 'verify_author_contacts' ) ); add_action( 'admin_notices', array( $this, 'author_tamper_notice' ) ); Jobs::register(); Rules::register(); add_action( 'template_redirect', array( $this, 'maybe_redirect_old_slug' ), 1 ); add_action( 'init', array( $this, 'load_textdomain' ) ); add_filter( 'plugin_locale', array( $this, 'plugin_language' ), 10, 2 ); add_filter( 'load_textdomain_mofile', array( $this, 'plugin_language_mofile' ), 10, 2 ); add_filter( 'load_script_translation_file', array( $this, 'plugin_language_json' ), 10, 3 ); add_action( 'before_woocommerce_init', array( $this, 'declare_woo_compatibility' ) ); } /** * Declare compatibility with modern WooCommerce features (HPOS, blocks). * Without this, WooCommerce shows compatibility warnings since 8.0. */ public function declare_woo_compatibility() { if ( ! class_exists( '\Automattic\WooCommerce\Utilities\FeaturesUtil', false ) ) { return; } \Automattic\WooCommerce\Utilities\FeaturesUtil::declare_compatibility( 'custom_order_tables', RAFGRID_FILE, true ); \Automattic\WooCommerce\Utilities\FeaturesUtil::declare_compatibility( 'cart_checkout_blocks', RAFGRID_FILE, true ); } /** * Verify that the official author contacts were not silently replaced. * * @return bool */ public function verify_author_contacts(): bool { return hash_equals( self::AUTHOR_SIGNATURE, Author::signature() ); } /** * Admin notice when the author contacts do not match the signature. */ public function author_tamper_notice() { if ( ! current_user_can( 'manage_options' ) || $this->verify_author_contacts() ) { return; } if ( ! self::is_plugin_screen() ) { return; } echo '

'; echo esc_html__( 'Rafgrid: the official author support contacts in this copy were modified. Official support: ', 'rafgrid' ); echo esc_html( Author::line() ); echo '

'; } /** * Versioned upgrade routine: runs on version change without reactivation, * so DB tables and defaults appear after a normal plugin update too. */ public function maybe_upgrade() { if ( get_option( 'rafgrid_version' ) === RAFGRID_VERSION ) { return; } Migrate::run(); Settings::ensure_defaults(); History::create_table(); Audit::create_table(); Jobs::ensure_scheduled(); update_option( 'rafgrid_version', RAFGRID_VERSION ); } /** * Plugin language override (Settings -> Plugin language). Does not change the whole admin. * * @param string $locale Locale. * @param string $domain Text domain. * @return string */ public function plugin_language( $locale, $domain ) { if ( 'rafgrid' !== $domain ) { return $locale; } $lang = $this->language_override(); return '' !== $lang ? $lang : $locale; } /** * Locale chosen in Settings -> Plugin language, or '' to follow the site. * * @return string */ private function language_override(): string { $lang = (string) $this->settings->get( 'language', 'auto' ); return array_key_exists( $lang, self::LANGUAGES ) ? $lang : ''; } /** * Plugin language for PHP strings: point just-in-time loading of this text * domain at the chosen locale (en_US has no file, so strings stay English). * * @param string $mofile Translation file. * @param string $domain Text domain. * @return string */ public function plugin_language_mofile( $mofile, $domain ) { $lang = 'rafgrid' === $domain ? $this->language_override() : ''; return '' !== $lang ? RAFGRID_DIR . 'languages/rafgrid-' . $lang . '.mo' : $mofile; } /** * Plugin language for the React app's JSON translations. * * @param string|false $file Translation file. * @param string $handle Script handle. * @param string $domain Text domain. * @return string|false */ public function plugin_language_json( $file, $handle, $domain ) { $lang = 'rafgrid' === $domain ? $this->language_override() : ''; if ( '' === $lang || 'rafgrid-app' !== $handle ) { return $file; } return RAFGRID_DIR . 'languages/rafgrid-' . $lang . '-' . md5( 'build/index.js' ) . '.json'; } /** * 301 redirect from a renamed slug (map written when Slug is edited in the sheet). */ public function maybe_redirect_old_slug() { if ( ! is_404() ) { return; } $map = get_option( 'rafgrid_redirects', array() ); if ( ! is_array( $map ) || empty( $map ) ) { return; } $path = trim( (string) wp_parse_url( esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ?? '' ) ), PHP_URL_PATH ), '/' ); if ( isset( $map[ $path ] ) ) { wp_safe_redirect( home_url( '/' . $map[ $path ] . '/' ), 301 ); exit; } } /** * Register the bundled /languages folder for just-in-time loading; language * packs from translate.wordpress.org take precedence. The filters above * apply the "Plugin language" setting to this text domain only. */ public function load_textdomain() { load_plugin_textdomain( 'rafgrid', false, dirname( plugin_basename( RAFGRID_FILE ) ) . '/languages' ); // phpcs:ignore PluginCheck.CodeAnalysis.DiscouragedFunctions.load_plugin_textdomainFound -- Needed for the per-plugin language setting and the bundled hy/ru_RU files. } /** * Activation: defaults + history table. */ public static function activate() { Migrate::run(); Settings::ensure_defaults(); History::create_table(); Audit::create_table(); Jobs::ensure_scheduled(); } /** * Is the current admin screen one of this plugin's pages (sheet, docs, settings)? * * @return bool */ public static function is_plugin_screen(): bool { $screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null; return $screen && str_contains( (string) $screen->id, 'rafgrid' ); } /** * Is WooCommerce active? * * @return bool */ public static function has_woo() { return class_exists( 'WooCommerce', false ) || function_exists( 'wc_get_product' ) || post_type_exists( 'product' ); } }