prepare( " AND %i.ID NOT IN (SELECT object_id FROM %i WHERE object_type = 'post' AND language_code <> %s)", $posts_table, Soft_ML_Translations::table(), $mode ); } return $wpdb->prepare( " AND %i.ID IN (SELECT object_id FROM %i WHERE object_type = 'post' AND language_code = %s)", $posts_table, Soft_ML_Translations::table(), $mode ); } /* ------------------------------------------------------------------ query + counts */ public static function filter_query( $q ) { if ( $q->is_main_query() && self::on_list( (string) $q->get( 'post_type' ) ?: '' ) ) { $q->set( 'softml_list_lang', self::current() ); } } public static function posts_where( $where, $q ) { $mode = $q->get( 'softml_list_lang' ); if ( ! $mode ) { return $where; } global $wpdb; return $where . self::condition( $mode, $wpdb->posts ); } /** * Keep the "All (n) | Published (n) | Draft (n)" numbers consistent with the filtered list. */ public static function count_posts( $counts, $type, $perm ) { static $busy = false; if ( $busy || ! self::on_list( $type ) || ! current_user_can( 'edit_others_posts' ) ) { return $counts; } $busy = true; global $wpdb; $mode = self::current(); $def = Soft_ML_Languages::default_code(); if ( 'all' === $mode ) { $rows = $wpdb->get_results( // phpcs:ignore WordPress.DB $wpdb->prepare( "SELECT post_status, COUNT(*) AS n FROM {$wpdb->posts} WHERE post_type = %s GROUP BY post_status", $type ), ARRAY_A ); } elseif ( $def === $mode ) { $rows = $wpdb->get_results( // phpcs:ignore WordPress.DB $wpdb->prepare( "SELECT post_status, COUNT(*) AS n FROM {$wpdb->posts} WHERE post_type = %s AND ID NOT IN (SELECT object_id FROM %i WHERE object_type = 'post' AND language_code <> %s) GROUP BY post_status", $type, Soft_ML_Translations::table(), $mode ), ARRAY_A ); } else { $rows = $wpdb->get_results( // phpcs:ignore WordPress.DB $wpdb->prepare( "SELECT post_status, COUNT(*) AS n FROM {$wpdb->posts} WHERE post_type = %s AND ID IN (SELECT object_id FROM %i WHERE object_type = 'post' AND language_code = %s) GROUP BY post_status", $type, Soft_ML_Translations::table(), $mode ), ARRAY_A ); } $out = new stdClass(); foreach ( get_post_stati() as $status ) { $out->$status = 0; } foreach ( (array) $rows as $r ) { $out->{$r['post_status']} = (int) $r['n']; } $busy = false; return $out; } /* ------------------------------------------------------------------ language bar */ /** * @param array $views Status links. * @return array */ public static function views( $views ) { global $wpdb; $type = isset( $_GET['post_type'] ) ? sanitize_key( wp_unslash( $_GET['post_type'] ) ) : 'post'; // phpcs:ignore WordPress.Security.NonceVerification $cur = self::current(); $def = Soft_ML_Languages::default_code(); // Counts per language (excluding trash and auto-drafts). $total = (int) $wpdb->get_var( // phpcs:ignore WordPress.DB $wpdb->prepare( "SELECT COUNT(*) FROM {$wpdb->posts} WHERE post_type = %s AND post_status NOT IN ('trash','auto-draft')", $type ) ); $per = array(); foreach ( (array) $wpdb->get_results( // phpcs:ignore WordPress.DB $wpdb->prepare( "SELECT t.language_code AS c, COUNT(*) AS n FROM %i t JOIN {$wpdb->posts} p ON p.ID = t.object_id WHERE t.object_type = 'post' AND p.post_type = %s AND p.post_status NOT IN ('trash','auto-draft') GROUP BY t.language_code", Soft_ML_Translations::table(), $type ), ARRAY_A ) as $r ) { $per[ $r['c'] ] = (int) $r['n']; } // Originals are registered in their group under the default language: those are not translations. $translated = array_sum( $per ) - ( isset( $per[ $def ] ) ? $per[ $def ] : 0 ); $base = add_query_arg( array_filter( array( 'post_type' => 'post' === $type ? '' : $type, 'post_status' => isset( $_GET['post_status'] ) ? sanitize_key( wp_unslash( $_GET['post_status'] ) ) : '' ) ), admin_url( 'edit.php' ) ); // phpcs:ignore WordPress.Security.NonceVerification $items = array(); $items[] = self::lang_link( $base, 'all', __( 'All languages', 'softtrix-multilanguage' ), $total, 'all' === $cur ); foreach ( Soft_ML_Languages::enabled() as $l ) { $n = $l['code'] === $def ? max( 0, $total - $translated ) : ( isset( $per[ $l['code'] ] ) ? $per[ $l['code'] ] : 0 ); $items[] = self::lang_link( $base, $l['code'], $l['native_name'], $n, $cur === $l['code'] ); } $bar = '
  • ' . esc_html__( 'Language:', 'softtrix-multilanguage' ) . ' ' . implode( ' | ', $items ) . '
  • '; // phpcs:ignore WordPress.Security.EscapeOutput -- built from escaped parts. // Keep the chosen language when switching status (All / Published / Draft ...). if ( $def !== $cur ) { foreach ( $views as $k => $html ) { $views[ $k ] = preg_replace_callback( '~href=(["\'])(.*?)\1~', static function ( $m ) use ( $cur ) { return 'href=' . $m[1] . esc_url( add_query_arg( 'softml_lang', $cur, html_entity_decode( $m[2] ) ) ) . $m[1]; }, $html ); } } return array_merge( array( 'softml_langs' => $bar ), $views ); } private static function lang_link( $base, $code, $label, $n, $active ) { $url = add_query_arg( 'softml_lang', $code, $base ); return '' . esc_html( $label ) . ' (' . (int) $n . ')'; } /* ------------------------------------------------------------------ column */ public static function columns( $cols ) { $out = array(); foreach ( $cols as $k => $v ) { $out[ $k ] = $v; if ( 'title' === $k ) { $out['softml_languages'] = esc_html__( 'Languages', 'softtrix-multilanguage' ); } } if ( ! isset( $out['softml_languages'] ) ) { $out['softml_languages'] = esc_html__( 'Languages', 'softtrix-multilanguage' ); } return $out; } public static function column( $column, $post_id ) { if ( 'softml_languages' !== $column ) { return; } $def = Soft_ML_Languages::default_code(); $row = Soft_ML_Translations::get_row( $post_id ); // A translation: say which language, link back to the original. if ( $row && $row['language_code'] !== $def ) { $l = Soft_ML_Languages::get( $row['language_code'] ); $src = Soft_ML_Translations::get_translation_id( $post_id, $def ); echo '' . esc_html( strtoupper( $row['language_code'] ) ) . ' '; if ( $src ) { echo '← ' . esc_html( strtoupper( $def ) ) . ' ' . esc_html__( 'original', 'softtrix-multilanguage' ) . ''; } unset( $l ); return; } $group = $row ? Soft_ML_Translations::get_group( $row['group_id'] ) : array(); $names = array( 'draft' => __( 'Draft', 'softtrix-multilanguage' ), 'in_progress' => __( 'In Progress', 'softtrix-multilanguage' ), 'published' => __( 'Published', 'softtrix-multilanguage' ), ); foreach ( Soft_ML_Languages::enabled() as $l ) { if ( $l['code'] === $def ) { continue; } $code = strtoupper( $l['code'] ); if ( isset( $group[ $l['code'] ] ) ) { $st = $group[ $l['code'] ]['status']; printf( '%4$s ', esc_attr( $st ), esc_url( get_edit_post_link( (int) $group[ $l['code'] ]['object_id'] ) ), /* translators: 1: language, 2: status */ esc_attr( sprintf( __( '%1$s: %2$s - click to edit', 'softtrix-multilanguage' ), $l['native_name'], isset( $names[ $st ] ) ? $names[ $st ] : $st ) ), esc_html( $code ) ); } else { $slug = (string) get_post_field( 'post_name', $post_id ); printf( '+ %3$s ', esc_url( admin_url( 'admin.php?page=' . Soft_ML_Admin::SLUG . '&tab=translations&s=' . rawurlencode( $slug ) ) ), /* translators: %s: language */ esc_attr( sprintf( __( '%s: not translated - open Translations to create it', 'softtrix-multilanguage' ), $l['native_name'] ) ), esc_html( $code ) ); } } } }