/home/fdhrevqn/public_html/wp-content/plugins.disabled/lingotek-translation/include/model.php
<?php
if ( ! defined( 'ABSPATH' ) ) exit();
/**
* Manages interactions with database
* Factory for Lingotek_Group objects
*
* @since 0.1
*/
class Lingotek_Model {
/**
* Polylang model.
*
* @var obj
*/
public $pllm;
public static $copying_post;
public static $copying_term;
/**
* constructor
*
* @since 0.1
*/
public function __construct() {
$this->pllm = $GLOBALS['polylang']->model;
register_taxonomy(
'lingotek_profile',
null,
array(
'label' => false,
'public' => false,
'query_var' => false,
'rewrite' => false,
)
);
register_taxonomy(
'lingotek_hash',
null,
array(
'label' => false,
'public' => false,
'query_var' => false,
'rewrite' => false,
)
);
}
/**
* get the strings groups as well as their count
*
* @since 0.2
*
* @return array
*/
public static function get_strings() {
static $strings = array();
if ( empty( $strings ) ) {
// Enables sanitization filter.
PLL_Admin_Strings::init();
foreach ( PLL_Admin_Strings::get_strings() as $string ) {
$strings[ $string['context'] ]['context'] = $string['context'];
$strings[ $string['context'] ]['count'] = empty( $strings[ $string['context'] ]['count'] ) ? 1 : $strings[ $string['context'] ]['count'] + 1;
}
$strings = array_values( $strings );
}
return $strings;
}
/**
* create a translation group object from a translation term
*
* @since 0.2
*
* @param object $term
* @return object
*/
protected function convert_term( $term ) {
switch ( $term->taxonomy ) {
case 'term_translations':
return new Lingotek_Group_Term( $term, $this->pllm );
case 'post_translations':
$class = $term->name === $term->slug ? 'Lingotek_Group_Post' : 'Lingotek_Group_String';
return new $class( $term, $this->pllm );
}
}
/**
* get the translation term of an object
*
* @since 0.2
*
* @param string $type Either 'post' or 'term' or 'string'.
* @param int|string $id Post id or term id or strings translations group name.
* @return object Translation term.
*/
public function get_group( $type, $id ) {
switch ( $type ) {
case 'post':
return ( $post = PLL()->model->post->get_object_term( (int) $id, $type . '_translations' ) ) && ! empty( $post ) ? $this->convert_term( $post ) : false;
case 'term':
return ( $term = PLL()->model->term->get_object_term( (int) $id, $type . '_translations' ) ) && ! empty( $term ) ? $this->convert_term( $term ) : false;
case 'string':
if ( is_numeric( $id ) ) {
$strings = self::get_strings();
$id = $strings[ $id ]['context'];
}
return ( $term = get_term_by( 'name', $id, 'post_translations' ) ) && ! empty( $term ) ? $this->convert_term( $term ) : false;
default:
return false;
}
}
/**
* get document id of an object, false if it wasn't uploaded yet.
*
* @since 1.4.11
*
* @param string $type either 'post' or 'term' or 'string'
* @param int|string $id post id or term id or strings translations group name
* @return string|bool document id or false
*/
public function get_document_id( $type, $id ) {
$document_term = $this->get_group( $type, $id );
$document_id = $document_term != false ? $document_term->document_id : false;
return $document_id;
}
/**
* get the translation term of an object by its Lingotek document id
*
* @since 0.2
*
* @param string|object $document_id
* @return object translation term
*/
public function get_group_by_id( $document_id ) {
// we already passed a translation group object
if ( is_object( $document_id ) ) {
return $document_id;
}
$terms = get_terms( array( 'post_translations', 'term_translations' ), array( 'slug' => $document_id ) );
return is_wp_error( $terms ) || empty( $terms ) ? false : $this->convert_term( reset( $terms ) );
}
/**
* get a translation profile
*
* @since 0.2
*
* @param string $type post type or taxonomy
* @param object $language
* @return array
*/
public static function get_profile( $type, $language, $post_id = null ) {
global $profileInformation, $ltk_profiles, $ltk_contentTypes;
if ( is_null( $ltk_profiles ) ) {
$ltk_profiles = get_option( 'lingotek_profiles' );
}
if ( $post_id && $profileInformation && isset( $profileInformation[ $type ] ) && isset( $profileInformation[ $type ][ $language->locale ] ) && isset( $profileInformation[ $type ][ $language->locale ][ $post_id ] ) ) {
return $ltk_profiles[ $profileInformation[ $type ][ $language->locale ][ $post_id ] ];
}
if ( is_null( $ltk_contentTypes ) ) {
$ltk_contentTypes = get_option( 'lingotek_content_type' );
}
// If a profile is set for a specific post/page get that first
if ( $post_id ) {
$profile_override = get_term_by( 'name', 'lingotek_profile_' . $post_id, 'lingotek_profile' );
if ( $profile_override ) {
if ( ! isset( $profileInformation ) ) {
$profileInformation = array(); }
if ( ! isset( $profileInformation[ $type ] ) ) {
$profileInformation[ $type ] = array(); }
if ( ! isset( $profileInformation[ $type ][ $language->locale ] ) ) {
$profileInformation[ $type ][ $language->locale ] = array(); }
$profileInformation[ $type ][ $language->locale ][ $post_id ] = $profile_override->description;
return $ltk_profiles[ $profile_override->description ];
}
}
// Default profile is manual for posts and pages, custom types are set to disabled by default.
$default = 'post' === $type || 'page' === $type ? 'manual' : 'disabled';
$profile = is_object( $language ) && isset( $content_types[ $type ]['sources'][ $language->slug ] ) ?
$ltk_contentTypes[ $type ]['sources'][ $language->slug ] :
( isset( $ltk_contentTypes[ $type ]['profile'] ) ? $ltk_contentTypes[ $type ]['profile'] : $default );
if ( $post_id ) {
if ( ! isset( $profileInformation ) ) {
$profileInformation = array(); }
if ( ! isset( $profileInformation[ $type ] ) ) {
$profileInformation[ $type ] = array(); }
if ( ! isset( $profileInformation[ $type ][ $language->locale ] ) ) {
$profileInformation[ $type ][ $language->locale ] = array(); }
$profileInformation[ $type ][ $language->locale ][ $post_id ] = $profile;
}
return $ltk_profiles[ $profile ];
}
public static function get_prefs() {
$default = array(
'download_post_status' => Lingotek_Group_Post::SAME_AS_SOURCE,
'auto_upload_post_statuses' => array(
// ignore auto-upload
'draft' => 0,
// auto-upload
'pending' => 1,
'publish' => 1,
'future' => 1,
'private' => 0,
),
'trash_linked_content' => array(),
'auto_update_status' => '10',
'enable_lingotek_logs' => 0,
);
// Ensure defaults are set for missing keys.
$prefs = array_merge( $default, get_option( 'lingotek_prefs', $default ) );
return $prefs;
}
/**
* get a profile option
*
* @since 0.2
*
* @param string $item 'project_id' | 'workflow_id' | 'upload' | 'download'.
* @param string $type Post type or taxonomy.
* @param object $source_language
* @param object $target_language Optional, needed to get custom target informations 'workflow_id' | 'download'.
* @return string | bool either the option or false if the translation is disabled.
*/
public static function get_profile_option( $item, $type, $source_language, $target_language = false, $post_id = null ) {
$profile = self::get_profile( $type, $source_language, $post_id );
if ( 'disabled' === $profile['profile'] || is_object( $target_language ) && isset( $profile['targets'][ $target_language->slug ] ) && 'disabled' === $profile['targets'][ $target_language->slug ] ) {
return false;
}
if ( ! empty( $target_language ) && isset( $profile['targets'][ $target_language->slug ] ) && ! empty( $profile['custom'][ $item ][ $target_language->slug ] ) ) {
return $profile['custom'][ $item ][ $target_language->slug ];
}
if ( ! empty( $profile[ $item ] ) ) {
return $profile[ $item ];
}
$defaults = get_option( 'lingotek_defaults', array() );
return isset( $defaults[ $item ] ) ? $defaults[ $item ] : null;
}
/**
* find targets that are set to copy in a profile
*
* @since 1.1.1
*
* @param array $profile (use get_profile to retrieve)
* @return array of targets that should be copied. if none exist returns empty array
*/
public function targets_to_be_copied( $profile ) {
if ( isset( $profile['targets'] ) && in_array( 'copy', $profile['targets'] ) ) {
$targets_to_copy = array_keys( $profile['targets'], 'copy' );
return $targets_to_copy;
} else {
return array();
}
}
/**
* copy a post from the source language to a target language
*
* @since 1.1.1
*
* @param object $post
* @param string $target polylang language slug (ex: en, de, fr, etc)
* @return $new_post_id if copy of post is successful, false otherwise
*/
public function copy_post( $post, $target ) {
self::$copying_post = true;
$document = $this->get_group( 'post', $post->ID );
$prefs = self::get_prefs();
$cp_lang = $this->pllm->get_language( $target );
$cp_post = (array) $post;
$cp_post['post_status'] = ( $prefs['download_post_status'] === 'SAME_AS_SOURCE' ) ? $post->post_status : $prefs['download_post_status'];
$slug = $cp_post['post_name'];
unset( $cp_post['ID'] );
unset( $cp_post['post_name'] );
if ( ! isset( $document->desc_array[ $target ] ) ) {
$new_post_id = wp_insert_post( $cp_post, true );
if ( ! is_wp_error( $new_post_id ) ) {
PLL()->model->post->set_language( $new_post_id, $cp_lang );
wp_set_object_terms( $new_post_id, $document->term_id, 'post_translations' );
$GLOBALS['polylang']->sync->taxonomies->copy( $document->source, $new_post_id, $cp_lang->slug );
$GLOBALS['polylang']->sync->post_metas->copy( $document->source, $new_post_id, $cp_lang->slug );
Lingotek_Group_Post::copy_or_ignore_metas( $post->ID, $new_post_id );
$document->desc_array[ $target ] = $new_post_id;
$document->save();
if ( class_exists( 'PLL_Share_Post_Slug', true ) ) {
wp_update_post(
array(
'ID' => $new_post_id,
'post_name' => $slug,
)
);
}
}
}
self::$copying_post = false;
}
public function copy_term( $term, $target, $taxonomy ) {
self::$copying_term = true;
$document = $this->get_group( 'term', $term->term_id );
$cp_lang = $this->pllm->get_language( $target );
$cp_term = (array) $term;
if ( class_exists( 'PLL_Share_Term_Slug', true ) ) {
remove_action( 'create_term', array( PLL()->filters_term, 'save_term' ), 999, 3 );
remove_action( 'edit_term', array( PLL()->filters_term, 'save_term' ), 999, 3 );
remove_action( 'pre_post_update', array( PLL()->filters_term, 'pre_post_update' ) );
remove_filter( 'pre_term_name', array( PLL()->filters_term, 'pre_term_name' ) );
remove_filter( 'pre_term_slug', array( PLL()->filters_term, 'pre_term_slug' ), 10, 2 );
add_action( 'pre_post_update', array( PLL()->share_term_slug, 'pre_post_update' ) );
add_filter( 'pre_term_name', array( PLL()->share_term_slug, 'pre_term_name' ) );
add_filter( 'pre_term_slug', array( PLL()->share_term_slug, 'pre_term_slug' ), 10, 2 );
add_action( 'create_term', array( PLL()->share_term_slug, 'save_term' ), 1, 3 );
add_action( 'edit_term', array( PLL()->share_term_slug, 'save_term' ), 1, 3 );
$_POST['term_lang_choice'] = $cp_lang->slug;
} else {
if ( isset( $cp_term['slug'] ) && term_exists( $cp_term['slug'] ) ) {
$cp_term['slug'] .= '-' . $cp_lang->slug;
}
}
$new_term = wp_insert_term( $cp_term['name'], $taxonomy, $cp_term );
if ( ! is_wp_error( $new_term ) ) {
PLL()->model->term->set_language( $new_term['term_id'], $cp_lang );
wp_set_object_terms( $new_term['term_id'], $document->term_id, 'term_translations' );
$document->desc_array[ $target ] = $new_term['term_id'];
$document->save();
}
self::$copying_term = false;
}
private function format_patch_params( $params, $profile, $source_lang, $translations ) {
$params['translation_locale_code'] = array();
$params['translation_workflow_id'] = array();
$requested_locales = isset($translations) && is_array($translations) ? array_keys($translations) : array();
foreach ( $this->pllm->get_languages_list() as $lang ) {
if ( $lang->lingotek_locale == $source_lang->lingotek_locale
|| ( isset($translations[$lang->locale]) && $translations[$lang->locale] === 'locked' )
|| !in_array($lang->locale, $requested_locales) //This ensures that only previously requested locales get included in the patch request
|| ( isset( $profile['targets'][ $lang->slug ] ) && 'disabled' === $profile['targets'][ $lang->slug ] ) ) {
continue;
}
$params['translation_locale_code'][] = $lang->lingotek_locale;
if ( isset( $profile['custom']['workflow_id'][ $lang->slug ], $profile['targets'][ $lang->lingotek_locale ] ) ) {
$params['translation_workflow_id'][] = $profile['custom']['workflow_id'][ $lang->slug ];
} elseif ( ! isset( $profile['targets'][ $lang->lingotek_locale ] ) && isset( $profile['workflow_id'] ) && $profile['workflow_id'] !== 'project-default' ) {
// Target is not using a custom workflow so we use the default workflow.
$params['translation_workflow_id'][] = $profile['workflow_id'];
}
}
if ( empty( $params['translation_workflow_id'] ) ) {
unset( $params['translation_workflow_id'] );
}
return $params;
}
/**
* uploads a new post to Lingotek TMS and requests the targets specified
*
* @since 0.1
*
* @param int $post_id
* @return boolean|string false if post failed to upload
*/
public function upload_post( $post_id ) {
$post = get_post( $post_id );
$language = PLL()->model->post->get_language( $post_id );
$profile = self::get_profile( $post->post_type, $language, $post_id );
if ( 'disabled' === $profile['profile'] || empty( $post ) || empty( $language ) ) {
return;
}
// Returns type string or boolean
$document_id = self::get_document_id( 'post', $post_id );
// Slug can't be empty or duplicated, so we prefix `disassociated` to show the document id is no longer associated with this post
if ( is_string( $document_id ) && $this->is_disassociated_deleted_cancelled_or_archived( $document_id ) ) {
$document_id = false;
}
$content = null;
// If we already uploaded this doc, check if it changed and prevent the upload if it didn't.
$client = new Lingotek_API();
if ( $document_id ) {
$content = Lingotek_Group_Post::get_content( $post );
$hash_terms = wp_get_object_terms( $post->ID, 'lingotek_hash' );
$hash_term = array_pop( $hash_terms );
$new_hash = md5( $content );
if ( ! empty( $hash_term ) ) {
// If the document hasn't changed and it exists in TMS, don't upload
$status = $client->get_document_status( $document_id );
if ( $hash_term->description === $new_hash && 'current' === $status ) {
return;
}
}
}
$document = $this->get_group( 'post', $post_id );
// Customized workflows have the option to do any sort of pre-processing before a document
// is uploaded to lingotek.
if ( $document ) {
$document->pre_upload_to_lingotek( $post_id, $post->post_type, $language, 'post' );
}
$external_url = get_page_link( $post_id );
if ( ! $content ) {
$content = Lingotek_Group_Post::get_content( $post );
}
$params = $this->build_params( $external_url, $post->post_title, $post->post_type, $content, $language, $profile, $post_id, $wp_target_locales );
$filter_ids = $this->get_filter_ids( $post->post_type, $language, $post_id );
$params = array_merge( $params, $filter_ids );
if ( $document && in_array( $document->status, array( 'edited', 'importing', 'current' ) ) && $document_id ) {
$response = $document->patch( $this->format_patch_params( $params, $profile, $language, $document->translations ) );
if ( $response ) {
// Only save the hash if the patch function is successful
// Re-establish hash relation if needed
if ( ! isset( $hash_term->term_id ) ) {
$hash_terms = wp_set_post_terms( $post->ID, 'lingotek_hash_' . $post->ID, 'lingotek_hash' );
$hash_term_id = array_pop( $hash_terms );
} else {
$hash_term_id = $hash_term->term_id;
}
wp_update_term( $hash_term_id, 'lingotek_hash', array( 'description' => $new_hash ) );
}
return $response;
} elseif ( ! Lingotek_Group::$creating_translation && ! self::$copying_post && ( ! $document || in_array( $document->status, array( 'deleted', 'disassociated', 'archived', 'cancelled', null ), true ) ) ) {
$document_id = $client->upload_document( $params, $post->ID );
if ( $document_id ) {
Lingotek_Group_Post::create( $post->ID, $language, $document_id );
$document = $this->get_group_by_id( $document_id );
if ( isset( $wp_target_locales ) ) {
foreach ( $wp_target_locales as $locale ) {
$language = PLL()->model->get_language( $locale );
$document->translations[ $language->locale ] = 'pending';
}
}
$document->save();
// If a translation profile has targets set to copy then copy them
$targets_to_copy = $this->targets_to_be_copied( $profile );
$upload = self::get_profile_option( 'upload', $post->post_type, $language, false, $post_id );
if ( ! empty( $targets_to_copy ) && $upload === 'automatic' ) {
foreach ( $targets_to_copy as $target ) {
$this->copy_post( $post, $target );
}
}
return $document_id;
}
return false;
}//end if
}
/**
* uploads a new term to Lingotek TMS
*
* @since 0.2
*
* @param int $term_id
* @param string $taxonomy
*/
public function upload_term( $term_id, $taxonomy ) {
$term = get_term( $term_id, $taxonomy );
$language = PLL()->model->term->get_language( $term_id );
if ( empty( $term ) || empty( $language ) ) {
return;
}
$profile = self::get_profile( $taxonomy, $language );
if ( 'disabled' === $profile['profile'] ) {
return;
}
/**
* Customized workflows have the option to do any sort of pre-processing before a document is uploaded to lingotek.
*/
$document = $this->get_group( 'term', $term_id );
if ( $document ) {
$document->pre_upload_to_lingotek( $term_id, $taxonomy, $language, 'term' );
}
$client = new Lingotek_API();
$content = Lingotek_Group_Term::get_content( $term );
$params = $this->build_params( get_term_link( $term_id, $taxonomy ), $term->name, $taxonomy, $content, $language, $profile, $term_id, $wp_target_locales );
$filter_ids = $this->get_filter_ids( $taxonomy, $language, $term_id );
$params = array_merge( $params, $filter_ids );
if ( ( $document = $this->get_group( 'term', $term_id ) ) && 'edited' === $document->status ) {
$document->patch( $this->format_patch_params( $params, $profile, $language, $document->translations ), $term->name, $term );
} elseif ( ! Lingotek_Group::$creating_translation && ! self::$copying_term ) {
$document_id = $client->upload_document( $params, $term_id );
if ( $document_id ) {
Lingotek_Group_Term::create( $term_id, $taxonomy, $language, $document_id );
$document = $this->get_group_by_id( $document_id );
foreach ( $wp_target_locales as $locale ) {
$document->translations[ $locale ] = 'pending';
}
$document->save();
// If a translation profile has targets set to copy then copy them
$targets_to_copy = $this->targets_to_be_copied( $profile );
if ( ! empty( $targets_to_copy ) && 'automatic' === $profile['upload'] ) {
foreach ( $targets_to_copy as $target ) {
$this->copy_term( $term, $target, $taxonomy );
}
}
}
}//end if
}
/**
* uploads a strings group to Lingotek TMS
*
* @since 0.2
*
* @param string $group
*/
public function upload_strings( $group ) {
$type = 'string';
$language = $this->pllm->get_language( $this->pllm->options['default_lang'] );
$profile = self::get_profile( $type, $language );
if ( 'disabled' === $profile['profile'] ) {
return;
}
if ( is_numeric( $group ) ) {
$strings = self::get_strings();
$group = $strings[ $group ]['context'];
}
// check that we have a valid string group
if ( ! in_array( $group, wp_list_pluck( self::get_strings(), 'context' ) ) ) {
return;
}
$client = new Lingotek_API();
$content = Lingotek_Group_String::get_content( $group );
$params = $this->build_params( '', $group, $type, $content, $language, $profile, null );
$filter_ids = $this->get_filter_ids( $type, $language, null );
$params = array_merge( $params, $filter_ids );
if ( ( $document = $this->get_group( $type, $group ) ) && 'edited' === $document->status ) {
$document->patch( $this->format_patch_params( $params, $profile, $language, $document->translations ) );
} else {
$document_id = $client->upload_document( $params, $group );
if ( $document_id ) {
Lingotek_Group_String::create( $group, $language, $document_id );
}
}
}
/**
* checks if the document can be upload to Lingotek
*
* @since 0.1
*
* @param string $type either 'post' or 'term'
* @param int $object_id post id or term id
* @return bool
*/
public function can_upload( $type, $object_id ) {
// FIXME should I check for disabled profile here?
$document = $this->get_group( $type, $object_id );
if ( $document && 'failed' === $document->status ) {
return false;
}
switch ( $type ) {
case 'string':
if ( empty( $document ) ) {
return true;
}
// Check if source strings have not been modified.
elseif ( $document->md5 !== md5( Lingotek_Group_String::get_content( $object_id ) ) ) {
$document->source_edited();
return true;
}
return false;
case 'post':
$language = PLL()->model->post->get_language( $object_id );
$allow_status = $document && 'edited' === $document->status ? true : ( $document && 'cancelled' === $document->status ? true : false );
return ! empty( $language ) && ( empty( $document ) ||
( isset( $document ) && $allow_status && $document->source == $object_id ) );
case 'term':
// first check that a language is associated to the object
$language = PLL()->model->term->get_language( $object_id );
// FIXME how to get profile to check if disabled?
return ! empty( $language ) && ( empty( $document ) ||
// Specific for terms as document is never empty.
( empty( $document->translations ) && empty( $document->source ) ) ||
( isset( $document ) && 'edited' == $document->status && $document->source == $object_id ) );
}//end switch
}
/**
* deletes a post
*
* @since 0.1
*
* @param int $object_id post id
*/
public function delete_post( $object_id ) {
if ( $document = $this->get_group( 'post', $object_id ) ) {
$client = new Lingotek_API();
if ( $document->source == $object_id ) {
$client->cancel_document( $document->document_id, $object_id );
} else {
PLL()->model->post->delete_translation( $object_id );
$lang = PLL()->model->post->get_language( $object_id );
$client->cancel_translation( $document->document_id, $lang->lingotek_locale, $object_id );
}
}
}
public function cancel_post( $object_id ) {
if ( $document = $this->get_group( 'post', $object_id ) ) {
$client = new Lingotek_API();
if ( $document->source == $object_id ) {
$client->cancel_document( $document->document_id, $object_id );
} else {
$lang = PLL()->model->post->get_language( $object_id );
$locale = $lang->locale;
if ( isset( $document->desc_array['lingotek']['translations'][ $locale ] ) ) {
$document->desc_array['lingotek']['translations'][ $locale ] = 'cancelled';
}
$document->save();
$client->cancel_translation( $document->document_id, $lang->lingotek_locale, $object_id );
}
}
}
/**
* deletes a term
*
* @since 0.2
*
* @param int $object_id term id
*/
public function delete_term( $object_id ) {
if ( $document = $this->get_group( 'term', $object_id ) ) {
$client = new Lingotek_API();
if ( $document->source == $object_id ) {
$client->cancel_document( $document->document_id, $object_id );
} else {
$lang = PLL()->model->term->get_language( $object_id );
PLL()->model->term->delete_language( $object_id );
PLL()->model->term->delete_translation( $object_id );
$client->cancel_translation( $document->document_id, $lang->lingotek_locale, $object_id );
}
}
}
public function cancel_term( $object_id ) {
if ( $document = $this->get_group( 'term', $object_id ) ) {
$client = new Lingotek_API();
if ( $document->source == $object_id ) {
$client->cancel_document( $document->document_id, $object_id );
} else {
$lang = PLL()->model->term->get_language( $object_id );
PLL()->model->term->cancel_translation( $document->document_id, $lang->lingotek_locale );
PLL()->model->term->delete_translation( $object_id );
$client->cancel_translation( $document->document_id, $lang->lingotek_locale, $object_id );
}
}
}
/**
* counts the number of targets per language
*
* @since 0.2
*
* @param array $groups Array of serialized 'post_translations' or 'term_translations' description.
* @return array number of targets per language
*/
protected function get_target_count( $groups ) {
$targets = array_fill_keys( $this->pllm->get_languages_list( array( 'fields' => 'slug' ) ), 0 );
foreach ( $groups as $group ) {
$group = unserialize( $group );
if ( isset( $group['lingotek']['translations'] ) ) {
foreach ( $group['lingotek']['translations'] as $locale => $status ) {
$language = $this->pllm->get_language( $locale );
if ( 'current' === $status && $language ) {
$targets[ $language->slug ]++;
}
}
}
}
return $targets;
}
/**
* counts the number of sources and targets per language for a certain post type
*
* @since 0.2
*
* @param string $post_type
* @return array
*/
public function count_posts( $post_type ) {
global $wpdb;
static $r = array();
if ( ! empty( $r[ $post_type ] ) ) {
return $r[ $post_type ];
}
if ( ! post_type_exists( $post_type ) ) {
return;
}
// gets all translations groups for the post type
$groups = $wpdb->get_col(
$wpdb->prepare(
"
SELECT DISTINCT tt.description FROM $wpdb->term_taxonomy AS tt
INNER JOIN $wpdb->term_relationships AS tr ON tt.term_taxonomy_id = tr.term_taxonomy_id
INNER JOIN $wpdb->posts AS p ON p.ID = tr.object_id
WHERE tt.taxonomy = %s
AND p.post_type = %s
AND p.post_status NOT IN ('trash', 'auto-draft')",
'post_translations',
$post_type
)
);
$targets = $this->get_target_count( $groups );
$group_ids = array();
$disabled = array();
foreach ( $this->pllm->get_languages_list() as $language ) {
// counts all the posts in one language
$n = $wpdb->get_var(
$wpdb->prepare(
"
SELECT COUNT(*) FROM $wpdb->term_relationships AS tr
INNER JOIN $wpdb->posts AS p ON p.ID = tr.object_id
WHERE tr.term_taxonomy_id = %d
AND p.post_type = %s
AND p.post_status NOT IN ('trash', 'auto-draft')",
$language->term_taxonomy_id,
$post_type
)
);
$objects = $wpdb->get_col(
$wpdb->prepare(
"
SELECT object_id FROM $wpdb->term_relationships AS tr
INNER JOIN $wpdb->posts AS p ON p.ID = tr.object_id
WHERE tr.term_taxonomy_id = %d
AND p.post_type = %s
AND p.post_status NOT IN ('trash', 'auto-draft')",
$language->term_taxonomy_id,
$post_type
)
);
foreach ( $groups as $group ) {
$group = unserialize( $group );
if ( array_key_exists( $language->slug, $group ) ) {
$group_ids[] = $group[ $language->slug ];
}
}
$count = 0;
foreach ( $objects as $object ) {
$id = $object;
if ( ! in_array( $id, $group_ids, true ) ) {
$profile = self::get_profile( $post_type, $language, $id );
if ( 'disabled' === $profile['profile'] && in_array( $id, $objects, true ) ) {
++$count;
}
}
}
$disabled[ $language->slug ] = $count;
// if a post is not a target, then it is source
$sources[ $language->slug ] = $n - $targets[ $language->slug ];
// $sources[$language->slug] -= $disabled[$language->slug];
}//end foreach
// untranslated posts have no associated translation group in DB
// so let's count them indirectly
// counts the number of translated posts
$n_translated = $wpdb->get_var(
$wpdb->prepare(
"
SELECT COUNT(*) FROM $wpdb->term_relationships AS tr
INNER JOIN $wpdb->posts AS p ON p.ID = tr.object_id
INNER JOIN $wpdb->term_taxonomy AS tt ON tt.term_taxonomy_id = tr.term_taxonomy_id
WHERE tt.taxonomy = %s
AND p.post_type = %s
AND p.post_status NOT IN ('trash', 'auto-draft')",
'post_translations',
$post_type
)
);
// untranslated = total - translated
// total of posts translations groups = untranslated + number of translation groups stored in DB
$count_posts = (array) wp_count_posts( $post_type );
// Don't count trash and auto-draft.
unset( $count_posts['trash'], $count_posts['auto-draft'] );
$total = array_sum( $count_posts ) - $n_translated + count( $groups );
return $r[ $post_type ] = compact( 'sources', 'targets', 'total' );
}
/**
* counts the number of sources and targets per language for a certain taxonomy
*
* @since 0.2
*
* @param string $taxonomy
* @return array
*/
public function count_terms( $taxonomy ) {
global $wpdb;
static $r = array();
if ( ! empty( $r[ $taxonomy ] ) ) {
return $r[ $taxonomy ];
}
if ( ! taxonomy_exists( $taxonomy ) ) {
return;
}
// gets all translations groups for the taxonomy
$groups = $wpdb->get_col(
$wpdb->prepare(
"
SELECT DISTINCT tt1.description FROM $wpdb->term_taxonomy AS tt1
INNER JOIN $wpdb->term_relationships AS tr ON tt1.term_taxonomy_id = tr.term_taxonomy_id
INNER JOIN $wpdb->term_taxonomy AS tt2 ON tt2.term_id = tr.object_id
WHERE tt1.taxonomy = %s
AND tt2.taxonomy = %s",
'term_translations',
$taxonomy
)
);
$targets = $this->get_target_count( $groups );
$group_ids = array();
$disabled = array();
foreach ( $this->pllm->get_languages_list() as $language ) {
// counts all the terms in one language
$n = $wpdb->get_var(
$wpdb->prepare(
"
SELECT COUNT(*) FROM $wpdb->term_relationships AS tr
INNER JOIN $wpdb->term_taxonomy AS tt ON tt.term_id = tr.object_id
WHERE tr.term_taxonomy_id = %d
AND tt.taxonomy = %s",
$language->tl_term_taxonomy_id,
$taxonomy
)
);
$objects = $wpdb->get_col(
$wpdb->prepare(
"
SELECT object_id FROM $wpdb->term_relationships AS tr
INNER JOIN $wpdb->term_taxonomy AS tt ON tt.term_id = tr.object_id
WHERE tr.term_taxonomy_id = %d
AND tt.taxonomy = %s",
$language->tl_term_taxonomy_id,
$taxonomy
)
);
$count = 0;
foreach ( $groups as $group ) {
$group = unserialize( $group );
if ( array_key_exists( $language->slug, $group ) ) {
$group_ids[] = $group[ $language->slug ];
$profile = self::get_profile( $taxonomy, $language, $group[ $language->slug ] );
if ( 'disabled' === $profile['profile'] && ! isset( $group['lingotek'] ) ) {
++$count;
}
}
}
$disabled[ $language->slug ] = $count;
// if a term is not a target, then it is a source
$sources[ $language->slug ] = $n - $targets[ $language->slug ];
// $sources[$language->slug] -= $disabled[$language->slug];
}//end foreach
$total = count( $groups );
// default categories are created by Polylang in all languages
// don't count them as sources if they are not associated to the TMS
if ( 'category' === $taxonomy ) {
$term_id = get_option( 'default_category' );
$group = $this->get_group( 'term', $term_id );
foreach ( $this->pllm->get_languages_list() as $language ) {
if ( empty( $group->source ) || ( $group->get_source_language()->slug !== $language->slug && empty( $group->translations[ $language->locale ] ) ) ) {
if ( $language->slug !== $this->pllm->options['default_lang'] ) {
$sources[ $language->slug ]--;
}
}
}
// Remove category targets from being counted until they are downloaded. Fixed target categories being counted as source languages.
foreach ( $groups as $group ) {
$group = unserialize( $group );
if ( isset( $group['lingotek']['translations'] ) ) {
foreach ( $group['lingotek']['translations'] as $locale => $status ) {
$language = $this->pllm->get_language( $locale );
if ( ( 'pending' === $status || 'ready' === $status ) && $language ) {
if ( $sources[ $language->slug ] > 0 ) {
$sources[ $language->slug ]--;
}
}
}
}
}
if ( 1 === count( $sources ) && $total !== $sources[ $this->pllm->options['default_lang'] ] ) {
$total = $sources[ $this->pllm->options['default_lang'] ];
}
}//end if
$r[ $taxonomy ] = compact( 'sources', 'targets', 'total' );
return $r[ $taxonomy ];
}
private function build_params( $external_url, $title, $type, $content, $language, $profile, $wp_id, &$wp_target_locales = array() ) {
$translation_workflow_id = self::get_profile_option( 'workflow_id', $type, $language, false, $wp_id );
if ( 'project-default' === $translation_workflow_id || false === $translation_workflow_id ) {
$translation_workflow_id = null;
}
$params = array(
'title' => $title,
'content' => $content,
'locale_code' => $language->lingotek_locale,
'project_id' => self::get_profile_option( 'project_id', $type, $language, false, $wp_id ),
'external_url' => $external_url,
);
$lingotek_metadata_keys = array(
'author_email',
'author_name',
'division',
'unit',
'campaign_id',
'channel',
'contact_email',
'contact_name',
'description',
'domain',
'style_id',
'purchase_order',
'reference_url',
'region',
'require_review',
);
foreach ( $lingotek_metadata_keys as $key ) {
if ( isset( $profile[ $key ] ) ) {
$params[ $key ] = $profile[ $key ];
}
}
if ( null !== $translation_workflow_id ) {
$params['translation_workflow_id'] = $translation_workflow_id;
}
// Get target locales to send up from profile
$target_locales = array();
if ( ! empty( $profile['target_locales'] ) ) {
if ( isset( $profile['target_locales'][ $language->slug ] ) ) {
unset( $profile['target_locales'][ $language->slug ] );
}
if ( isset( $profile['custom']['workflow_id'][ $language->slug ] ) ) {
unset( $profile['custom']['workflow_id'][ $language->slug ] );
}
$target_locales['translation_locale_code'] = array_values( $profile['target_locales'] );
$wp_target_locales = array_keys( $profile['target_locales'] );
// Add workflows
if ( ! empty( $profile['custom']['workflow_id'] ) ) {
$temp_workflow_ids = array();
$workflow_id = null;
foreach ( $wp_target_locales as $language_slug ) {
if ( isset( $profile['custom']['workflow_id'][ $language_slug ] ) ) {
$profile_override = $profile['custom']['workflow_id'][ $language_slug ];
$workflow_id = 'project-default' === $profile_override ? $translation_workflow_id : $profile_override;
} else {
$workflow_id = $translation_workflow_id;
}
if ( $workflow_id ) {
$temp_workflow_ids[] = $workflow_id;
}
}
$params['translation_workflow_id'] = $temp_workflow_ids;
}
} else {
// No targets being sent up to TMS, unset the workflow
unset( $params['translation_workflow_id'] );
}//end if
$params = array_merge( $params, $target_locales );
return $params;
}
/**
* Builds the array of parameters for reuploads by getting only the post id.
* Primarily for when handling 410 and 404 response codes
* Return empty array if profile is disabled, or post/language are empty
*
* @since 1.5.0
*
* @param integer $post_id
* @return array
*/
public function reupload_build_params( $post_id ) {
$post = get_post( $post_id );
$language = PLL()->model->post->get_language( $post_id );
$profile = self::get_profile( $post->post_type, $language, $post_id );
if ( 'disabled' === $profile['profile'] || empty( $post ) || empty( $language ) ) {
Lingotek_Logger::info(
'Document cannot be uploaded',
array(
'profile' => $profile['profile'],
'post is empty' => empty( $post ),
'language is empty' => empty( $language ),
)
);
return array();
}
$external_url = get_page_link( $post_id );
$content = Lingotek_Group_Post::get_content( $post );
return $this->build_params( $external_url, $post->post_title, $post->post_type, $content, $language, $profile, $post_id );
}
private function get_filter_ids( $type, $language, $wp_id ) {
$filter_ids = array();
if ( self::get_profile_option( 'primary_filter_id', $type, $language, false, $wp_id ) ) {
$filter_ids['fprm_id'] = self::get_profile_option( 'primary_filter_id', $type, $language, false, $wp_id );
}
if ( self::get_profile_option( 'secondary_filter_id', $type, $language, false, $wp_id ) ) {
$filter_ids['fprm_subfilter_id'] = self::get_profile_option( 'secondary_filter_id', $type, $language, false, $wp_id );
}
return $filter_ids;
}
/**
* Checks if a document id is disassociated, cancelled or archived.
*
* @param string $document_id
*
* @return bool
*/
protected function is_disassociated_deleted_cancelled_or_archived( $document_id ) {
return strpos( $document_id, 'disassociated_' ) === 0 ||
strpos( $document_id, 'deleted_' ) === 0 ||
strpos( $document_id, 'cancelled_' ) === 0 ||
strpos( $document_id, 'archived_' ) === 0;
}
}