<?php declare( strict_types=1 ); namespace Automattic\WooCommerce\GoogleListingsAndAds\Admin; use Automattic\WooCommerce\GoogleListingsAndAds\Admin\MetaBox\MetaBoxInterface; use Automattic\WooCommerce\GoogleListingsAndAds\Ads\AdsService; use Automattic\WooCommerce\GoogleListingsAndAds\Assets\AdminScriptAsset; use Automattic\WooCommerce\GoogleListingsAndAds\Assets\AdminScriptWithBuiltDependenciesAsset; use Automattic\WooCommerce\GoogleListingsAndAds\Assets\AdminStyleAsset; use Automattic\WooCommerce\GoogleListingsAndAds\Assets\Asset; use Automattic\WooCommerce\GoogleListingsAndAds\Assets\AssetsHandlerInterface; use Automattic\WooCommerce\GoogleListingsAndAds\Infrastructure\AdminConditional; use Automattic\WooCommerce\GoogleListingsAndAds\Infrastructure\Conditional; use Automattic\WooCommerce\GoogleListingsAndAds\Infrastructure\Registerable; use Automattic\WooCommerce\GoogleListingsAndAds\Infrastructure\Service; use Automattic\WooCommerce\GoogleListingsAndAds\Infrastructure\ViewFactory; use Automattic\WooCommerce\GoogleListingsAndAds\MerchantCenter\MerchantCenterService; use Automattic\WooCommerce\GoogleListingsAndAds\PluginHelper; use Automattic\WooCommerce\GoogleListingsAndAds\Value\BuiltScriptDependencyArray; use Automattic\WooCommerce\GoogleListingsAndAds\View\ViewException; use Automattic\WooCommerce\GoogleListingsAndAds\Options\OptionsAwareInterface; use Automattic\WooCommerce\GoogleListingsAndAds\Options\OptionsAwareTrait; use Automattic\WooCommerce\GoogleListingsAndAds\Options\OptionsInterface; /** * Class Admin * * @package Automattic\WooCommerce\GoogleListingsAndAds\Pages */ class Admin implements Service, Registerable, Conditional, OptionsAwareInterface { use AdminConditional; use PluginHelper; use OptionsAwareTrait; /** * @var AssetsHandlerInterface */ protected $assets_handler; /** * @var ViewFactory */ protected $view_factory; /** * @var MerchantCenterService */ protected $merchant_center; /** * @var AdsService */ protected $ads; /** * Admin constructor. * * @param AssetsHandlerInterface $assets_handler * @param ViewFactory $view_factory * @param MerchantCenterService $merchant_center * @param AdsService $ads */ public function __construct( AssetsHandlerInterface $assets_handler, ViewFactory $view_factory, MerchantCenterService $merchant_center, AdsService $ads ) { $this->assets_handler = $assets_handler; $this->view_factory = $view_factory; $this->merchant_center = $merchant_center; $this->ads = $ads; } /** * Register a service. */ public function register(): void { $this->assets_handler->add_many( $this->get_assets() ); add_action( 'admin_enqueue_scripts', function() { $this->assets_handler->enqueue_many( $this->get_assets() ); } ); add_action( "plugin_action_links_{$this->get_plugin_basename()}", function( $links ) { return $this->add_plugin_links( $links ); } ); add_action( 'wp_default_scripts', function( $scripts ) { $this->inject_fast_refresh_for_dev( $scripts ); }, 20 ); } /** * Return an array of assets. * * @return Asset[] */ protected function get_assets(): array { $wc_admin_condition = function() { return wc_admin_is_registered_page(); }; $assets[] = ( new AdminScriptWithBuiltDependenciesAsset( 'google-listings-and-ads', 'js/build/index', "{$this->get_root_dir()}/js/build/index.asset.php", new BuiltScriptDependencyArray( [ 'dependencies' => [], 'version' => (string) filemtime( "{$this->get_root_dir()}/js/build/index.js" ), ] ), $wc_admin_condition ) )->add_inline_script( 'glaData', [ 'mcSetupComplete' => $this->merchant_center->is_setup_complete(), 'mcSupportedCountry' => $this->merchant_center->is_store_country_supported(), 'mcSupportedLanguage' => $this->merchant_center->is_language_supported(), 'adsCampaignConvertStatus' => $this->options->get( OptionsInterface::CAMPAIGN_CONVERT_STATUS ), 'adsSetupComplete' => $this->ads->is_setup_complete(), 'enableReports' => $this->enableReports(), 'dateFormat' => get_option( 'date_format' ), 'timeFormat' => get_option( 'time_format' ), 'siteLogoUrl' => wp_get_attachment_image_url( get_theme_mod( 'custom_logo' ), 'full' ), ] ); $assets[] = ( new AdminStyleAsset( 'google-listings-and-ads-css', '/js/build/index', defined( 'WC_ADMIN_PLUGIN_FILE' ) ? [ 'wc-admin-app' ] : [], (string) filemtime( "{$this->get_root_dir()}/js/build/index.css" ), $wc_admin_condition ) ); $product_condition = function () { $screen = get_current_screen(); return ( null !== $screen && 'product' === $screen->id ); }; $assets[] = ( new AdminScriptAsset( 'gla-custom-inputs', 'js/build/custom-inputs', [], '', $product_condition ) ); $assets[] = ( new AdminStyleAsset( 'gla-product-attributes-css', 'js/build/product-attributes', [], '', $product_condition ) ); return $assets; } /** * Adds links to the plugin's row in the "Plugins" wp-admin page. * * @see https://codex.wordpress.org/Plugin_API/Filter_Reference/plugin_action_links_(plugin_file_name) * @param array $links The existing list of links that will be rendered. */ protected function add_plugin_links( $links ): array { $plugin_links = []; // Display settings url if setup is complete otherwise link to get started page if ( $this->merchant_center->is_setup_complete() ) { $plugin_links[] = sprintf( '<a href="%1$s">%2$s</a>', esc_attr( $this->get_settings_url() ), esc_html__( 'Settings', 'google-listings-and-ads' ) ); } else { $plugin_links[] = sprintf( '<a href="%1$s">%2$s</a>', esc_attr( $this->get_start_url() ), esc_html__( 'Get Started', 'google-listings-and-ads' ) ); } $plugin_links[] = sprintf( '<a href="%1$s">%2$s</a>', esc_attr( $this->get_documentation_url() ), esc_html__( 'Documentation', 'google-listings-and-ads' ) ); // Add new links to the beginning return array_merge( $plugin_links, $links ); } /** * Adds a meta box. * * @param MetaBoxInterface $meta_box */ public function add_meta_box( MetaBoxInterface $meta_box ) { add_filter( "postbox_classes_{$meta_box->get_screen()}_{$meta_box->get_id()}", function ( array $classes ) use ( $meta_box ) { return array_merge( $classes, $meta_box->get_classes() ); } ); add_meta_box( $meta_box->get_id(), $meta_box->get_title(), $meta_box->get_callback(), $meta_box->get_screen(), $meta_box->get_context(), $meta_box->get_priority(), $meta_box->get_callback_args() ); } /** * @param string $view Name of the view * @param array $context_variables Array of variables to pass to the view * * @return string The rendered view * * @throws ViewException If the view doesn't exist or can't be loaded. */ public function get_view( string $view, array $context_variables = [] ): string { return $this->view_factory->create( $view ) ->render( $context_variables ); } /** * Only show reports if we enable it through a snippet. * * @return bool Whether reports should be enabled . */ protected function enableReports(): bool { return apply_filters( 'woocommerce_gla_enable_reports', true ); } /** * This method is ONLY used during development. * * The runtime.js file is created when the front-end is developed in Fast Refresh mode * and must be loaded together to enable the mode. * * When Gutenberg is not installed or not activated, the react dependency will not have * the 'wp-react-refresh-entry' handle, so here injects the Fast Refresh scripts we built. * * The Fast Refresh also needs the development version of React and ReactDOM. * They will be replaced if the SCRIPT_DEBUG flag is not enabled. * * @param WP_Scripts $scripts WP_Scripts instance. */ private function inject_fast_refresh_for_dev( $scripts ) { $runtime_path = "{$this->get_root_dir()}/js/build/runtime.js"; if ( ! file_exists( $runtime_path ) ) { return; } $react_script = $scripts->query( 'react', 'registered' ); if ( ! $react_script ) { return; } if ( ! ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ) { $react_dom_script = $scripts->query( 'react-dom', 'registered' ); $react_dom_script->src = str_replace( '.min', '', $react_dom_script->src ); $react_script->src = str_replace( '.min', '', $react_script->src ); } $plugin_url = $this->get_plugin_url(); $scripts->add( 'gla-webpack-rumtime', "{$plugin_url}/js/build/runtime.js", [], (string) filemtime( $runtime_path ) ); $react_script->deps[] = 'gla-webpack-rumtime'; if ( ! in_array( 'wp-react-refresh-entry', $react_script->deps, true ) ) { $scripts->add( 'wp-react-refresh-runtime', "{$plugin_url}/js/build-dev/react-refresh-runtime.js", [] ); $scripts->add( 'wp-react-refresh-entry', "{$plugin_url}/js/build-dev/react-refresh-entry.js", [ 'wp-react-refresh-runtime' ] ); $react_script->deps[] = 'wp-react-refresh-entry'; } } }