493 lines
15 KiB
PHP
493 lines
15 KiB
PHP
<?php
|
|
|
|
use WPML\FP\Lst;
|
|
|
|
/**
|
|
* Class WPML_TM_Dashboard
|
|
*/
|
|
class WPML_TM_Dashboard {
|
|
|
|
/**
|
|
* @var array
|
|
*/
|
|
private $translatable_post_types = null;
|
|
|
|
/**
|
|
* @var wpdb
|
|
*/
|
|
private $wpdb;
|
|
|
|
/**
|
|
* @var SitePress
|
|
*/
|
|
private $sitepress;
|
|
|
|
/**
|
|
* @var int
|
|
*/
|
|
private $found_documents = 0;
|
|
|
|
/**
|
|
* WPML_TM_Dashboard constructor.
|
|
*
|
|
* @param wpdb $wpdb
|
|
* @param SitePress $sitepress
|
|
*/
|
|
public function __construct( wpdb $wpdb, SitePress $sitepress ) {
|
|
$this->wpdb = $wpdb;
|
|
$this->sitepress = $sitepress;
|
|
add_filter( 'posts_where', array( $this, 'add_dashboard_filter_conditions' ), 10, 2 );
|
|
}
|
|
|
|
/**
|
|
* @param array $args
|
|
*
|
|
* @return array
|
|
*/
|
|
public function get_documents( $args = array() ) {
|
|
$results = array();
|
|
$documents = array();
|
|
|
|
$defaults = array(
|
|
'from_lang' => 'en',
|
|
'to_lang' => '',
|
|
'tstatus' => -1,
|
|
'sort_by' => 'date',
|
|
'sort_order' => 'DESC',
|
|
'limit_no' => ICL_TM_DOCS_PER_PAGE,
|
|
'parent_type' => 'any',
|
|
'parent_id' => false,
|
|
'type' => '',
|
|
'title' => '',
|
|
'status' => array( 'publish', 'pending', 'draft', 'future', 'private', 'inherit' ),
|
|
'page' => 0,
|
|
);
|
|
|
|
$args = $this->remove_empty_arguments( $args );
|
|
$args = wp_parse_args( $args, $defaults );
|
|
|
|
$documents = $this->add_string_packages( $documents, $args );
|
|
$documents = $this->add_translatable_posts( $documents, $args );
|
|
$filtered_documents = apply_filters( 'wpml_tm_dashboard_documents', $documents );
|
|
$filtered_documents = array_slice( $filtered_documents, 0, $args['limit_no'] );
|
|
$results['documents'] = $filtered_documents;
|
|
$results['found_documents'] = $this->found_documents - ( count( $documents ) - count( $filtered_documents ) );
|
|
|
|
return $results;
|
|
}
|
|
|
|
/**
|
|
* @param $args
|
|
*
|
|
* @return array
|
|
*/
|
|
private function remove_empty_arguments( $args ) {
|
|
$output = array();
|
|
foreach ( $args as $argument_name => $argument_value ) {
|
|
if ( '' !== $argument_value && null !== $argument_value ) {
|
|
$output[ $argument_name ] = $argument_value;
|
|
}
|
|
}
|
|
|
|
return $output;
|
|
}
|
|
|
|
/**
|
|
* Add list of translatable post types to dashboard.
|
|
*
|
|
* @param array $results
|
|
* @param array $args
|
|
*
|
|
* @return array
|
|
*/
|
|
private function add_translatable_posts( $results, $args ) {
|
|
$post_types = $this->get_translatable_post_types();
|
|
$offset = 0;
|
|
if ( $this->is_cpt_type( $args ) ) {
|
|
$post_types = array( $args['type'] );
|
|
$offset = $args['page'] * $args['limit_no'];
|
|
} elseif ( ! empty( $args['type'] ) ) {
|
|
return $results;
|
|
}
|
|
|
|
$query_args = [
|
|
'post_type' => $post_types,
|
|
'orderby' => $args['sort_by'],
|
|
'order' => $args['sort_order'],
|
|
'posts_per_page' => $args['limit_no'] + 1,
|
|
'post_status' => $args['status'],
|
|
'post_language' => $args['from_lang'],
|
|
'post_language_to' => $args['to_lang'],
|
|
'post_translation_status' => $args['tstatus'],
|
|
'suppress_filters' => false,
|
|
'update_post_meta_cache' => false,
|
|
'update_post_term_cache' => false,
|
|
'no_found_rows' => true,
|
|
'offset' => $offset,
|
|
];
|
|
|
|
if ( 'any' !== $args['parent_type'] ) {
|
|
switch ( $args['parent_type'] ) {
|
|
case 'page':
|
|
$query_args['post_parent'] = (int) $args['parent_id'];
|
|
break;
|
|
default:
|
|
$query_args['tax_query'] = array(
|
|
array(
|
|
'taxonomy' => $args['parent_type'],
|
|
'field' => 'term_id',
|
|
'terms' => (int) $args['parent_id'],
|
|
),
|
|
);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( isset( $args['translation_priority'] ) ) {
|
|
|
|
$translation_priorities = new WPML_TM_Translation_Priorities();
|
|
|
|
if ( $translation_priorities->get_default_value_id() === (int) $args['translation_priority'] ) {
|
|
$tax_query = array(
|
|
'relation' => 'OR',
|
|
array(
|
|
'taxonomy' => 'translation_priority',
|
|
'operator' => 'NOT EXISTS',
|
|
),
|
|
);
|
|
}
|
|
|
|
$tax_query[] = array(
|
|
'taxonomy' => 'translation_priority',
|
|
'field' => 'term_id',
|
|
'terms' => $args['translation_priority'],
|
|
);
|
|
|
|
$query_args['tax_query'] = $tax_query;
|
|
|
|
}
|
|
|
|
if ( ! empty( $args['title'] ) ) {
|
|
$query_args['post_title_like'] = $args['title'];
|
|
}
|
|
|
|
$lang = $this->sitepress->get_admin_language();
|
|
$this->sitepress->switch_lang( $args['from_lang'] );
|
|
$query_args = apply_filters( 'wpml_tm_dashboard_post_query_args', $query_args, $args );
|
|
$query = new WPML_TM_WP_Query( $query_args );
|
|
$this->sitepress->switch_lang( $lang );
|
|
if ( ! empty( $query->posts ) ) {
|
|
foreach ( $query->posts as $post ) {
|
|
$language_details = $this->sitepress->get_element_language_details( $post->ID, 'post_' . $post->post_type );
|
|
$post_obj = new stdClass();
|
|
$post_obj->ID = $post->ID;
|
|
$post_obj->translation_element_type = 'post_' . $post->post_type;
|
|
$post_obj->title = $post->post_title;
|
|
$post_obj->is_translation = ( null === $language_details->source_language_code ) ? '0' : '1';
|
|
$post_obj->language_code = $language_details->language_code;
|
|
$post_obj->trid = $language_details->trid;
|
|
$results[] = $post_obj;
|
|
}
|
|
}
|
|
$this->found_documents += $query->get_found_count();
|
|
wp_reset_query();
|
|
return $results;
|
|
}
|
|
|
|
/**
|
|
* Add additional where conditions to support the following query arguments:
|
|
* - post_title_like - Allow query posts with SQL LIKE in post title.
|
|
* - post_language_to - Allow query posts with language they are translated to.
|
|
* - post_translation_status - Allow to query posts by their translation status.
|
|
*
|
|
* @param string $where
|
|
* @param object $wp_query
|
|
*
|
|
* @return string
|
|
*/
|
|
public function add_dashboard_filter_conditions( $where, $wp_query ) {
|
|
$post_title_like = $wp_query->get( 'post_title_like' );
|
|
$post_language = $wp_query->get( 'post_language_to' );
|
|
$post_translation_status = (int) $wp_query->get( 'post_translation_status' );
|
|
|
|
if ( $post_title_like ) {
|
|
$where .= $this->wpdb->prepare( " AND {$this->wpdb->posts}.post_title LIKE '%s'", '%' . $this->wpdb->esc_like( $post_title_like ) . '%' );
|
|
}
|
|
|
|
$post_type = $wp_query->get( 'post_type' );
|
|
if ( Lst::includes( $post_type[0], $this->get_translatable_post_types() ) ) {
|
|
$where .= $this->build_translation_status_where( $post_translation_status, $post_language );
|
|
}
|
|
|
|
return $where;
|
|
}
|
|
|
|
/**
|
|
* Add string packages to translation dashboard.
|
|
*
|
|
* @param array $results
|
|
* @param array $args
|
|
*
|
|
* @return array
|
|
*/
|
|
private function add_string_packages( $results, $args ) {
|
|
$string_packages_table = $this->wpdb->prefix . 'icl_string_packages';
|
|
$translations_table = $this->wpdb->prefix . 'icl_translations';
|
|
$offset = 0;
|
|
|
|
if ( $this->is_cpt_type( $args ) ) {
|
|
return array();
|
|
}
|
|
|
|
$sql_calc_found_rows = '';
|
|
$must_count_rows = array_key_exists( 'type', $args ) && ! empty( $args['type'] );
|
|
if ( $must_count_rows ) {
|
|
$offset = $args['page'] * $args['limit_no'];
|
|
$sql_calc_found_rows = 'SQL_CALC_FOUND_ROWS';
|
|
}
|
|
|
|
if ( ! is_plugin_active( 'wpml-string-translation/plugin.php' ) ) {
|
|
return $results;
|
|
}
|
|
|
|
// Exit if *icl_string_packages table doesn't exist.
|
|
if ( $this->wpdb->get_var( "SHOW TABLES LIKE '$string_packages_table'" ) !== $string_packages_table ) {
|
|
return $results;
|
|
}
|
|
|
|
$where = $this->create_string_packages_where( $args );
|
|
|
|
$sql = "SELECT DISTINCT {$sql_calc_found_rows}
|
|
st_table.ID,
|
|
st_table.kind_slug,
|
|
st_table.title,
|
|
wpml_translations.element_type,
|
|
wpml_translations.language_code,
|
|
wpml_translations.source_language_code,
|
|
wpml_translations.trid
|
|
FROM {$string_packages_table} AS st_table
|
|
LEFT JOIN {$translations_table} AS wpml_translations
|
|
ON wpml_translations.element_id=st_table.ID OR wpml_translations.element_id = null
|
|
WHERE 1 = 1 {$where}
|
|
GROUP BY st_table.ID
|
|
ORDER BY st_table.ID ASC
|
|
LIMIT {$args['limit_no']}
|
|
OFFSET {$offset}";
|
|
$sql = apply_filters( 'wpml_tm_dashboard_external_type_sql_query', $sql, $args );
|
|
$packages = $this->wpdb->get_results( $sql );
|
|
|
|
if ( $must_count_rows ) {
|
|
$this->found_documents += $this->wpdb->get_var( 'SELECT FOUND_ROWS()' );
|
|
}
|
|
foreach ( $packages as $package ) {
|
|
$package_obj = new stdClass();
|
|
$package_obj->ID = $package->ID;
|
|
$package_obj->translation_element_type = WPML_Package_Translation::get_package_element_type( $package->kind_slug );
|
|
$package_obj->title = $package->title;
|
|
$package_obj->is_translation = ( null === $package->source_language_code ) ? '0' : '1';
|
|
$package_obj->language_code = $package->language_code;
|
|
$package_obj->trid = $package->trid;
|
|
$results[] = $package_obj;
|
|
}
|
|
|
|
return $results;
|
|
}
|
|
|
|
/**
|
|
* Create additional where clause for querying string packages based on filters.
|
|
*
|
|
* @param array $args
|
|
*
|
|
* @return string
|
|
*/
|
|
private function create_string_packages_where( $args ) {
|
|
$where = " AND wpml_translations.element_type LIKE 'package%' AND st_table.post_id IS NULL";
|
|
if ( ! $this->is_cpt_type( $args ) && ! empty( $args['type'] ) ) {
|
|
$where .= $this->wpdb->prepare( " AND kind_slug='%s'", $args['type'] );
|
|
}
|
|
|
|
if ( ! empty( $args['title'] ) ) {
|
|
$where .= $this->wpdb->prepare( " AND title LIKE '%s'", '%' . $this->wpdb->esc_like( $args['title'] ) . '%' );
|
|
}
|
|
|
|
if ( ! empty( $args['to_lang'] ) ) {
|
|
$where .= $this->wpdb->prepare( " AND wpml_translations.language_code='%s'", $args['to_lang'] );
|
|
$where .= $this->wpdb->prepare( " AND wpml_translations.source_language_code='%s'", $args['from_lang'] );
|
|
} else {
|
|
$where .= $this->wpdb->prepare( " AND wpml_translations.language_code='%s'", $args['from_lang'] );
|
|
}
|
|
|
|
if ( $args['tstatus'] >= 0 ) {
|
|
$where .= $this->build_translation_status_where( $args['tstatus'] );
|
|
}
|
|
|
|
return $where;
|
|
}
|
|
|
|
/**
|
|
* @param integer $translation_status
|
|
* @param string $language
|
|
*
|
|
* @return string
|
|
*/
|
|
private function build_translation_status_where( $translation_status, $language = null ) {
|
|
if ( $translation_status < 0 && ! $language ) {
|
|
return '';
|
|
}
|
|
|
|
if ( $translation_status < 0 && $language ) {
|
|
$subquery = $this->only_language_condition( $language );
|
|
} else {
|
|
switch ( $translation_status ) {
|
|
case ICL_TM_NOT_TRANSLATED:
|
|
$subquery = $this->not_translated_or_needs_update_condition( $language );
|
|
break;
|
|
case ICL_TM_NEEDS_UPDATE:
|
|
$subquery = $this->needs_update_condition( $language );
|
|
break;
|
|
case ICL_TM_IN_PROGRESS:
|
|
$subquery = $this->explicit_status_condition(
|
|
wpml_prepare_in( [ ICL_TM_IN_PROGRESS, ICL_TM_WAITING_FOR_TRANSLATOR ], '%d' ),
|
|
$language
|
|
);
|
|
break;
|
|
case ICL_TM_COMPLETE:
|
|
$subquery = $this->explicit_status_condition(
|
|
wpml_prepare_in( [ ICL_TM_COMPLETE, ICL_TM_DUPLICATE ], '%d' ),
|
|
$language
|
|
);
|
|
break;
|
|
default:
|
|
$subquery = '';
|
|
}
|
|
}
|
|
|
|
if ( $subquery ) {
|
|
return " AND wpml_translations.trid IN ({$subquery})";
|
|
}
|
|
|
|
return '';
|
|
}
|
|
|
|
private function only_language_condition( $language ) {
|
|
$query = "
|
|
SELECT translations.trid
|
|
FROM {$this->wpdb->prefix}icl_translations translations
|
|
WHERE translations.language_code = %s
|
|
";
|
|
|
|
return $this->wpdb->prepare( $query, $language );
|
|
}
|
|
|
|
private function explicit_status_condition( $status, $language = null ) {
|
|
$prefix = $this->wpdb->prefix;
|
|
|
|
$query = "
|
|
SELECT trid
|
|
FROM {$prefix}icl_translations translations
|
|
INNER JOIN {$prefix}icl_translation_status translation_status ON translation_status.translation_id = translations.translation_id
|
|
WHERE (translation_status.status IN ({$status}) AND translation_status.needs_update = 0)
|
|
";
|
|
|
|
if ( $language ) {
|
|
$query .= $this->language_where( $language );
|
|
}
|
|
|
|
return $query;
|
|
}
|
|
|
|
private function needs_update_condition( $language = null ) {
|
|
$prefix = $this->wpdb->prefix;
|
|
|
|
$query = "
|
|
SELECT trid
|
|
FROM {$prefix}icl_translations translations
|
|
INNER JOIN {$prefix}icl_translation_status translation_status ON translation_status.translation_id = translations.translation_id
|
|
WHERE translation_status.needs_update = 1
|
|
";
|
|
|
|
if ( $language ) {
|
|
$query .= $this->language_where( $language );
|
|
}
|
|
|
|
return $query;
|
|
}
|
|
|
|
private function not_translated_or_needs_update_condition( $language = null ) {
|
|
$prefix = $this->wpdb->prefix;
|
|
|
|
$query = "
|
|
SELECT trid
|
|
FROM {$prefix}icl_translations translations
|
|
INNER JOIN {$prefix}icl_translation_status translation_status ON translation_status.translation_id = translations.translation_id
|
|
WHERE ( translation_status.needs_update = 1 OR translation_status.status = 0 )
|
|
";
|
|
if ( $language ) {
|
|
$query .= $this->language_where( $language );
|
|
}
|
|
|
|
$query .= ' UNION ';
|
|
|
|
if ( $language ) {
|
|
$query .= "
|
|
SELECT trid
|
|
FROM {$prefix}icl_translations translations
|
|
WHERE NOT EXISTS (
|
|
SELECT inner_translations.trid
|
|
FROM {$prefix}icl_translations inner_translations
|
|
WHERE inner_translations.trid = translations.trid AND inner_translations.language_code = %s
|
|
)
|
|
";
|
|
$query = $this->wpdb->prepare( $query, $language );
|
|
} else {
|
|
$query .= "
|
|
SELECT trid
|
|
FROM {$prefix}icl_translations translations
|
|
WHERE (
|
|
SELECT COUNT(inner_translations.trid)
|
|
FROM {$prefix}icl_translations inner_translations
|
|
WHERE inner_translations.trid = translations.trid
|
|
) < %d
|
|
";
|
|
$query = $this->wpdb->prepare( $query, count( $this->sitepress->get_active_languages() ) );
|
|
}
|
|
|
|
return $query;
|
|
}
|
|
|
|
private function language_where( $language ) {
|
|
return $this->wpdb->prepare( ' AND translations.language_code = %s', $language );
|
|
}
|
|
|
|
/**
|
|
* @param array $args
|
|
* @param string $post_type
|
|
*
|
|
* @return bool
|
|
*/
|
|
private function is_cpt_type( $args = array(), $post_type = '' ) {
|
|
$is_cpt_type = false;
|
|
if ( ! empty( $args ) && '' === $post_type && array_key_exists( 'type', $args ) && ! empty( $args['type'] ) ) {
|
|
$post_type = $args['type'];
|
|
}
|
|
|
|
if ( in_array( $post_type, $this->get_translatable_post_types() ) ) {
|
|
$is_cpt_type = true;
|
|
}
|
|
|
|
return $is_cpt_type;
|
|
}
|
|
|
|
/**
|
|
* @return array
|
|
*/
|
|
private function get_translatable_post_types() {
|
|
if ( null === $this->translatable_post_types ) {
|
|
$translatable_post_types = $this->sitepress->get_translatable_documents();
|
|
$this->translatable_post_types = array_keys( apply_filters( 'wpml_tm_dashboard_translatable_types', $translatable_post_types ) );
|
|
}
|
|
|
|
return $this->translatable_post_types;
|
|
}
|
|
}
|