]*)>#'; /** * Theme Builder language resolution service. * * @var EssentialAddonsTemplates */ private $templates; /** * Post translation relationships. * * @var PostTranslationManager */ private $post_translations; /** * Shared list column renderer. * * @var TranslationListTable */ private $list_table; /** * The dashboard's prepared list table, once the columns are on it. * * @var WP_List_Table|null */ private $table = null; /** * Whether this screen's output is being captured. * * @var bool */ private $capturing = false; /** * Constructor. * * @param EssentialAddonsTemplates $templates Theme Builder language resolution. * @param PostTranslationManager $post_translations Post translation manager. * @param LanguageManager $language_manager Language manager. */ public function __construct( EssentialAddonsTemplates $templates, PostTranslationManager $post_translations, LanguageManager $language_manager ) { $this->templates = $templates; $this->post_translations = $post_translations; $this->list_table = new TranslationListTable( $post_translations, $language_manager, new TranslationActions() ); } /** * {@inheritdoc} */ public function register() { if ( ! $this->templates->is_available() ) { return; } add_action( 'current_screen', array( $this, 'prepare_screen' ) ); } /** * Hooks the dashboard's own load and render. * * @param WP_Screen $screen Current administration screen. * @return void */ public function prepare_screen( $screen ) { if ( ! $screen instanceof WP_Screen || ! $this->is_theme_builder_screen() ) { return; } if ( ! $this->post_translations->supports_post_type( EssentialAddonsTemplates::POST_TYPE ) ) { return; } $page_hook = isset( $GLOBALS['page_hook'] ) && is_string( $GLOBALS['page_hook'] ) ? $GLOBALS['page_hook'] : ''; if ( '' === $page_hook ) { return; } add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_assets' ) ); // After the dashboard's own load handler, which is what builds the table. add_action( 'load-' . $page_hook, array( $this, 'extend_table' ), 11 ); // The dashboard prints itself from this hook at the default priority, so // the capture opens ahead of everything on it and closes behind. add_action( $page_hook, array( $this, 'start_capture' ), 0 ); add_action( $page_hook, array( $this, 'print_captured' ), 20 ); } /** * Adds the two columns to the table the dashboard prepared. * * @return void */ public function extend_table() { $table = $this->find_list_table(); if ( null === $table ) { return; } $headers = $this->read_column_headers( $table ); if ( null === $headers || ! isset( $headers[0] ) || ! is_array( $headers[0] ) ) { return; } $headers[0] = $this->list_table->add_columns( $headers[0] ); if ( $this->write_column_headers( $table, $headers ) ) { $this->table = $table; } } /** * Begins capturing the dashboard's output. * * @return void */ public function start_capture() { $this->capturing = ob_start(); } /** * Prints the dashboard with the two columns filled in. * * @return void */ public function print_captured() { if ( ! $this->capturing ) { return; } $this->capturing = false; $html = ob_get_clean(); if ( ! is_string( $html ) ) { return; } // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Administration markup already printed by the screen, with cells filled by escaped column renderers. echo $this->fill_columns( $html ); } /** * Loads the translation UI styles on the Theme Builder dashboard. * * @return void */ public function enqueue_assets() { wp_enqueue_style( 'shapetranslate-admin', SHAPETRANSLATE_URL . 'assets/css/admin.css', array(), Assets::version( 'assets/css/admin.css' ) ); } /** * Writes each row's markup into the cell left empty for it. * * The rows print in the order the table holds them, and each row prints one * cell per column, so the nth empty cell of a column belongs to the nth * template. Nothing else in the table is read, which is what keeps this * indifferent to how the rest of a row is built. * * @param string $html Captured dashboard markup. * @return string */ private function fill_columns( $html ) { if ( null === $this->table || ! is_array( $this->table->items ) ) { return $html; } $items = array_values( $this->table->items ); $rows = array( 'shapetranslate_language' => 0, 'shapetranslate_translations' => 0, ); $filled = preg_replace_callback( self::CELL_PATTERN, function ( $matches ) use ( &$rows, $items ) { $quote = $matches[1]; $column = $matches[2]; $row = $rows[ $column ]; ++$rows[ $column ]; $post_id = isset( $items[ $row ] ) && $items[ $row ] instanceof WP_Post ? absint( $items[ $row ]->ID ) : 0; if ( 0 === $post_id ) { return $matches[0]; } $content = 'shapetranslate_language' === $column ? $this->list_table->get_language_markup( $post_id ) : $this->list_table->get_translations_markup( $post_id ); return '