PageRenderTime 32ms CodeModel.GetById 8ms RepoModel.GetById 1ms app.codeStats 0ms

/wp-content/plugins/sitepress-multilingual-cms/classes/translations/class-wpml-translations.php

https://bitbucket.org/RickCalder/mcc
PHP | 302 lines | 177 code | 41 blank | 84 comment | 24 complexity | a37e5c75e94484c093fda792f30704df MD5 | raw file
Possible License(s): MIT, Apache-2.0, GPL-3.0, BSD-3-Clause
  1. <?php
  2. /**
  3. * @author OnTheGo Systems
  4. */
  5. class WPML_Translations extends WPML_SP_User {
  6. /** @var bool */
  7. public $skip_empty = false;
  8. /** @var bool */
  9. public $all_statuses = false;
  10. /** @var bool */
  11. public $skip_cache = false;
  12. /** @var bool */
  13. public $skip_recursions = false;
  14. private $duplicated_by = array();
  15. private $mark_as_duplicate_meta_key = '_icl_lang_duplicate_of';
  16. private $wpml_cache;
  17. /**
  18. * WPML_Translations constructor.
  19. *
  20. * @param SitePress $sitepress
  21. * @param WPML_WP_Cache $wpml_cache
  22. */
  23. public function __construct( SitePress $sitepress, WPML_WP_Cache $wpml_cache = null ) {
  24. parent::__construct( $sitepress );
  25. $this->wpml_cache = $wpml_cache ? $wpml_cache : new WPML_WP_Cache( WPML_ELEMENT_TRANSLATIONS_CACHE_GROUP );
  26. }
  27. /**
  28. * @param $trid
  29. * @param $wpml_element_type
  30. *
  31. * @return array|bool|false|mixed
  32. */
  33. public function get_translations( $trid, $wpml_element_type ) {
  34. $cache_key_args = array_filter( array( $trid, $wpml_element_type, $this->skip_empty, $this->all_statuses, $this->skip_recursions ) );
  35. $cache_key = md5( wp_json_encode( $cache_key_args ) );
  36. $cache_found = false;
  37. $temp_elements = $this->wpml_cache->get( $cache_key, $cache_found );
  38. if ( ! $this->skip_cache && $cache_found ) {
  39. return $temp_elements;
  40. }
  41. $translations = array();
  42. $sql_parts = array(
  43. 'select' => array(),
  44. 'join' => array(),
  45. 'where' => array(),
  46. 'group_by' => array(),
  47. );
  48. if ( $trid ) {
  49. if ( $this->wpml_element_type_is_post( $wpml_element_type ) ) {
  50. $sql_parts = $this->get_sql_parts_for_post( $wpml_element_type, $sql_parts );
  51. } elseif ( $this->wpml_element_type_is_taxonomy( $wpml_element_type ) ) {
  52. $sql_parts = $this->get_sql_parts_for_taxonomy( $sql_parts );
  53. }
  54. $sql_parts['where'][] = $this->sitepress->get_wpdb()->prepare( ' AND t.trid=%d ', $trid );
  55. $select = implode( ' ', $sql_parts['select'] );
  56. $join = implode( ' ', $sql_parts['join'] );
  57. $where = implode( ' ', $sql_parts['where'] );
  58. $group_by = implode( ' ', $sql_parts['group_by'] );
  59. $query = "
  60. SELECT t.translation_id, t.language_code, t.element_id, t.source_language_code, t.element_type, NULLIF(t.source_language_code, '') IS NULL AS original
  61. {$select}
  62. FROM {$this->sitepress->get_wpdb()->prefix}icl_translations t
  63. {$join}
  64. WHERE 1 {$where}
  65. {$group_by}
  66. ";
  67. $results = $this->sitepress->get_wpdb()->get_results( $query );
  68. foreach ( $results as $translation ) {
  69. if ( $this->must_ignore_translation( $translation ) ) {
  70. continue;
  71. }
  72. $cached_object_key = $translation->element_id . '#' . $wpml_element_type . '#0#' . $translation->language_code;
  73. wp_cache_set( $cached_object_key, $cached_object_key, 'icl_object_id' );
  74. $translations[ $translation->language_code ] = $translation;
  75. }
  76. }
  77. if ( $translations ) {
  78. $this->wpml_cache->set( $cache_key, $translations );
  79. }
  80. return $translations;
  81. }
  82. public function link_elements( WPML_Translation_Element $source_translation_element, WPML_Translation_Element $target_translation_element, $target_language = null ) {
  83. if ( null !== $target_language ) {
  84. $this->set_language_code( $target_translation_element, $target_language );
  85. }
  86. $this->set_source_element( $target_translation_element, $source_translation_element );
  87. }
  88. public function set_source_element( WPML_Translation_Element $element, WPML_Translation_Element $source_element ) {
  89. $this->elements_type_matches( $element, $source_element );
  90. $this->sitepress->set_element_language_details( $element->get_element_id(), $element->get_wpml_element_type(), $source_element->get_trid(), $element->get_language_code(), $source_element->get_language_code() );
  91. $element->flush_cache();
  92. }
  93. private function elements_type_matches( $element1, $element2 ) {
  94. if ( get_class( $element1 ) !== get_class( $element2 ) ) {
  95. throw new UnexpectedValueException( '$source_element is not an instance of ' . get_class( $element1 ) . ': instance of ' . get_class( $element2 ) . ' received instead.' );
  96. }
  97. }
  98. /**
  99. * @param WPML_Translation_Element $element
  100. * @param string $language_code
  101. */
  102. public function set_language_code( WPML_Translation_Element $element, $language_code ) {
  103. $element_id = $element->get_element_id();
  104. $wpml_element_type = $element->get_wpml_element_type();
  105. $trid = $element->get_trid();
  106. $this->sitepress->set_element_language_details( $element_id, $wpml_element_type, $trid, $language_code );
  107. $element->flush_cache();
  108. }
  109. /**
  110. * @param WPML_Translation_Element $element
  111. * @param int $trid
  112. *
  113. * @throws \UnexpectedValueException
  114. */
  115. public function set_trid( WPML_Translation_Element $element, $trid ) {
  116. if ( ! $element->get_language_code() ) {
  117. throw new UnexpectedValueException( 'Element has no language information.' );
  118. }
  119. $this->sitepress->set_element_language_details( $element->get_element_id(), $element->get_wpml_element_type(), $trid, $element->get_language_code() );
  120. $element->flush_cache();
  121. }
  122. /**
  123. * @param WPML_Duplicable_Element|WPML_Translation_Element $duplicate
  124. * @param WPML_Duplicable_Element|WPML_Translation_Element $original
  125. *
  126. * @throws \UnexpectedValueException
  127. */
  128. public function make_duplicate_of( WPML_Duplicable_Element $duplicate, WPML_Duplicable_Element $original ) {
  129. $this->validate_duplicable_element( $duplicate );
  130. $this->validate_duplicable_element( $original, 'source' );
  131. $this->set_source_element( $duplicate, $original );
  132. update_post_meta( $duplicate->get_id(), $this->mark_as_duplicate_meta_key, $original->get_id() );
  133. $duplicate->flush_cache();
  134. $this->duplicated_by[ $duplicate->get_id() ] = array();
  135. }
  136. /**
  137. * @param WPML_Duplicable_Element|WPML_Translation_Element $element
  138. *
  139. * @return WPML_Post_Element
  140. * @throws \InvalidArgumentException
  141. */
  142. public function is_a_duplicate_of( WPML_Duplicable_Element $element ) {
  143. $this->validate_duplicable_element( $element );
  144. $duplicate_of = get_post_meta( $element->get_id(), $this->mark_as_duplicate_meta_key, true );
  145. if ( $duplicate_of ) {
  146. return new WPML_Post_Element( $duplicate_of, $this->sitepress );
  147. }
  148. return null;
  149. }
  150. /**
  151. * @param WPML_Duplicable_Element|WPML_Translation_Element $element
  152. *
  153. * @return array
  154. * @throws \UnexpectedValueException
  155. * @throws \InvalidArgumentException
  156. */
  157. public function is_duplicated_by( WPML_Duplicable_Element $element ) {
  158. $this->validate_duplicable_element( $element );
  159. $this->init_cache_for_element( $element );
  160. if ( ! $this->duplicated_by[ $element->get_id() ] ) {
  161. $this->duplicated_by[ $element->get_id() ] = array();
  162. $args = array(
  163. 'post_type' => $element->get_wp_element_type(),
  164. 'meta_query' => array(
  165. array(
  166. 'key' => $this->mark_as_duplicate_meta_key,
  167. 'value' => $element->get_id(),
  168. 'compare' => '=',
  169. ),
  170. ),
  171. );
  172. $query = new WP_Query( $args );
  173. $results = $query->get_posts();
  174. foreach ( $results as $post ) {
  175. $this->duplicated_by[ $element->get_id() ][] = new WPML_Post_Element( $post->ID, $this->sitepress );
  176. }
  177. }
  178. return $this->duplicated_by[ $element->get_id() ];
  179. }
  180. /**
  181. * @param WPML_Translation_Element $element
  182. * @param string $argument_name
  183. *
  184. * @throws \UnexpectedValueException
  185. */
  186. private function validate_duplicable_element( WPML_Translation_Element $element, $argument_name = 'element' ) {
  187. if ( ! ( $element instanceof WPML_Duplicable_Element ) ) {
  188. throw new UnexpectedValueException( sprintf( 'Argument %s does not implement `WPML_Duplicable_Element`.', $argument_name ) );
  189. }
  190. }
  191. /**
  192. * @param WPML_Translation_Element $element
  193. */
  194. private function init_cache_for_element( WPML_Translation_Element $element ) {
  195. if ( ! array_key_exists( $element->get_id(), $this->duplicated_by ) ) {
  196. $this->duplicated_by[ $element->get_id() ] = array();
  197. }
  198. }
  199. /**
  200. * @param $element_type
  201. * @param $sql_parts
  202. *
  203. * @return mixed
  204. */
  205. private function get_sql_parts_for_post( $element_type, $sql_parts ) {
  206. $sql_parts['select'][] = ', p.post_title, p.post_status';
  207. $sql_parts['join'][] = " LEFT JOIN {$this->sitepress->get_wpdb()->posts} p ON t.element_id=p.ID";
  208. if ( ! $this->all_statuses && 'post_attachment' !== $element_type && ! is_admin() ) {
  209. // the current user may not be the admin but may have read private post/page caps!
  210. if ( current_user_can( 'read_private_pages' ) || current_user_can( 'read_private_posts' ) ) {
  211. $sql_parts['where'][] = " AND (p.post_status IN ('publish', 'draft', 'private', 'pending' ))";
  212. } else {
  213. $sql_parts['where'][] = ' AND (';
  214. $sql_parts['where'][] = "p.post_status = 'publish' ";
  215. if ( $uid = $this->sitepress->get_current_user()->ID ) {
  216. $sql_parts['where'][] = $this->sitepress->get_wpdb()->prepare( " OR (post_status in ('draft', 'private', 'pending') AND post_author = %d)", $uid );
  217. }
  218. $sql_parts['where'][] = ') ';
  219. }
  220. }
  221. return $sql_parts;
  222. }
  223. /**
  224. * @param $sql_parts
  225. *
  226. * @return mixed
  227. */
  228. private function get_sql_parts_for_taxonomy( $sql_parts ) {
  229. $sql_parts['select'][] = ', tm.name, tm.term_id, COUNT(tr.object_id) AS instances';
  230. $sql_parts['join'][] = " LEFT JOIN {$this->sitepress->get_wpdb()->term_taxonomy} tt ON t.element_id=tt.term_taxonomy_id
  231. LEFT JOIN {$this->sitepress->get_wpdb()->terms} tm ON tt.term_id = tm.term_id
  232. LEFT JOIN {$this->sitepress->get_wpdb()->term_relationships} tr ON tr.term_taxonomy_id=tt.term_taxonomy_id
  233. ";
  234. $sql_parts['group_by'][] = 'GROUP BY tm.term_id';
  235. return $sql_parts;
  236. }
  237. /**
  238. * @param stdClass $translation
  239. *
  240. * @return bool
  241. */
  242. private function must_ignore_translation( $translation ) {
  243. return $this->wpml_element_type_is_taxonomy( $translation->element_type ) && $this->skip_empty && $translation->instances === 0 && ( ! $this->skip_recursions && ! _icl_tax_has_objects_recursive( $translation->element_id ) );
  244. }
  245. /**
  246. * @param string $wpml_element_type
  247. *
  248. * @return int
  249. */
  250. private function wpml_element_type_is_taxonomy( $wpml_element_type ) {
  251. return preg_match( '#^tax_(.+)$#', $wpml_element_type );
  252. }
  253. /**
  254. * @param string $wpml_element_type
  255. *
  256. * @return bool
  257. */
  258. private function wpml_element_type_is_post( $wpml_element_type ) {
  259. return 0 === strpos( $wpml_element_type, 'post_' );
  260. }
  261. }