translation_manager = $translation_manager; $this->language_manager = $language_manager; $this->actions = $actions; $this->meta_box = new TranslationMetaBox( $translation_manager, $language_manager, $actions ); $this->list_table = new TranslationListTable( $translation_manager, $language_manager, $actions ); } /** * {@inheritdoc} */ public function register() { $this->list_table->register_hooks(); add_action( 'add_meta_boxes', array( $this, 'register_meta_box' ), 10, 2 ); add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_assets' ) ); add_action( 'save_post', array( $this, 'save_post_language' ), 10, 2 ); add_action( 'admin_post_shapetranslate_create_translation', array( $this, 'create_translation' ) ); add_action( 'admin_notices', array( $this, 'render_notice' ) ); } /** * Loads translation UI styles on supported post screens. * * @return void */ public function enqueue_assets() { $screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null; if ( ! $screen || ! in_array( $screen->base, array( 'post', 'edit' ), true ) || ! $this->translation_manager->supports_post_type( $screen->post_type ) ) { return; } wp_enqueue_style( 'shapetranslate-admin', SHAPETRANSLATE_URL . 'assets/css/admin.css', array(), Assets::version( 'assets/css/admin.css' ) ); } /** * Registers the language meta box for supported posts. * * @param string $post_type Current post type. * @param WP_Post $post Current post. * @return void */ public function register_meta_box( $post_type, $post ) { if ( ! $post instanceof WP_Post || ! $this->translation_manager->supports_post_type( $post_type ) || ! $this->language_manager->has_languages() || ! current_user_can( 'edit_post', $post->ID ) ) { return; } add_meta_box( 'shapetranslate-language', esc_html__( 'Language', 'shapetranslate' ), array( $this->meta_box, 'render' ), $post_type, 'side', 'high' ); } /** * Saves a post language from the editor. * * @param int $post_id Post identifier. * @param WP_Post $post Saved post. * @return void */ public function save_post_language( $post_id, $post ) { if ( ! $post instanceof WP_Post || ! $this->translation_manager->supports_post_type( $post->post_type ) || ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) || wp_is_post_revision( $post_id ) || wp_is_post_autosave( $post_id ) || ! current_user_can( 'edit_post', $post_id ) ) { return; } // phpcs:disable WordPress.Security.NonceVerification.Missing -- Verified immediately below. $nonce = isset( $_POST['shapetranslate_language_nonce'] ) && is_scalar( $_POST['shapetranslate_language_nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['shapetranslate_language_nonce'] ) ) : ''; // phpcs:enable WordPress.Security.NonceVerification.Missing if ( ! wp_verify_nonce( $nonce, 'shapetranslate_save_post_language_' . absint( $post_id ) ) ) { return; } // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Verified above. $language_id = isset( $_POST['shapetranslate_language_id'] ) && is_scalar( $_POST['shapetranslate_language_id'] ) ? sanitize_text_field( wp_unslash( $_POST['shapetranslate_language_id'] ) ) : ''; $result = $this->translation_manager->set_post_language( $post_id, $language_id ); if ( is_wp_error( $result ) ) { $this->store_error( $result ); } } /** * Creates and opens a translated draft. * * @return void */ public function create_translation() { // Values select the nonce action and are validated before any mutation. // phpcs:disable WordPress.Security.NonceVerification.Recommended $source_post_id = isset( $_GET['source_post_id'] ) && is_scalar( $_GET['source_post_id'] ) ? absint( wp_unslash( $_GET['source_post_id'] ) ) : 0; $language_id = isset( $_GET['language_id'] ) && is_scalar( $_GET['language_id'] ) ? sanitize_text_field( wp_unslash( $_GET['language_id'] ) ) : ''; // phpcs:enable WordPress.Security.NonceVerification.Recommended check_admin_referer( 'shapetranslate_create_translation_' . $source_post_id . '_' . $language_id ); $post = get_post( $source_post_id ); if ( ! $post instanceof WP_Post || ! $this->translation_manager->supports_post_type( $post->post_type ) || ! $this->actions->can_create_translation( $post ) ) { wp_die( esc_html__( 'You are not allowed to create this translation.', 'shapetranslate' ), '', array( 'response' => 403 ) ); } $result = $this->translation_manager->create_translation( $source_post_id, $language_id ); if ( is_wp_error( $result ) ) { $this->store_error( $result ); $this->redirect_to_post( $source_post_id ); } $edit_url = get_edit_post_link( $result, '' ); $edit_url = is_string( $edit_url ) && '' !== $edit_url ? $edit_url : add_query_arg( array( 'post' => absint( $result ), 'action' => 'edit', ), admin_url( 'post.php' ) ); wp_safe_redirect( add_query_arg( 'shapetranslate_notice', 'translation_created', $edit_url ) ); exit; } /** * Renders controlled content translation notices. * * @return void */ public function render_notice() { // phpcs:disable WordPress.Security.NonceVerification.Recommended -- Read-only, allowlisted notice code. $notice_code = isset( $_GET['shapetranslate_notice'] ) ? sanitize_key( wp_unslash( $_GET['shapetranslate_notice'] ) ) : ''; // phpcs:enable WordPress.Security.NonceVerification.Recommended $notices = array( 'translation_created' => __( 'Translated draft created and linked.', 'shapetranslate' ), ); if ( isset( $notices[ $notice_code ] ) ) { printf( '
%s
%s