Soft_ML_Admin::SLUG, 'tab' => 'edit', 'post' => $source, 'lang' => $lang ), $extra ), admin_url( 'admin.php' ) ); } private function flash( $type, $msg ) { set_transient( 'softml_notice_' . get_current_user_id(), array( $type, $msg ), 60 ); } /* ------------------------------------------------------------ handlers */ public function handle_create() { check_admin_referer( 'softml_create_translation' ); if ( ! current_user_can( Soft_ML_Admin::CAP ) ) { wp_die( esc_html__( 'You do not have permission to do that.', 'softtrix-multilanguage' ), 403 ); } $source = isset( $_POST['source'] ) ? absint( $_POST['source'] ) : 0; $lang = isset( $_POST['lang'] ) ? sanitize_key( wp_unslash( $_POST['lang'] ) ) : ''; $slug = isset( $_POST['slug'] ) ? sanitize_title( wp_unslash( $_POST['slug'] ) ) : ''; $new = Soft_ML_Page_Creator::create( $source, $lang, $slug ); if ( is_wp_error( $new ) ) { $this->flash( 'error', $new->get_error_message() ); wp_safe_redirect( admin_url( 'admin.php?page=' . Soft_ML_Admin::SLUG . '&tab=translations' ) ); exit; } $this->flash( 'success', __( 'Translation created as a draft. Scan the original page to load its text.', 'softtrix-multilanguage' ) ); wp_safe_redirect( $this->edit_url( $source, $lang ) ); exit; } public function handle_scan() { check_admin_referer( 'softml_scan_page' ); if ( ! current_user_can( Soft_ML_Admin::CAP ) ) { wp_die( esc_html__( 'You do not have permission to do that.', 'softtrix-multilanguage' ), 403 ); } $source = isset( $_POST['source'] ) ? absint( $_POST['source'] ) : 0; $lang = isset( $_POST['lang'] ) ? sanitize_key( wp_unslash( $_POST['lang'] ) ) : ''; if ( ! current_user_can( 'edit_post', $source ) ) { wp_die( esc_html__( 'You do not have permission to do that.', 'softtrix-multilanguage' ), 403 ); } $res = Soft_ML_Scanner::scan( $source ); if ( is_wp_error( $res ) ) { $this->flash( 'error', $res->get_error_message() ); } else { /* translators: 1: segments on the page, 2: segments not seen before. */ $this->flash( 'success', sprintf( __( 'Scan complete: %1$d text segments, %2$d new.', 'softtrix-multilanguage' ), $res['segments'], $res['new'] ) ); } wp_safe_redirect( $this->edit_url( $source, $lang ) ); exit; } public function handle_save() { check_admin_referer( 'softml_save_segments' ); if ( ! current_user_can( Soft_ML_Admin::CAP ) ) { wp_die( esc_html__( 'You do not have permission to do that.', 'softtrix-multilanguage' ), 403 ); } $source = isset( $_POST['source'] ) ? absint( $_POST['source'] ) : 0; $lang = isset( $_POST['lang'] ) ? sanitize_key( wp_unslash( $_POST['lang'] ) ) : ''; $tid = Soft_ML_Translations::get_translation_id( $source, $lang ); if ( ! $tid || ! Soft_ML_Languages::exists( $lang ) ) { wp_die( esc_html__( 'Unknown translation.', 'softtrix-multilanguage' ), 404 ); } if ( ! current_user_can( 'edit_post', $tid ) ) { wp_die( esc_html__( 'You do not have permission to do that.', 'softtrix-multilanguage' ), 403 ); } $errors = array(); // Title, slug, status. $update = array( 'ID' => $tid ); if ( isset( $_POST['title'] ) ) { $update['post_title'] = sanitize_text_field( wp_unslash( $_POST['title'] ) ); } $status = isset( $_POST['tr_status'] ) ? sanitize_key( wp_unslash( $_POST['tr_status'] ) ) : ''; if ( in_array( $status, Soft_ML_Translations::STATUSES, true ) ) { $update['post_status'] = 'published' === $status ? 'publish' : 'draft'; } if ( isset( $_POST['slug'] ) ) { $slug = sanitize_title( wp_unslash( $_POST['slug'] ) ); if ( '' === $slug ) { $errors[] = __( 'Slug cannot be empty.', 'softtrix-multilanguage' ); } elseif ( Soft_ML_Page_Creator::slug_taken( $slug, $lang, $tid ) ) { $errors[] = __( 'That slug is already used by another translation in this language.', 'softtrix-multilanguage' ); } else { update_post_meta( $tid, '_softml_slug', $slug ); } } // SEO fields first, then always re-save the post: SEO plugins rebuild their indexable on save. $seo = isset( $_POST['seo'] ) && is_array( $_POST['seo'] ) ? wp_unslash( $_POST['seo'] ) : array(); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput Soft_ML_SEO_Meta::save( $tid, $seo ); wp_update_post( wp_slash( $update ) ); Soft_ML_Links::bump(); if ( in_array( $status, Soft_ML_Translations::STATUSES, true ) ) { Soft_ML_Translations::set_status( $tid, $status ); } // Segments. $tr = isset( $_POST['tr'] ) && is_array( $_POST['tr'] ) ? wp_unslash( $_POST['tr'] ) : array(); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput $ok = isset( $_POST['ok'] ) && is_array( $_POST['ok'] ) ? array_keys( $_POST['ok'] ) : array(); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput $saved = 0; foreach ( $tr as $hash => $text ) { if ( ! is_string( $hash ) || 1 !== preg_match( '/^[a-f0-9]{40}$/', $hash ) || ! is_string( $text ) ) { continue; } $approved = in_array( $hash, $ok, true ) ? Soft_ML_Strings::STATUS_APPROVED : Soft_ML_Strings::STATUS_DRAFT; $res = Soft_ML_Strings::set_translation( $hash, $lang, $text, $approved ); if ( is_wp_error( $res ) ) { $errors[] = $res->get_error_message(); } else { ++$saved; } } if ( $errors ) { $this->flash( 'error', implode( ' ', array_unique( $errors ) ) ); } else { /* translators: %d: number of segments saved. */ $this->flash( 'success', sprintf( __( 'Saved. %d segment(s) updated.', 'softtrix-multilanguage' ), $saved ) ); } wp_safe_redirect( $this->edit_url( $source, $lang, array( 'filter' => isset( $_POST['filter'] ) ? sanitize_key( wp_unslash( $_POST['filter'] ) ) : 'all', 'paged' => isset( $_POST['paged'] ) ? absint( $_POST['paged'] ) : 1 ) ) ); exit; } /* ------------------------------------------------------------ view */ public function render() { $source = isset( $_GET['post'] ) ? absint( $_GET['post'] ) : 0; // phpcs:ignore WordPress.Security.NonceVerification $lang = isset( $_GET['lang'] ) ? sanitize_key( wp_unslash( $_GET['lang'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification $filter = isset( $_GET['filter'] ) ? sanitize_key( wp_unslash( $_GET['filter'] ) ) : 'all'; // phpcs:ignore WordPress.Security.NonceVerification $filter = in_array( $filter, array( 'all', 'todo', 'review' ), true ) ? $filter : 'all'; $paged = isset( $_GET['paged'] ) ? max( 1, absint( $_GET['paged'] ) ) : 1; // phpcs:ignore WordPress.Security.NonceVerification $src = get_post( $source ); $tid = $src ? Soft_ML_Translations::get_translation_id( $source, $lang ) : 0; if ( ! $src || ! $tid || ! Soft_ML_Languages::exists( $lang ) ) { echo '
' . esc_html__( 'Translation not found.', 'softtrix-multilanguage' ) . '
'; return; } $language = Soft_ML_Languages::get( $lang ); $row = Soft_ML_Translations::get_row( $tid ); $prog = Soft_ML_Strings::progress( $source, $lang ); $scanned = get_post_meta( $source, '_softml_scanned_at', true ); $pct = $prog['total'] ? (int) floor( 100 * $prog['approved'] / $prog['total'] ) : 0; echo '← ' . esc_html__( 'Back to overview', 'softtrix-multilanguage' ) . ' | '; echo '' . esc_html__( 'Original', 'softtrix-multilanguage' ) . ' | '; echo '' . esc_html__( 'Translation post', 'softtrix-multilanguage' ) . ' | '; echo '' . esc_html__( 'Preview (includes unapproved text)', 'softtrix-multilanguage' ) . '
'; /* translators: 1: approved, 2: total, 3: percent. */ echo '' . esc_html( sprintf( __( 'Approved %1$d of %2$d segments (%3$d%%)', 'softtrix-multilanguage' ), $prog['approved'], $prog['total'], $pct ) ) . ' · '; echo esc_html( sprintf( /* translators: %d: drafts */ __( '%d awaiting review', 'softtrix-multilanguage' ), $prog['draft'] ) ) . ' · '; echo esc_html( $scanned ? sprintf( /* translators: %s: date */ __( 'last scanned %s UTC', 'softtrix-multilanguage' ), $scanned ) : __( 'not scanned yet', 'softtrix-multilanguage' ) ) . '
'; echo ''; list( $rows, $total ) = Soft_ML_Strings::editor_rows( $source, $lang, $filter, ( $paged - 1 ) * self::PER_PAGE, self::PER_PAGE ); echo ''; // Separate form (forms cannot nest) used by the "Approve all drafts" button above. echo ''; /** * Extra editor sections from add-ons. * * @param int $source Original post ID. * @param string $lang Language code. * @param int $tid Translation post ID. */ do_action( 'softml_editor_after', $source, $lang, $tid ); } /** * Show' . esc_html( $p ) . '';
} else {
$out .= esc_html( html_entity_decode( $p, ENT_QUOTES, 'UTF-8' ) );
}
}
return $out;
}
}