first commit
This commit is contained in:
@@ -0,0 +1,290 @@
|
||||
<?php
|
||||
|
||||
use WPML\API\Sanitize;
|
||||
|
||||
/**
|
||||
* Class WPML_Admin_Post_Actions
|
||||
*
|
||||
* @package wpml-core
|
||||
* @subpackage post-translation
|
||||
*/
|
||||
class WPML_Admin_Post_Actions extends WPML_Post_Translation {
|
||||
|
||||
const DUPLICATE_MEDIA_META_KEY = '_wpml_media_duplicate';
|
||||
const DUPLICATE_FEATURED_META_KEY = '_wpml_media_featured';
|
||||
const DUPLICATE_MEDIA_GLOBAL_KEY = 'duplicate_media';
|
||||
const DUPLICATE_FEATURED_GLOBAL_KEY = 'duplicate_media';
|
||||
|
||||
private $http_referer;
|
||||
|
||||
public function init() {
|
||||
parent::init ();
|
||||
if ( $this->is_setup_complete() ) {
|
||||
add_action ( 'delete_post', array( $this, 'delete_post_actions' ) );
|
||||
add_action ( 'wp_trash_post', array( $this, 'trashed_post_actions' ) );
|
||||
add_action ( 'untrashed_post', array( $this, 'untrashed_post_actions' ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $post_id
|
||||
* @param string $post_status
|
||||
*
|
||||
* @return null|int
|
||||
*/
|
||||
function get_save_post_trid( $post_id, $post_status ) {
|
||||
$trid = $this->get_element_trid( $post_id );
|
||||
|
||||
if ( ! ( $this->is_inner_post_insertion() && $this->is_editing_different_post( $post_id ) ) ) {
|
||||
$trid = $trid ? $trid : filter_var( isset( $_POST['icl_trid'] ) ? $_POST['icl_trid'] : '', FILTER_SANITIZE_NUMBER_INT );
|
||||
$trid = $trid ? $trid : filter_var( isset( $_GET['trid'] ) ? $_GET['trid'] : '', FILTER_SANITIZE_NUMBER_INT );
|
||||
$trid = $trid ? $trid : $this->get_trid_from_referer();
|
||||
}
|
||||
|
||||
$trid = apply_filters( 'wpml_save_post_trid_value', $trid, $post_status );
|
||||
|
||||
return $trid;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $post_id
|
||||
* @param WP_Post $post
|
||||
*/
|
||||
public function save_post_actions( $post_id, $post ) {
|
||||
global $sitepress;
|
||||
|
||||
$this->defer_term_counting();
|
||||
if ( ! $post ) {
|
||||
$post = get_post( $post_id );
|
||||
}
|
||||
|
||||
// exceptions
|
||||
$http_referer = $this->get_http_referer();
|
||||
if ( ! $this->has_save_post_action( $post ) && ! $http_referer->is_rest_request_called_from_post_edit_page() ) {
|
||||
return;
|
||||
}
|
||||
if ( WPML_WordPress_Actions::is_bulk_trash( $post_id ) ||
|
||||
WPML_WordPress_Actions::is_bulk_untrash( $post_id ) ||
|
||||
$this->has_invalid_language_details_on_heartbeat()
|
||||
) {
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$default_language = $sitepress->get_default_language();
|
||||
$post_vars = $this->get_post_vars( $post );
|
||||
|
||||
if ( isset( $post_vars['action'] ) && $post_vars['action'] === 'post-quickpress-publish' ) {
|
||||
$language_code = $default_language;
|
||||
} else {
|
||||
if( isset( $post_vars['post_ID'] ) ){
|
||||
$post_id = $post_vars['post_ID'];
|
||||
}
|
||||
$language_code = $this->get_save_post_lang( $post_id, $sitepress );
|
||||
}
|
||||
|
||||
if ( $this->is_inline_action( $post_vars ) && ! ( $language_code = $this->get_element_lang_code(
|
||||
$post_id
|
||||
) )
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( isset( $post_vars['icl_translation_of'] ) && is_numeric( $post_vars['icl_translation_of'] ) ) {
|
||||
$translation_of_data_prepared = $this->wpdb->prepare(
|
||||
"SELECT trid, language_code
|
||||
FROM {$this->wpdb->prefix}icl_translations
|
||||
WHERE element_id=%d
|
||||
AND element_type=%s
|
||||
LIMIT 1",
|
||||
$post_vars['icl_translation_of'],
|
||||
'post_' . $post->post_type
|
||||
);
|
||||
list( $trid, $source_language ) = $this->wpdb->get_row( $translation_of_data_prepared, 'ARRAY_N' );
|
||||
}
|
||||
|
||||
if ( isset( $post_vars['icl_translation_of'] ) && $post_vars['icl_translation_of'] == 'none' ) {
|
||||
$trid = null;
|
||||
$source_language = $language_code;
|
||||
} else {
|
||||
$trid = isset( $trid ) && $trid ? $trid : $this->get_save_post_trid( $post_id, $post->post_status );
|
||||
// after getting the right trid set the source language from it by referring to the root translation
|
||||
// of this trid, in case no proper source language has been set yet
|
||||
$source_language = isset( $source_language )
|
||||
? $source_language : $this->get_save_post_source_lang( $trid, $language_code, $default_language );
|
||||
}
|
||||
if ( isset( $post_vars['icl_tn_note'] ) ) {
|
||||
update_post_meta( $post_id, '_icl_translator_note', $post_vars['icl_tn_note'] );
|
||||
}
|
||||
|
||||
$this->after_save_post( $trid, $post_vars, $language_code, $source_language );
|
||||
|
||||
if ( 'attachment' !== $post->post_type ) {
|
||||
$this->save_media_options( $post_id, $source_language );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $post_id
|
||||
* @param string|null $source_language
|
||||
*/
|
||||
private function save_media_options( $post_id, $source_language ) {
|
||||
|
||||
if ( $this->has_post_media_options_metabox() ) {
|
||||
$original_post_id = isset( $_POST['icl_translation_of'] )
|
||||
? filter_var( $_POST['icl_translation_of'], FILTER_SANITIZE_NUMBER_INT ) : $post_id;
|
||||
$duplicate_media = isset( $_POST['wpml_duplicate_media'] )
|
||||
? filter_var( $_POST['wpml_duplicate_media'], FILTER_SANITIZE_NUMBER_INT ) : false;
|
||||
$duplicate_featured = isset( $_POST['wpml_duplicate_featured'] )
|
||||
? filter_var( $_POST['wpml_duplicate_featured'], FILTER_SANITIZE_NUMBER_INT ) : false;
|
||||
|
||||
update_post_meta( $original_post_id, self::DUPLICATE_MEDIA_META_KEY, (int) $duplicate_media );
|
||||
update_post_meta( $original_post_id, self::DUPLICATE_FEATURED_META_KEY, (int) $duplicate_featured );
|
||||
} else {
|
||||
$this->sync_media_options_with_original_or_global_settings( $post_id, $source_language );
|
||||
}
|
||||
}
|
||||
|
||||
private function has_post_media_options_metabox() {
|
||||
return array_key_exists( WPML_Meta_Boxes_Post_Edit_HTML::FLAG_HAS_MEDIA_OPTIONS, $_POST );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $post_id
|
||||
* @param string|null $source_language
|
||||
*/
|
||||
private function sync_media_options_with_original_or_global_settings( $post_id, $source_language ) {
|
||||
global $sitepress;
|
||||
|
||||
$source_post_id = $sitepress->get_object_id( $post_id, get_post_type( $post_id ), false, $source_language );
|
||||
$is_translation = $source_post_id && $source_post_id !== $post_id;
|
||||
|
||||
foreach (
|
||||
array(
|
||||
self::DUPLICATE_FEATURED_META_KEY => self::DUPLICATE_FEATURED_GLOBAL_KEY,
|
||||
self::DUPLICATE_MEDIA_META_KEY => self::DUPLICATE_MEDIA_GLOBAL_KEY,
|
||||
) as $meta_key => $global_key
|
||||
) {
|
||||
|
||||
$source_value = get_post_meta( $source_post_id, $meta_key, true );
|
||||
|
||||
if ( '' === $source_value ) {
|
||||
// fallback to global setting
|
||||
$media_options = get_option( '_wpml_media', array() );
|
||||
|
||||
if ( isset( $media_options['new_content_settings'][ $global_key ] ) ) {
|
||||
$source_value = (int) $media_options['new_content_settings'][ $global_key ];
|
||||
|
||||
if ( $source_post_id ) {
|
||||
update_post_meta( $source_post_id, $meta_key, $source_value );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( '' !== $source_value && $is_translation ) {
|
||||
update_post_meta( $post_id, $meta_key, $source_value );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private function has_invalid_language_details_on_heartbeat() {
|
||||
if ( ! WPML_WordPress_Actions::is_heartbeat() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( isset( $_POST['data']['icl_post_language'], $_POST['data']['icl_trid'] ) ) {
|
||||
$_POST['icl_post_language'] = Sanitize::string( $_POST['data']['icl_post_language'] );
|
||||
$_POST['icl_trid'] = filter_var( $_POST['data']['icl_trid'], FILTER_SANITIZE_NUMBER_INT );
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param integer $post_id
|
||||
* @param SitePress $sitepress
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
public function get_save_post_lang( $post_id, $sitepress ) {
|
||||
$language_code = null;
|
||||
if ( isset( $_POST['post_ID'] ) && (int) $_POST['post_ID'] === (int) $post_id ) {
|
||||
$language_code = filter_var(
|
||||
( isset( $_POST['icl_post_language'] ) ? $_POST['icl_post_language'] : '' ),
|
||||
FILTER_SANITIZE_FULL_SPECIAL_CHARS );
|
||||
}
|
||||
$language_code = $language_code
|
||||
? $language_code
|
||||
: filter_input(
|
||||
INPUT_GET,
|
||||
'lang',
|
||||
FILTER_SANITIZE_FULL_SPECIAL_CHARS
|
||||
);
|
||||
|
||||
return $language_code ? $language_code : parent::get_save_post_lang( $post_id, $sitepress );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $post_vars
|
||||
* @return bool
|
||||
*/
|
||||
private function is_inline_action( $post_vars ) {
|
||||
|
||||
return isset( $post_vars[ 'action' ] )
|
||||
&& $post_vars[ 'action' ] == 'inline-save'
|
||||
|| isset( $_GET[ 'bulk_edit' ] )
|
||||
|| isset( $_GET[ 'doing_wp_cron' ] )
|
||||
|| ( isset( $_GET[ 'action' ] )
|
||||
&& $_GET[ 'action' ] == 'untrash' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $trid
|
||||
* @param string $language_code
|
||||
* @param string $default_language
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
protected function get_save_post_source_lang( $trid, $language_code, $default_language ) {
|
||||
$source_language = filter_input ( INPUT_GET, 'source_lang', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
|
||||
$source_language = $source_language ? $source_language : $this->get_source_language_from_referer();
|
||||
$source_language = $source_language ? $source_language : SitePress::get_source_language_by_trid ( $trid );
|
||||
$source_language = $source_language === 'all' ? $default_language : $source_language;
|
||||
$source_language = $source_language !== $language_code ? $source_language : null;
|
||||
|
||||
return $source_language;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the source_language $_GET parameter from the HTTP_REFERER
|
||||
*
|
||||
* @return string|bool
|
||||
*/
|
||||
private function get_source_language_from_referer() {
|
||||
if ( ! isset( $_SERVER['HTTP_REFERER'] ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$referer = $_SERVER['HTTP_REFERER'];
|
||||
$query = (string) wpml_parse_url( $referer, PHP_URL_QUERY );
|
||||
parse_str( $query, $query_parts );
|
||||
|
||||
return isset( $query_parts['source_lang'] ) ? $query_parts['source_lang'] : false;
|
||||
}
|
||||
|
||||
public function get_trid_from_referer() {
|
||||
$http_referer = $this->get_http_referer();
|
||||
return $http_referer->get_trid();
|
||||
}
|
||||
|
||||
protected function get_http_referer() {
|
||||
if ( ! $this->http_referer ) {
|
||||
$factory = new WPML_URL_HTTP_Referer_Factory();
|
||||
$this->http_referer = $factory->create();
|
||||
}
|
||||
|
||||
return $this->http_referer;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
class WPML_Comment_Duplication{
|
||||
|
||||
public function move_to_original($duplicate_of, $post_duplicates, $comment){
|
||||
global $wpml_post_translations, $wpdb;
|
||||
|
||||
$_orig_lang = $wpml_post_translations->get_element_lang_code ( $duplicate_of );
|
||||
$post_duplicates[ $_orig_lang ] = $duplicate_of;
|
||||
$original_parent = get_comment_meta ( $comment[ 'comment_parent' ], '_icl_duplicate_of', true );
|
||||
$wpdb->update (
|
||||
$wpdb->comments,
|
||||
array(
|
||||
'comment_post_ID' => $duplicate_of,
|
||||
'comment_parent' => $original_parent
|
||||
), array( 'comment_ID' => $comment['comment_ID'] ), array( '%d', '%d' ), array( '%d' )
|
||||
);
|
||||
wp_update_comment_count_now($duplicate_of);
|
||||
}
|
||||
|
||||
public function get_correct_parent($comment, $dup_id){
|
||||
global $wpdb;
|
||||
|
||||
$translated_parent = $wpdb->get_var (
|
||||
$wpdb->prepare (
|
||||
" SELECT cmb.comment_id
|
||||
FROM {$wpdb->commentmeta} cm
|
||||
JOIN {$wpdb->commentmeta} cmb
|
||||
ON ( cmb.meta_value = cm.meta_value
|
||||
AND cmb.meta_key = cm.meta_key)
|
||||
OR cm.comment_id = cmb.meta_value
|
||||
JOIN {$wpdb->comments} c
|
||||
ON c.comment_ID = cmb.comment_id
|
||||
WHERE cm.meta_key = '_icl_duplicate_of'
|
||||
AND ( cm.comment_id = %d OR cm.meta_value = %d )
|
||||
AND c.comment_post_ID = %d",
|
||||
$comment[ 'comment_parent' ],
|
||||
$comment[ 'comment_parent' ],
|
||||
$dup_id
|
||||
)
|
||||
);
|
||||
|
||||
return $translated_parent;
|
||||
}
|
||||
|
||||
public function insert_duplicated_comment( $comment, $dup_id, $original_cid ) {
|
||||
global $wpdb, $iclTranslationManagement;
|
||||
$dup_comment_id = $this->duplicate_exists ( $dup_id, $original_cid );
|
||||
remove_action ( 'wp_insert_comment', array( $iclTranslationManagement, 'duplication_insert_comment' ), 100 );
|
||||
|
||||
if ( $dup_comment_id ) {
|
||||
$comment[ 'comment_ID' ] = $dup_comment_id;
|
||||
wp_update_comment ( $comment );
|
||||
} else {
|
||||
$wpdb->insert ( $wpdb->comments, $comment );
|
||||
$dup_comment_id = $wpdb->insert_id;
|
||||
|
||||
add_action ( 'wp_insert_comment', array( $iclTranslationManagement, 'duplication_insert_comment' ), 100 );
|
||||
update_comment_meta ( $dup_comment_id, '_icl_duplicate_of', $original_cid );
|
||||
// comment meta
|
||||
$meta = $wpdb->get_results (
|
||||
$wpdb->prepare (
|
||||
"SELECT meta_key, meta_value FROM {$wpdb->commentmeta} WHERE comment_id=%d",
|
||||
$original_cid
|
||||
)
|
||||
);
|
||||
foreach ( $meta as $meta_row ) {
|
||||
$wpdb->insert (
|
||||
$wpdb->commentmeta,
|
||||
array(
|
||||
'comment_id' => $dup_comment_id,
|
||||
'meta_key' => $meta_row->meta_key,
|
||||
'meta_value' => $meta_row->meta_value
|
||||
), array( '%d', '%s', '%s' )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
wp_update_comment_count_now ( $dup_id );
|
||||
}
|
||||
|
||||
private function duplicate_exists( $dup_id, $original_cid ) {
|
||||
global $wpdb;
|
||||
|
||||
$duplicate = $wpdb->get_var (
|
||||
$wpdb->prepare (
|
||||
" SELECT comm.comment_ID
|
||||
FROM {$wpdb->comments} comm
|
||||
JOIN {$wpdb->commentmeta} cm
|
||||
ON comm.comment_ID = cm.comment_id
|
||||
WHERE comm.comment_post_ID = %d
|
||||
AND cm.meta_key = '_icl_duplicate_of'
|
||||
AND cm.meta_value = %d
|
||||
LIMIT 1",
|
||||
$dup_id,
|
||||
$original_cid
|
||||
)
|
||||
);
|
||||
|
||||
return $duplicate;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class WPML_Create_Post_Helper
|
||||
*
|
||||
* @since 3.2
|
||||
*/
|
||||
class WPML_Create_Post_Helper {
|
||||
|
||||
/** @var SitePress $sitepress */
|
||||
private $sitepress;
|
||||
|
||||
public function __construct( SitePress $sitepress ) {
|
||||
$this->sitepress = $sitepress;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $postarr will be escaped inside the method
|
||||
* @param string|null $lang
|
||||
* @param bool $wp_error
|
||||
*
|
||||
* @return int|WP_Error
|
||||
*/
|
||||
public function insert_post( array $postarr, $lang = null, $wp_error = false ) {
|
||||
$current_language = null;
|
||||
$postarr = $this->slash_and_preserve_tag_ids( $postarr );
|
||||
|
||||
if ( $lang ) {
|
||||
$current_language = $this->sitepress->get_current_language();
|
||||
$this->sitepress->switch_lang( $lang, false );
|
||||
}
|
||||
|
||||
if ( isset( $postarr['ID'] ) ) {
|
||||
$new_post_id = wp_update_post( $postarr, $wp_error );
|
||||
} else {
|
||||
add_filter( 'wp_insert_post_empty_content', array( $this, 'allow_empty_post' ), 10, 0 );
|
||||
$new_post_id = wp_insert_post( $postarr, $wp_error );
|
||||
remove_filter( 'wp_insert_post_empty_content', array( $this, 'allow_empty_post' ) );
|
||||
|
||||
}
|
||||
|
||||
if ( $current_language ) {
|
||||
$this->sitepress->switch_lang( $current_language, false );
|
||||
}
|
||||
|
||||
return $new_post_id;
|
||||
}
|
||||
|
||||
public function allow_empty_post() {
|
||||
return false; // We need to return false to indicate that the post is not empty
|
||||
}
|
||||
|
||||
/**
|
||||
* We need to make sure that tag IDs are not casted into strings.
|
||||
* This is a side effect of https://core.trac.wordpress.org/ticket/45121
|
||||
* (wp_update_post() can modify post tag) for which we have
|
||||
* a temporary fix in `\WPML_Page_Builders_Media_Shortcodes_Update::translate`.
|
||||
*
|
||||
* @param array $postarr
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function slash_and_preserve_tag_ids( array $postarr ) {
|
||||
if ( array_key_exists( 'tags_input', $postarr ) ) {
|
||||
$tagIds = array_filter( $postarr['tags_input'], 'is_int' );
|
||||
$postarr = wp_slash( $postarr );
|
||||
$postarr['tags_input'] = array_merge( $tagIds, $this->parse_tag( $postarr['tags_input'] ) );
|
||||
} else {
|
||||
$postarr = wp_slash( $postarr );
|
||||
}
|
||||
|
||||
return $postarr;
|
||||
}
|
||||
|
||||
private function parse_tag( $tags ) {
|
||||
if ( empty( $tags ) ) {
|
||||
$tags = array();
|
||||
}
|
||||
|
||||
if ( ! is_array( $tags ) ) {
|
||||
$comma = _x( ',', 'tag delimiter' );
|
||||
if ( ',' !== $comma ) {
|
||||
$tags = str_replace( $comma, ',', $tags );
|
||||
}
|
||||
$tags = explode( ',', trim( $tags, " \n\t\r\0\x0B," ) );
|
||||
}
|
||||
|
||||
return $tags;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
use WPML\LIB\WP\Hooks;
|
||||
|
||||
class WPML_Frontend_Post_Actions extends WPML_Post_Translation {
|
||||
|
||||
public function init() {
|
||||
parent::init ();
|
||||
if ( $this->is_setup_complete() ) {
|
||||
|
||||
/**
|
||||
* In theory, we could add the 'delete_post` action for all frontend requests
|
||||
* We'll limit it to REST to avoid any unexpected problems
|
||||
*/
|
||||
Hooks::onAction( 'rest_api_init' )
|
||||
->then( function () {
|
||||
add_action( 'delete_post', [ $this, 'delete_post_actions' ] );
|
||||
} );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $post_id
|
||||
* @param string $post_status
|
||||
*
|
||||
* @return null|int
|
||||
*/
|
||||
function get_save_post_trid( $post_id, $post_status ) {
|
||||
|
||||
return $this->get_element_trid( $post_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $pidd
|
||||
* @param WP_Post $post
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function save_post_actions( $pidd, $post ) {
|
||||
global $sitepress;
|
||||
|
||||
$this->defer_term_counting();
|
||||
if ( ! $post ) {
|
||||
$post = get_post( $pidd );
|
||||
}
|
||||
|
||||
$http_referer = new WPML_URL_HTTP_Referer( new WPML_Rest( new WP_Http() ) );
|
||||
// exceptions
|
||||
if ( ! $this->has_save_post_action( $post ) || $http_referer->is_rest_request_called_from_post_edit_page() ) {
|
||||
return;
|
||||
}
|
||||
$default_language = $sitepress->get_default_language();
|
||||
$post_vars = $this->get_post_vars( $post );
|
||||
$post_id = isset( $post_vars['post_ID'] ) ? $post_vars['post_ID']
|
||||
: $pidd; //latter case for XML-RPC publishing
|
||||
$language_code = $this->get_save_post_lang( $post_id, $sitepress );
|
||||
$trid = $this->get_save_post_trid( $post_id, $post->post_status );
|
||||
// after getting the right trid set the source language from it by referring to the root translation
|
||||
// of this trid, in case no proper source language has been set yet
|
||||
$source_language = $this->get_save_post_source_lang( $trid, $language_code, $default_language );
|
||||
$this->after_save_post( $trid, $post_vars, $language_code, $source_language );
|
||||
}
|
||||
|
||||
protected function get_save_post_source_lang( $trid, $language_code, $default_language ) {
|
||||
$post_id = $this->get_element_id ( $trid, $language_code );
|
||||
|
||||
return $post_id ? $this->get_source_lang_code ( $post_id ) : null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,383 @@
|
||||
<?php
|
||||
|
||||
require_once dirname( __FILE__ ) . '/wpml-wordpress-actions.class.php';
|
||||
|
||||
/**
|
||||
* Class WPML_Post_Duplication
|
||||
*
|
||||
* @package wpml-core
|
||||
* @subpackage post-translation
|
||||
*/
|
||||
class WPML_Post_Duplication extends WPML_WPDB_And_SP_User {
|
||||
|
||||
function get_duplicates( $master_post_id ) {
|
||||
global $wpml_post_translations;
|
||||
$duplicates = array();
|
||||
|
||||
$post_ids_query = " SELECT post_id
|
||||
FROM {$this->wpdb->postmeta}
|
||||
WHERE meta_key='_icl_lang_duplicate_of'
|
||||
AND meta_value = %d
|
||||
AND post_id <> %d";
|
||||
$post_ids_prepare = $this->wpdb->prepare( $post_ids_query, array( $master_post_id, $master_post_id ) );
|
||||
$post_ids = $this->wpdb->get_col( $post_ids_prepare );
|
||||
foreach ( $post_ids as $post_id ) {
|
||||
$language_code = $wpml_post_translations->get_element_lang_code( $post_id );
|
||||
|
||||
if ( ! $language_code ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$duplicates[ $language_code ] = $post_id;
|
||||
}
|
||||
|
||||
return $duplicates;
|
||||
}
|
||||
|
||||
function make_duplicate( $master_post_id, $lang ) {
|
||||
global $wpml_post_translations;
|
||||
|
||||
/**
|
||||
* @deprecated Use 'wpml_before_make_duplicate' instead
|
||||
* @since 3.4
|
||||
*/
|
||||
do_action( 'icl_before_make_duplicate', $master_post_id, $lang );
|
||||
do_action( 'wpml_before_make_duplicate', $master_post_id, $lang );
|
||||
$master_post = get_post( $master_post_id );
|
||||
|
||||
if ( ! $master_post || $this->is_external( $master_post_id ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$is_duplicated = false;
|
||||
$translations = $wpml_post_translations->get_element_translations( $master_post_id, false, false );
|
||||
if ( isset( $translations[ $lang ] ) ) {
|
||||
$post_array[ 'ID' ] = $translations[ $lang ];
|
||||
if ( WPML_WordPress_Actions::is_bulk_trash( $post_array[ 'ID' ] ) || WPML_WordPress_Actions::is_bulk_untrash( $post_array[ 'ID' ] ) ) {
|
||||
return true;
|
||||
}
|
||||
$is_duplicated = get_post_meta( $translations[ $lang ], '_icl_lang_duplicate_of', true );
|
||||
}
|
||||
$post_array['post_author'] = $master_post->post_author;
|
||||
$post_array['post_date'] = $master_post->post_date;
|
||||
$post_array['post_date_gmt'] = $master_post->post_date_gmt;
|
||||
$duplicated_post_content = $this->duplicate_post_content( $lang, $master_post );
|
||||
$post_array['post_content'] = $duplicated_post_content;
|
||||
$duplicated_post_title = $this->duplicate_post_title( $lang, $master_post );
|
||||
$post_array['post_title'] = $duplicated_post_title;
|
||||
$duplicated_post_excerpt = $this->duplicate_post_excerpt( $lang, $master_post );
|
||||
$post_array['post_excerpt'] = $duplicated_post_excerpt;
|
||||
if ( $this->sitepress->get_setting('sync_post_status' ) ) {
|
||||
$sync_post_status = true;
|
||||
} else {
|
||||
$sync_post_status = ( ! isset( $post_array[ 'ID' ] )
|
||||
|| ( $this->sitepress->get_setting( 'sync_delete' ) && $master_post->post_status === 'trash' ) || $is_duplicated );
|
||||
}
|
||||
if ( $sync_post_status || ( isset( $post_array[ 'ID' ] ) && get_post_status( $post_array[ 'ID' ] ) === 'auto-draft' ) ) {
|
||||
$post_array[ 'post_status' ] = $master_post->post_status;
|
||||
}
|
||||
$post_array[ 'comment_status' ] = $master_post->comment_status;
|
||||
$post_array[ 'ping_status' ] = $master_post->ping_status;
|
||||
$post_array[ 'post_name' ] = $master_post->post_name;
|
||||
if ( $master_post->post_parent ) {
|
||||
$parent = $this->sitepress->get_object_id( $master_post->post_parent, $master_post->post_type, false, $lang );
|
||||
$post_array[ 'post_parent' ] = $parent;
|
||||
}
|
||||
$post_array['menu_order'] = $master_post->menu_order;
|
||||
$post_array['post_type'] = $master_post->post_type;
|
||||
$post_array['post_mime_type'] = $master_post->post_mime_type;
|
||||
$trid = $this->sitepress->get_element_trid( $master_post->ID,
|
||||
'post_' . $master_post->post_type );
|
||||
$id = $this->save_duplicate( $post_array, $lang );
|
||||
|
||||
require_once WPML_PLUGIN_PATH . '/inc/cache.php';
|
||||
icl_cache_clear();
|
||||
|
||||
global $ICL_Pro_Translation;
|
||||
/** @var WPML_Pro_Translation $ICL_Pro_Translation */
|
||||
if ( $ICL_Pro_Translation ) {
|
||||
$ICL_Pro_Translation->fix_links_to_translated_content( $id, $lang );
|
||||
}
|
||||
if ( ! is_wp_error( $id ) ) {
|
||||
$ret = $this->run_wpml_actions( $master_post, $trid, $lang, $id, $post_array );
|
||||
} else {
|
||||
throw new Exception( $id->get_error_message() );
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $element_id
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
private function is_external( $element_id ) {
|
||||
$query = "SELECT element_type FROM {$this->wpdb->prefix}icl_translations WHERE element_id=%d AND element_type LIKE %s LIMIT 1";
|
||||
|
||||
return ! $this->wpdb->get_var( $this->wpdb->prepare( $query, $element_id, 'post_%' ) );
|
||||
}
|
||||
|
||||
private function run_wpml_actions( $master_post, $trid, $lang, $id, $post_array ) {
|
||||
$master_post_id = $master_post->ID;
|
||||
$this->sitepress->set_element_language_details( $id, 'post_' . $master_post->post_type, $trid, $lang );
|
||||
$this->sync_duplicate_password( $master_post_id, $id );
|
||||
$this->sync_page_template( $master_post_id, $id );
|
||||
$this->duplicate_fix_children( $master_post_id, $lang );
|
||||
|
||||
// make sure post name is copied
|
||||
$this->wpdb->update( $this->wpdb->posts, array( 'post_name' => $master_post->post_name ), array( 'ID' => $id ) );
|
||||
|
||||
if ( $this->sitepress->get_setting( 'sync_post_taxonomies', false ) ) {
|
||||
$this->duplicate_taxonomies( $master_post_id, $lang );
|
||||
}
|
||||
$this->duplicate_custom_fields( $master_post_id, $lang );
|
||||
update_post_meta( $id, '_icl_lang_duplicate_of', $master_post->ID );
|
||||
|
||||
// Duplicate post format after the taxonomies because post format is stored
|
||||
// as a taxonomy by WP.
|
||||
if ( $this->sitepress->get_setting( 'sync_post_format' ) ) {
|
||||
$_wp_post_format = get_post_format( $master_post_id );
|
||||
set_post_format( $id, $_wp_post_format );
|
||||
}
|
||||
if ( $this->sitepress->get_setting( 'sync_comments_on_duplicates' ) ) {
|
||||
$this->duplicate_comments( $master_post_id, $id );
|
||||
}
|
||||
$status_helper = wpml_get_post_status_helper();
|
||||
$status_helper->set_status( $id, ICL_TM_DUPLICATE );
|
||||
$status_helper->set_update_status( $id, false );
|
||||
do_action( 'icl_make_duplicate', $master_post_id, $lang, $post_array, $id );
|
||||
clean_post_cache( $id );
|
||||
|
||||
return $id;
|
||||
}
|
||||
|
||||
private function sync_page_template( $master_post_id, $duplicate_post_id ) {
|
||||
$_wp_page_template = get_post_meta( $master_post_id, '_wp_page_template', true );
|
||||
if ( ! empty( $_wp_page_template ) ) {
|
||||
update_post_meta( $duplicate_post_id, '_wp_page_template', $_wp_page_template );
|
||||
}
|
||||
}
|
||||
|
||||
private function duplicate_comments( $master_post_id, $translated_id ) {
|
||||
global $sitepress;
|
||||
|
||||
remove_filter( 'comments_clauses', array( $sitepress, 'comments_clauses' ), 10 );
|
||||
$comments_on_master = get_comments( array( 'post_id' => $master_post_id ) );
|
||||
$comments_on_translation = get_comments( array( 'post_id' => $translated_id, 'status' => 'any' ) );
|
||||
add_filter( 'comments_clauses', array( $sitepress, 'comments_clauses' ), 10, 2 );
|
||||
foreach ( $comments_on_translation as $comment ) {
|
||||
wp_delete_comment( $comment->comment_ID, true );
|
||||
clean_comment_cache( $comment->comment_ID );
|
||||
}
|
||||
$iclTranslationManagement = wpml_load_core_tm();
|
||||
foreach ( $comments_on_master as $comment ) {
|
||||
$iclTranslationManagement->duplication_insert_comment( $comment->comment_ID );
|
||||
clean_comment_cache( $comment->comment_ID );
|
||||
}
|
||||
|
||||
wp_update_comment_count_now( $master_post_id );
|
||||
wp_update_comment_count_now( $translated_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $post_array
|
||||
* @param string $lang
|
||||
*
|
||||
* @return int|WP_Error
|
||||
*/
|
||||
private function save_duplicate( array $post_array, $lang ) {
|
||||
return wpml_get_create_post_helper()->insert_post( $post_array, $lang, true );
|
||||
}
|
||||
|
||||
private function duplicate_fix_children( $master_post_id, $lang ) {
|
||||
$post_type = $this->wpdb->get_var(
|
||||
$this->wpdb->prepare( "SELECT post_type FROM {$this->wpdb->posts} WHERE ID=%d", $master_post_id )
|
||||
);
|
||||
$master_children = $this->wpdb->get_col(
|
||||
$this->wpdb->prepare(
|
||||
"SELECT ID FROM {$this->wpdb->posts} WHERE post_parent=%d AND post_type != 'revision'",
|
||||
$master_post_id
|
||||
)
|
||||
);
|
||||
$dup_parent = icl_object_id( $master_post_id, $post_type, false, $lang );
|
||||
if ( $master_children ) {
|
||||
foreach ( $master_children as $master_child ) {
|
||||
$dup_child = icl_object_id( $master_child, $post_type, false, $lang );
|
||||
if ( $dup_child ) {
|
||||
$this->wpdb->update( $this->wpdb->posts, array( 'post_parent' => $dup_parent ), array( 'ID' => $dup_child ) );
|
||||
}
|
||||
$this->duplicate_fix_children( $master_child, $lang );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function duplicate_taxonomies( $master_post_id, $lang ) {
|
||||
$post_type = get_post_field( 'post_type', $master_post_id );
|
||||
$taxonomies = get_object_taxonomies( $post_type );
|
||||
$trid = $this->sitepress->get_element_trid( $master_post_id, 'post_' . $post_type );
|
||||
if ( $trid ) {
|
||||
$translations = $this->sitepress->get_element_translations( $trid, 'post_' . $post_type, false, false, true );
|
||||
if ( isset( $translations[ $lang ] ) ) {
|
||||
$duplicate_post_id = $translations[ $lang ]->element_id;
|
||||
/* If we have an existing post, we first of all remove all terms currently attached to it.
|
||||
* The main reason behind is the removal of the potentially present default category on the post.
|
||||
*/
|
||||
wp_delete_object_term_relationships( $duplicate_post_id, $taxonomies );
|
||||
} else {
|
||||
return false; // translation not found!
|
||||
}
|
||||
}
|
||||
$term_helper = wpml_get_term_translation_util();
|
||||
$term_helper->duplicate_terms( $master_post_id, $lang );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function sync_duplicate_password( $master_post_id, $duplicate_post_id ) {
|
||||
if ( post_password_required( $master_post_id ) ) {
|
||||
$sql = $this->wpdb->prepare( "UPDATE {$this->wpdb->posts} AS dupl,
|
||||
(SELECT org.post_password FROM {$this->wpdb->posts} AS org WHERE ID = %d ) AS pwd
|
||||
SET dupl.post_password = pwd.post_password
|
||||
WHERE dupl.ID = %d",
|
||||
array( $master_post_id, $duplicate_post_id ) );
|
||||
$this->wpdb->query( $sql );
|
||||
}
|
||||
}
|
||||
|
||||
private function duplicate_custom_fields( $master_post_id, $lang ) {
|
||||
$duplicate_post_id = false;
|
||||
$post_type = get_post_field( 'post_type', $master_post_id );
|
||||
|
||||
$trid = $this->sitepress->get_element_trid( $master_post_id, 'post_' . $post_type );
|
||||
if ( $trid ) {
|
||||
$translations = $this->sitepress->get_element_translations( $trid, 'post_' . $post_type );
|
||||
if ( isset( $translations[ $lang ] ) ) {
|
||||
$duplicate_post_id = $translations[ $lang ]->element_id;
|
||||
} else {
|
||||
return false; // translation not found!
|
||||
}
|
||||
}
|
||||
$default_exceptions = WPML_Config::get_custom_fields_translation_settings();
|
||||
$exceptions = apply_filters( 'wpml_duplicate_custom_fields_exceptions', array() );
|
||||
$exceptions = array_merge( $exceptions, $default_exceptions );
|
||||
$exceptions = array_unique( $exceptions );
|
||||
|
||||
$exceptions_in = ! empty( $exceptions )
|
||||
? 'AND meta_key NOT IN ( ' . wpml_prepare_in( $exceptions ) . ') ' : '';
|
||||
$from_where_string = "FROM {$this->wpdb->postmeta} WHERE post_id = %d " . $exceptions_in;
|
||||
$post_meta_master = $this->wpdb->get_results( "SELECT meta_key, meta_value " . $this->wpdb->prepare( $from_where_string,
|
||||
$master_post_id ) );
|
||||
$this->wpdb->query( "DELETE " . $this->wpdb->prepare( $from_where_string, $duplicate_post_id ) );
|
||||
|
||||
$values = [];
|
||||
foreach ( $post_meta_master as $post_meta ) {
|
||||
$is_serialized = is_serialized( $post_meta->meta_value );
|
||||
$meta_data = array(
|
||||
'context' => 'custom_field',
|
||||
'attribute' => 'value',
|
||||
'key' => $post_meta->meta_key,
|
||||
'is_serialized' => $is_serialized,
|
||||
'post_id' => $duplicate_post_id,
|
||||
'master_post_id' => $master_post_id,
|
||||
);
|
||||
|
||||
/**
|
||||
* @deprecated use 'wpml_duplicate_generic_string' instead, with the same arguments
|
||||
*/
|
||||
$icl_duplicate_generic_string = apply_filters( 'icl_duplicate_generic_string',
|
||||
$post_meta->meta_value,
|
||||
$lang,
|
||||
$meta_data );
|
||||
$post_meta->meta_value = $icl_duplicate_generic_string;
|
||||
$wpml_duplicate_generic_string = apply_filters( 'wpml_duplicate_generic_string',
|
||||
$post_meta->meta_value,
|
||||
$lang,
|
||||
$meta_data );
|
||||
$post_meta->meta_value = $wpml_duplicate_generic_string;
|
||||
if ( ! is_serialized( $post_meta->meta_value ) ) {
|
||||
$post_meta->meta_value = maybe_serialize( $post_meta->meta_value );
|
||||
}
|
||||
|
||||
$values[] = $this->wpdb->prepare(
|
||||
'( %d, %s, %s )',
|
||||
$duplicate_post_id,
|
||||
$post_meta->meta_key,
|
||||
$post_meta->meta_value
|
||||
);
|
||||
}
|
||||
|
||||
if ( ! empty( $values ) ) {
|
||||
$values = implode( ', ', $values );
|
||||
$this->wpdb->query(
|
||||
// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
|
||||
"INSERT INTO `{$this->wpdb->postmeta}` (`post_id`, `meta_key`, `meta_value`) VALUES {$values}"
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $lang
|
||||
* @param \WP_Post $master_post
|
||||
*
|
||||
* @return array<string,mixed>
|
||||
*/
|
||||
private function duplicate_post_content( $lang, $master_post ) {
|
||||
$duplicated_post_content_meta = array(
|
||||
'context' => 'post',
|
||||
'attribute' => 'content',
|
||||
'key' => $master_post->ID
|
||||
);
|
||||
$duplicated_post_content = $master_post->post_content;
|
||||
$duplicated_post_content = apply_filters( 'icl_duplicate_generic_string', $duplicated_post_content, $lang, $duplicated_post_content_meta );
|
||||
$duplicated_post_content = apply_filters( 'wpml_duplicate_generic_string', $duplicated_post_content, $lang, $duplicated_post_content_meta );
|
||||
|
||||
return $duplicated_post_content;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $lang
|
||||
* @param \WP_Post $master_post
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
private function duplicate_post_title( $lang, $master_post ) {
|
||||
$duplicated_post_title_meta = array(
|
||||
'context' => 'post',
|
||||
'attribute' => 'title',
|
||||
'key' => $master_post->ID
|
||||
);
|
||||
$duplicated_post_title = $master_post->post_title;
|
||||
$duplicated_post_title = apply_filters( 'icl_duplicate_generic_string', $duplicated_post_title, $lang, $duplicated_post_title_meta );
|
||||
$duplicated_post_title = apply_filters( 'wpml_duplicate_generic_string', $duplicated_post_title, $lang, $duplicated_post_title_meta );
|
||||
|
||||
return $duplicated_post_title;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $lang
|
||||
* @param WP_Post $master_post
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
private function duplicate_post_excerpt( $lang, $master_post ) {
|
||||
$duplicated_post_excerpt_meta = array(
|
||||
'context' => 'post',
|
||||
'attribute' => 'excerpt',
|
||||
'key' => $master_post->ID
|
||||
);
|
||||
$duplicated_post_excerpt = $master_post->post_excerpt;
|
||||
$duplicated_post_excerpt = apply_filters( 'icl_duplicate_generic_string',
|
||||
$duplicated_post_excerpt,
|
||||
$lang,
|
||||
$duplicated_post_excerpt_meta );
|
||||
$duplicated_post_excerpt = apply_filters( 'wpml_duplicate_generic_string',
|
||||
$duplicated_post_excerpt,
|
||||
$lang,
|
||||
$duplicated_post_excerpt_meta );
|
||||
|
||||
return $duplicated_post_excerpt;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
class WPML_Post_Hierarchy_Sync extends WPML_Hierarchy_Sync {
|
||||
|
||||
protected $element_id_column = 'ID';
|
||||
protected $parent_element_id_column = 'ID';
|
||||
protected $parent_id_column = 'post_parent';
|
||||
protected $element_type_column = 'post_type';
|
||||
protected $element_type_prefix = 'post_';
|
||||
|
||||
/**
|
||||
* @param wpdb $wpdb
|
||||
*/
|
||||
public function __construct( &$wpdb ) {
|
||||
parent::__construct( $wpdb );
|
||||
$this->elements_table = $wpdb->posts;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $element_type
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_hierarchical( $element_type ) {
|
||||
return is_post_type_hierarchical( $element_type );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,364 @@
|
||||
<?php
|
||||
|
||||
use WPML\FP\Lst;
|
||||
use WPML\FP\Maybe;
|
||||
use WPML\FP\Obj;
|
||||
use function WPML\FP\partial;
|
||||
|
||||
/**
|
||||
* Class WPML_Post_Synchronization
|
||||
*
|
||||
* @package wpml-core
|
||||
* @subpackage post-translation
|
||||
*/
|
||||
|
||||
class WPML_Post_Synchronization extends WPML_SP_And_PT_User {
|
||||
|
||||
/** @var bool[] */
|
||||
private $sync_parent_cpt = array();
|
||||
/** @var bool $sync_parent */
|
||||
private $sync_parent;
|
||||
/** @var bool $sync_delete */
|
||||
private $sync_delete;
|
||||
/** @var bool $sync_ping_status */
|
||||
private $sync_ping_status;
|
||||
/** @var bool $sync_post_date */
|
||||
private $sync_post_date;
|
||||
/** @var bool $sync_post_format */
|
||||
private $sync_post_format;
|
||||
/** @var bool $sync_comment_status */
|
||||
private $sync_comment_status;
|
||||
/** @var bool $sync_page_template */
|
||||
private $sync_page_template;
|
||||
/** @var bool $sync_menu_order */
|
||||
private $sync_menu_order;
|
||||
/** @var bool $sync_password */
|
||||
private $sync_password;
|
||||
/** @var bool $sync_private_flag */
|
||||
private $sync_private_flag;
|
||||
/** @var bool $is_deleting_all_translations */
|
||||
private $is_deleting_all_translations = false;
|
||||
/** @var array $deleted_post_types */
|
||||
private $deleted_post_types = array();
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $sync_document_status;
|
||||
|
||||
/**
|
||||
* @param array $settings
|
||||
* @param WPML_Post_Translation $post_translations
|
||||
* @param SitePress $sitepress
|
||||
*/
|
||||
public function __construct( &$settings, &$post_translations, &$sitepress ) {
|
||||
parent::__construct( $post_translations, $sitepress );
|
||||
$this->sync_delete = isset( $settings[ 'sync_delete' ] ) ? $settings[ 'sync_delete' ] : false;
|
||||
$this->sync_parent = isset( $settings[ 'sync_page_parent' ] ) ? $settings[ 'sync_page_parent' ] : false;
|
||||
$this->sync_ping_status = isset( $settings[ 'sync_ping_status' ] ) ? $settings[ 'sync_ping_status' ] : false;
|
||||
$this->sync_post_date = isset( $settings[ 'sync_post_date' ] ) ? $settings[ 'sync_post_date' ] : false;
|
||||
$this->sync_post_format = isset( $settings[ 'sync_post_format' ] ) ? $settings[ 'sync_post_format' ] : false;
|
||||
$this->sync_comment_status = isset( $settings[ 'sync_comment_status' ] ) ? $settings[ 'sync_comment_status' ] : false;
|
||||
$this->sync_page_template = isset( $settings[ 'sync_page_template' ] ) ? $settings[ 'sync_page_template' ] : false;
|
||||
$this->sync_password = isset( $settings[ 'sync_password' ] ) ? $settings[ 'sync_password' ] : false;
|
||||
$this->sync_private_flag = isset( $settings[ 'sync_private_flag' ] ) ? $settings[ 'sync_private_flag' ] : false;
|
||||
$this->sync_document_status = isset( $settings[ 'translated_document_status' ] ) ? $settings[ 'translated_document_status' ] : 1;
|
||||
$this->sync_menu_order = isset( $settings[ 'sync_page_ordering' ] ) ? $settings[ 'sync_page_ordering' ] : array();
|
||||
}
|
||||
|
||||
private function must_sync_parents( $post_type ) {
|
||||
if ( ! array_key_exists( $post_type, $this->sync_parent_cpt ) ) {
|
||||
$this->sync_parent_cpt[ $post_type ] = apply_filters( 'wpml_sync_parent_for_post_type', $this->sync_parent, $post_type );
|
||||
}
|
||||
|
||||
return $this->sync_parent_cpt[ $post_type ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Fixes parents of translations for hierarchical post types
|
||||
*
|
||||
* User changed parent for a post in $post_type and we are setting proper parent for $translation_id in
|
||||
* $language_code_translated language
|
||||
*
|
||||
* @param string $post_type - post_type that should have the translated parents fixed
|
||||
*/
|
||||
private function maybe_fix_translated_parent( $post_type ) {
|
||||
if ( $this->must_sync_parents( $post_type ) ) {
|
||||
$sync_helper = wpml_get_hierarchy_sync_helper();
|
||||
$sync_helper->sync_element_hierarchy( $post_type );
|
||||
}
|
||||
}
|
||||
|
||||
public function sync_with_duplicates( $post_id ) {
|
||||
$duplicates = $this->sitepress->get_duplicates( $post_id );
|
||||
foreach ( array_keys( $duplicates ) as $lang_code ) {
|
||||
$this->sitepress->make_duplicate( $post_id, $lang_code );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $post_id
|
||||
* @param bool $keep_db_entries
|
||||
*/
|
||||
public function delete_post_actions( $post_id, $keep_db_entries = false ) {
|
||||
$post_type = get_post_type( $post_id );
|
||||
$post_type_exceptions = array( 'nav_menu_item' );
|
||||
if ( in_array( $post_type, $post_type_exceptions ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$trid = null;
|
||||
if ( ! $this->is_deleting_all_translations ) {
|
||||
$this->is_deleting_all_translations = ! $this->post_translation->get_original_element( $post_id, true );
|
||||
$trid = $this->post_translation->get_element_trid( $post_id );
|
||||
$translated_ids = $this->get_translations_without_source( $post_id, $trid );
|
||||
if ( $this->sync_delete || Lst::includes( $post_type, [ 'wp_template', 'wp_template_part' ] ) ) {
|
||||
$this->delete_translations( $translated_ids, $keep_db_entries );
|
||||
}
|
||||
$this->is_deleting_all_translations = false;
|
||||
}
|
||||
|
||||
if ( ! $keep_db_entries ) {
|
||||
$this->post_translation->delete_post_translation_entry( $post_id );
|
||||
|
||||
if ( $trid && ! $this->is_deleting_all_translations ) {
|
||||
$lang_code = $this->post_translation->get_element_lang_code( $post_id );
|
||||
$this->set_new_original( $trid, $lang_code );
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! $this->is_deleting_all_translations ) {
|
||||
$this->run_final_actions_for_delete_post( $post_type );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $post_id
|
||||
* @param int $trid
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_translations_without_source( $post_id, $trid ) {
|
||||
$actual_translations_only = ! $this->is_deleting_all_translations;
|
||||
$translated_ids = $this->post_translation->get_element_translations( $post_id, $trid, $actual_translations_only );
|
||||
unset( $translated_ids[ array_search( $post_id, $translated_ids ) ] );
|
||||
return $translated_ids;
|
||||
}
|
||||
|
||||
private function is_bulk_delete() {
|
||||
return ( isset( $_REQUEST['action'] ) && 'delete' === $_REQUEST['action']
|
||||
|| isset( $_REQUEST['action2'] ) && 'delete' === $_REQUEST['action2']
|
||||
) && ( isset( $_REQUEST['post'] ) && is_array( $_REQUEST['post'] )
|
||||
|| isset( $_REQUEST['media'] ) && is_array( $_REQUEST['media'] )
|
||||
);
|
||||
}
|
||||
|
||||
/** @param string $post_type */
|
||||
private function reset_cache( $post_type ) {
|
||||
require_once WPML_PLUGIN_PATH . '/inc/cache.php';
|
||||
icl_cache_clear( $post_type . 's_per_language', true );
|
||||
}
|
||||
|
||||
/** @param string $post_type */
|
||||
private function defer_delete_actions( $post_type ) {
|
||||
if ( ! in_array( $post_type, $this->deleted_post_types, true ) ) {
|
||||
$this->deleted_post_types[] = $post_type;
|
||||
if ( ! has_action( 'shutdown', array( $this, 'shutdown_action' ) ) ) {
|
||||
add_action( 'shutdown', array( $this, 'shutdown_action' ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function shutdown_action() {
|
||||
$this->post_translation->reload();
|
||||
|
||||
foreach ( $this->deleted_post_types as $post_type ) {
|
||||
$this->reset_cache( $post_type );
|
||||
$this->maybe_fix_translated_parent( $post_type );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $translated_ids
|
||||
* @param bool $keep_db_entries
|
||||
*/
|
||||
private function delete_translations( array $translated_ids, $keep_db_entries ) {
|
||||
if ( ! empty( $translated_ids ) ) {
|
||||
foreach ( $translated_ids as $trans_id ) {
|
||||
if ( ! $this->is_bulk_prevented( $trans_id ) ) {
|
||||
if ( $keep_db_entries ) {
|
||||
$this->post_translation->trash_translation( $trans_id );
|
||||
} else {
|
||||
wp_delete_post( $trans_id, true );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @param string $post_type */
|
||||
private function run_final_actions_for_delete_post( $post_type ) {
|
||||
if ( $this->is_bulk_delete() ) {
|
||||
$this->defer_delete_actions( $post_type );
|
||||
} else {
|
||||
$this->post_translation->reload();
|
||||
$this->reset_cache( $post_type );
|
||||
$this->maybe_fix_translated_parent( $post_type );
|
||||
}
|
||||
}
|
||||
|
||||
private function is_bulk_prevented( $post_id ) {
|
||||
|
||||
return ( isset( $_GET[ 'delete_all' ] ) && $_GET[ 'delete_all' ] === 'Empty Trash' )
|
||||
|| in_array( $post_id, ( isset( $_GET[ 'ids' ] ) ? $_GET[ 'ids' ] : array() ) );
|
||||
}
|
||||
|
||||
function untrashed_post_actions( $post_id ) {
|
||||
if ( $this->sync_delete ) {
|
||||
$translations = $this->post_translation->get_element_translations( $post_id, false, true );
|
||||
foreach ( $translations as $t_id ) {
|
||||
$this->post_translation->untrash_translation( $t_id );
|
||||
}
|
||||
}
|
||||
$post_type = get_post_type( $post_id );
|
||||
require_once WPML_PLUGIN_PATH . '/inc/cache.php';
|
||||
icl_cache_clear( $post_type . 's_per_language', true );
|
||||
}
|
||||
|
||||
public function sync_with_translations( $post_id, $post_vars = false ) {
|
||||
global $wpdb;
|
||||
|
||||
$wp_api = $this->sitepress->get_wp_api();
|
||||
$term_count_update = new WPML_Update_Term_Count( $wp_api );
|
||||
|
||||
$post = get_post ( $post_id );
|
||||
$source_post_status = $this->get_post_status( $post_id );
|
||||
$translated_ids = $this->post_translation->get_element_translations( $post_id, false, true );
|
||||
$post_format = $this->sync_post_format ? get_post_format( $post_id ) : null;
|
||||
$ping_status = $this->sync_ping_status ? ( pings_open( $post_id ) ? 'open' : 'closed' ) : null;
|
||||
$comment_status = $this->sync_comment_status ? ( comments_open( $post_id ) ? 'open' : 'closed' ) : null;
|
||||
$post_password = $this->sync_password ? $post->post_password : null;
|
||||
$menu_order = $this->sync_menu_order && ! empty( $post->menu_order ) ? $post->menu_order : null;
|
||||
$page_template = $this->sync_page_template && get_post_type( $post_id ) === 'page' ? get_post_meta( $post_id, '_wp_page_template', true ) : null;
|
||||
$post_date = $this->sync_post_date ? $wpdb->get_var( $wpdb->prepare( "SELECT post_date FROM {$wpdb->posts} WHERE ID=%d LIMIT 1", $post_id ) ) : null;
|
||||
|
||||
foreach ( $translated_ids as $lang_code => $translated_pid ) {
|
||||
$post_status = $this->get_post_status( $translated_pid );
|
||||
|
||||
$post_status_differs = ( 'private' === $source_post_status && 'publish' === $post_status )
|
||||
|| ( 'publish' === $source_post_status && 'private' === $post_status );
|
||||
if ( $this->sync_private_flag && $post_status_differs ) {
|
||||
$post_status = $source_post_status;
|
||||
}
|
||||
|
||||
$this->sync_custom_fields ( $post_id, $translated_pid );
|
||||
if ( $post_format ) {
|
||||
set_post_format ( $translated_pid, $post_format );
|
||||
}
|
||||
if ( $post_date !== null ) {
|
||||
$post_date_gmt = get_gmt_from_date ( $post_date );
|
||||
$data = array( 'post_date' => $post_date, 'post_date_gmt' => $post_date_gmt );
|
||||
$now = gmdate('Y-m-d H:i:59');
|
||||
$allow_post_statuses = array( 'private', 'pending', 'draft' );
|
||||
if ( mysql2date('U', $post_date_gmt, false) > mysql2date('U', $now, false) ) {
|
||||
if ( ! in_array( $post_status, $allow_post_statuses, true ) ) {
|
||||
$post_status = 'future';
|
||||
}
|
||||
}
|
||||
$data[ 'post_status' ] = $post_status;
|
||||
$wpdb->update ( $wpdb->posts, $data, array( 'ID' => $translated_pid ) );
|
||||
wp_schedule_single_event( strtotime( $post_date_gmt . '+1 second' ), 'publish_future_post', array( $translated_pid ) );
|
||||
}
|
||||
if ( $post_password !== null ) {
|
||||
$wpdb->update ( $wpdb->posts, array( 'post_password' => $post_password ), array( 'ID' => $translated_pid ) );
|
||||
}
|
||||
if ( $post_status !== null && ! in_array( $this->get_post_status( $translated_pid ), array( 'auto-draft', 'draft', 'inherit', 'trash' ) ) ) {
|
||||
$wpdb->update ( $wpdb->posts, array( 'post_status' => $post_status ), array( 'ID' => $translated_pid ) );
|
||||
$term_count_update->update_for_post( $translated_pid );
|
||||
} elseif ( $post_status == null && $this->sync_private_flag && $this->get_post_status( $translated_pid ) === 'private' ) {
|
||||
$wpdb->update ( $wpdb->posts, array( 'post_status' => $this->get_post_status( $post_id ) ), array( 'ID' => $translated_pid ) );
|
||||
$term_count_update->update_for_post( $translated_pid );
|
||||
}
|
||||
if ( $ping_status !== null ) {
|
||||
$wpdb->update ( $wpdb->posts, array( 'ping_status' => $ping_status ), array( 'ID' => $translated_pid ) );
|
||||
}
|
||||
if ( $comment_status !== null ) {
|
||||
$wpdb->update ( $wpdb->posts, array( 'comment_status' => $comment_status ), array( 'ID' => $translated_pid ) );
|
||||
}
|
||||
if ( $page_template !== null ) {
|
||||
update_post_meta ( $translated_pid, '_wp_page_template', $page_template );
|
||||
}
|
||||
$this->sync_with_translations ( $translated_pid );
|
||||
}
|
||||
$this->maybe_fix_translated_parent( get_post_type( $post_id ) );
|
||||
|
||||
if ( $menu_order !== null && (bool) $translated_ids !== false ) {
|
||||
$query = $wpdb->prepare(
|
||||
"UPDATE {$wpdb->posts}
|
||||
SET menu_order=%s
|
||||
WHERE ID IN (" . wpml_prepare_in( $translated_ids, '%d' ) . ')',
|
||||
$menu_order
|
||||
);
|
||||
$wpdb->query( $query );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The function `get_post_status` does not return the raw status for attachments.
|
||||
* As we are running direct DB updates here, we need the actual DB value.
|
||||
*
|
||||
* @param int $post_id
|
||||
*
|
||||
* @return string|false
|
||||
*/
|
||||
private function get_post_status( $post_id ) {
|
||||
$isAttachment = function( $post_id ) { return 'attachment' === get_post_type( $post_id ); };
|
||||
|
||||
return Maybe::of( $post_id )
|
||||
->filter( $isAttachment )
|
||||
->map( 'get_post' )
|
||||
->map( Obj::prop( 'post_status' ) )
|
||||
->getOrElse( partial( 'get_post_status', $post_id ) );
|
||||
}
|
||||
|
||||
private function sync_custom_fields( $original_id, $post_id ) {
|
||||
if ( $original_id && $original_id != $post_id ) {
|
||||
$this->sitepress->copy_custom_fields ( $original_id, $post_id );
|
||||
} else {
|
||||
$translations = $this->post_translation->get_element_translations ( $post_id, false, true );
|
||||
foreach ( $translations as $t_id ) {
|
||||
$this->sitepress->copy_custom_fields ( $post_id, $t_id );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function set_new_original( $trid, $removed_lang_code ) {
|
||||
if ( $trid && $removed_lang_code ) {
|
||||
$priorities = $this->sitepress->get_setting( 'languages_order' );
|
||||
$this->post_translation->reload();
|
||||
$translations = $this->post_translation->get_element_translations( false, $trid );
|
||||
$new_source_lang_code = false;
|
||||
foreach ( $priorities as $lang_code ) {
|
||||
if ( isset( $translations[ $lang_code ] ) ) {
|
||||
$new_source_lang_code = $lang_code;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( $new_source_lang_code ) {
|
||||
global $wpdb;
|
||||
|
||||
$rows_updated = $wpdb->update( $wpdb->prefix . 'icl_translations',
|
||||
array( 'source_language_code' => $new_source_lang_code ),
|
||||
array( 'trid' => $trid, 'source_language_code' => $removed_lang_code )
|
||||
);
|
||||
|
||||
if( 0 < $rows_updated ) {
|
||||
do_action( 'wpml_translation_update', array( 'trid' => $trid ) );
|
||||
}
|
||||
|
||||
$wpdb->query( " UPDATE {$wpdb->prefix}icl_translations
|
||||
SET source_language_code = NULL
|
||||
WHERE language_code = source_language_code" );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,442 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class WPML_Post_Translation
|
||||
*
|
||||
* @package wpml-core
|
||||
* @subpackage post-translation
|
||||
*/
|
||||
abstract class WPML_Post_Translation extends WPML_Element_Translation {
|
||||
|
||||
protected $settings;
|
||||
protected $post_translation_sync;
|
||||
public static $defer_term_counting = false;
|
||||
|
||||
/**
|
||||
* @var WPML_Debug_BackTrace
|
||||
*/
|
||||
private $debug_backtrace;
|
||||
|
||||
/**
|
||||
* @param array $settings
|
||||
* @param wpdb $wpdb
|
||||
*/
|
||||
public function __construct( &$settings, &$wpdb ) {
|
||||
parent::__construct( $wpdb );
|
||||
$this->settings = $settings;
|
||||
}
|
||||
|
||||
protected function is_setup_complete( ) {
|
||||
return isset( $this->settings[ 'setup_complete' ]) && $this->settings[ 'setup_complete' ];
|
||||
}
|
||||
|
||||
public function init() {
|
||||
if ( $this->is_setup_complete() ) {
|
||||
add_action( 'save_post', [ $this, 'save_post_actions' ], 100, 2 );
|
||||
add_action( 'shutdown', [ $this, 'shutdown_action' ], PHP_INT_MAX );
|
||||
add_action( 'edit_attachment', [ $this, 'attachment_actions' ], 100 );
|
||||
add_action( 'add_attachment', [ $this, 'attachment_actions' ], 100 );
|
||||
}
|
||||
}
|
||||
|
||||
public function get_original_post_status( $trid, $source_lang_code = null ) {
|
||||
|
||||
return $this->get_original_post_attr ( $trid, 'post_status', $source_lang_code );
|
||||
}
|
||||
|
||||
public function get_original_post_ID( $trid, $source_lang_code = null ) {
|
||||
|
||||
return $this->get_original_post_attr ( $trid, 'ID', $source_lang_code );
|
||||
}
|
||||
|
||||
public function get_original_menu_order
|
||||
( $trid, $source_lang_code = null ) {
|
||||
|
||||
return $this->get_original_post_attr ( $trid, 'menu_order', $source_lang_code );
|
||||
}
|
||||
|
||||
public function get_original_comment_status( $trid, $source_lang_code = null ) {
|
||||
|
||||
return $this->get_original_post_attr ( $trid, 'comment_status', $source_lang_code );
|
||||
}
|
||||
|
||||
public function get_original_ping_status( $trid, $source_lang_code = null ) {
|
||||
|
||||
return $this->get_original_post_attr ( $trid, 'ping_status', $source_lang_code );
|
||||
}
|
||||
|
||||
public function get_original_post_format( $trid, $source_lang_code = null ) {
|
||||
|
||||
return get_post_format ( $this->get_original_post_ID ( $trid, $source_lang_code ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $pidd
|
||||
* @param WP_Post $post
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public abstract function save_post_actions( $pidd, $post );
|
||||
|
||||
/** @param int $post_id */
|
||||
public function attachment_actions( $post_id ) {
|
||||
/**
|
||||
* This filter hooks determines whether we should apply the
|
||||
* "save_post" actions on an attachment.
|
||||
*
|
||||
* @since 4.4.0
|
||||
*
|
||||
* @param bool True if we should apply save post actions on the attachment, false otherwise (default false).
|
||||
* @param int $post_id The attachment post ID.
|
||||
*/
|
||||
if ( apply_filters( 'wpml_apply_save_attachment_actions', false, $post_id ) ) {
|
||||
$post = get_post( $post_id );
|
||||
|
||||
if ( $post ) {
|
||||
$this->save_post_actions( $post_id, $post );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function shutdown_action() {
|
||||
if ( self::$defer_term_counting ) {
|
||||
self::$defer_term_counting = false;
|
||||
wp_defer_term_counting( false );
|
||||
}
|
||||
}
|
||||
|
||||
public function trash_translation ( $trans_id ) {
|
||||
if ( !WPML_WordPress_Actions::is_bulk_trash( $trans_id ) ) {
|
||||
wp_trash_post( $trans_id );
|
||||
}
|
||||
}
|
||||
|
||||
public function untrash_translation( $trans_id ) {
|
||||
if ( ! WPML_WordPress_Actions::is_bulk_untrash( $trans_id ) ) {
|
||||
wp_untrash_post( $trans_id );
|
||||
}
|
||||
}
|
||||
|
||||
function untrashed_post_actions( $post_id ) {
|
||||
$translation_sync = $this->get_sync_helper ();
|
||||
$translation_sync->untrashed_post_actions ( $post_id );
|
||||
}
|
||||
|
||||
public function delete_post_translation_entry( $post_id ) {
|
||||
|
||||
$update_args = array( 'context' => 'post', 'element_id' => $post_id );
|
||||
do_action( 'wpml_translation_update', array_merge( $update_args, array( 'type' => 'before_delete' ) ) );
|
||||
|
||||
$sql = $this->wpdb->prepare( "DELETE FROM {$this->wpdb->prefix}icl_translations
|
||||
WHERE element_id = %d
|
||||
AND element_type LIKE 'post%%'
|
||||
LIMIT 1",
|
||||
$post_id );
|
||||
$res = $this->wpdb->query( $sql );
|
||||
|
||||
do_action( 'wpml_translation_update', array_merge( $update_args, array( 'type' => 'after_delete' ) ) );
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
public function trashed_post_actions( $post_id ) {
|
||||
$this->delete_post_actions( $post_id, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* This function holds all actions to be run after deleting a post.
|
||||
* 1. Delete the posts entry in icl_translations.
|
||||
* 2. Set one of the posts translations or delete all translations of the post, depending on sitepress settings.
|
||||
*
|
||||
* @param Integer $post_id
|
||||
* @param bool $keep_db_entries Sets whether icl_translations entries are to be deleted or kept, when hooking this to
|
||||
* post trashing we want them to be kept.
|
||||
*/
|
||||
public function delete_post_actions( $post_id, $keep_db_entries = false ) {
|
||||
$translation_sync = $this->get_sync_helper ();
|
||||
$translation_sync->delete_post_actions ( $post_id, $keep_db_entries );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $post_id
|
||||
* @param string $post_status
|
||||
*
|
||||
* @return null|int
|
||||
*/
|
||||
abstract function get_save_post_trid( $post_id, $post_status );
|
||||
|
||||
/**
|
||||
* @param integer $post_id
|
||||
* @param SitePress $sitepress
|
||||
* @return bool|mixed|null|string|void
|
||||
*/
|
||||
public function get_save_post_lang( $post_id, $sitepress ) {
|
||||
$language_code = $this->get_element_lang_code ( $post_id );
|
||||
$language_code = $language_code ? $language_code : $sitepress->get_current_language ();
|
||||
$language_code = $sitepress->is_active_language ( $language_code ) ? $language_code
|
||||
: $sitepress->get_default_language ();
|
||||
|
||||
return apply_filters ( 'wpml_save_post_lang', $language_code );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $trid
|
||||
* @param string $language_code
|
||||
* @param string $default_language
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
protected abstract function get_save_post_source_lang( $trid, $language_code, $default_language );
|
||||
|
||||
/**
|
||||
* Sets a posts language details, invalidates caches relating to the post and triggers
|
||||
* synchronisation actions across translations of the just saved post.
|
||||
*
|
||||
* @param int $trid
|
||||
* @param array $post_vars
|
||||
* @param string $language_code
|
||||
* @param string $source_language
|
||||
*
|
||||
* @used-by \WPML_Post_Translation::save_post_actions as final step of the WPML Core save_post actions
|
||||
*/
|
||||
protected function after_save_post( $trid, $post_vars, $language_code, $source_language ) {
|
||||
$this->maybe_set_elid( $trid, $post_vars['post_type'], $language_code, $post_vars['ID'], $source_language );
|
||||
$translation_sync = $this->get_sync_helper();
|
||||
$original_id = $this->get_original_element( $post_vars['ID'] );
|
||||
$translation_sync->sync_with_translations( $original_id ? $original_id : $post_vars['ID'], $post_vars );
|
||||
$translation_sync->sync_with_duplicates( $post_vars['ID'] );
|
||||
if ( ! function_exists( 'icl_cache_clear' ) ) {
|
||||
require_once WPML_PLUGIN_PATH . '/inc/cache.php';
|
||||
}
|
||||
icl_cache_clear( $post_vars['post_type'] . 's_per_language', true );
|
||||
if ( ! in_array( $post_vars['post_type'], array( 'nav_menu_item', 'attachment' ), true ) ) {
|
||||
do_action( 'wpml_tm_save_post', $post_vars['ID'], get_post( $post_vars['ID'] ), false );
|
||||
}
|
||||
// Flush object cache.
|
||||
$this->flush_object_cache_for_groups( array( 'ls_languages', 'element_translations' ) );
|
||||
|
||||
do_action( 'wpml_after_save_post', $post_vars['ID'], $trid, $language_code, $source_language );
|
||||
}
|
||||
|
||||
/**
|
||||
* Create new instance of WPML_WP_Cache for each group and flush cache for group.
|
||||
* @param array $groups
|
||||
*/
|
||||
private function flush_object_cache_for_groups( $groups = array() ) {
|
||||
if ( ! empty( $groups ) ) {
|
||||
foreach ( $groups as $group ) {
|
||||
$cache = new WPML_WP_Cache( $group );
|
||||
$cache->flush_group_cache();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function get_original_post_attr( $trid, $attribute, $source_lang_code ) {
|
||||
$legal_attributes = array(
|
||||
'post_status',
|
||||
'post_date',
|
||||
'menu_order',
|
||||
'comment_status',
|
||||
'ping_status',
|
||||
'ID'
|
||||
);
|
||||
$res = false;
|
||||
if ( in_array ( $attribute, $legal_attributes, true ) ) {
|
||||
$attribute = 'p.' . $attribute;
|
||||
$source_snippet = $source_lang_code === null
|
||||
? " AND wpml_translations.source_language_code IS NULL "
|
||||
: $this->wpdb->prepare ( " AND wpml_translations.language_code = %s ", $source_lang_code );
|
||||
$res = $this->wpdb->get_var (
|
||||
$this->wpdb->prepare (
|
||||
"SELECT {$attribute}
|
||||
" . $this->get_element_join() . "
|
||||
WHERE wpml_translations.trid=%d
|
||||
{$source_snippet}
|
||||
LIMIT 1",
|
||||
$trid
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
public function has_save_post_action( $post ) {
|
||||
if ( ! $post ) {
|
||||
return false;
|
||||
}
|
||||
$is_auto_draft = isset( $post->post_status ) && $post->post_status === 'auto-draft';
|
||||
$is_editing_different_post = $this->is_editing_different_post( $post->ID );
|
||||
$is_saving_a_revision = array_key_exists( 'post_type', $_POST ) && 'revision' === $_POST['post_type'];
|
||||
$is_untrashing = array_key_exists( 'action', $_GET ) && 'untrash' === $_GET['action'];
|
||||
$is_auto_save = array_key_exists( 'autosave', $_POST );
|
||||
$skip_sitepress_actions = array_key_exists( 'skip_sitepress_actions', $_POST );
|
||||
$is_post_a_revision = 'revision' === $post->post_type;
|
||||
$is_scheduled_to_be_trashed = get_post_meta( $post->ID, '_wp_trash_meta_status', true );
|
||||
$is_add_meta_action = isset( $_POST['action'] ) && 'add-meta' === $_POST['action'];
|
||||
$is_inner_post_insertion = $this->is_inner_post_insertion();
|
||||
|
||||
return $this->is_translated_type( $post->post_type )
|
||||
&& ! ( $is_auto_draft
|
||||
|| $is_auto_save
|
||||
|| $skip_sitepress_actions
|
||||
|| ( $is_editing_different_post && ! $is_inner_post_insertion )
|
||||
|| $is_saving_a_revision
|
||||
|| $is_post_a_revision
|
||||
|| $is_scheduled_to_be_trashed
|
||||
|| $is_add_meta_action
|
||||
|| $is_untrashing );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $post_id
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function is_editing_different_post( $post_id ) {
|
||||
return array_key_exists( 'post_ID', $_POST ) && (int) $_POST['post_ID'] && $post_id != $_POST['post_ID'];
|
||||
}
|
||||
|
||||
protected function get_element_join() {
|
||||
|
||||
return "FROM {$this->wpdb->prefix}icl_translations wpml_translations
|
||||
JOIN {$this->wpdb->posts} p
|
||||
ON wpml_translations.element_id = p.ID
|
||||
AND wpml_translations.element_type = CONCAT('post_', p.post_type)";
|
||||
}
|
||||
|
||||
protected function get_type_prefix() {
|
||||
return 'post_';
|
||||
}
|
||||
|
||||
|
||||
public function is_translated_type( $post_type ) {
|
||||
global $sitepress;
|
||||
|
||||
return $sitepress->is_translated_post_type ( $post_type );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WP_Post $post
|
||||
*
|
||||
* @return string[] all language codes the post can be translated into
|
||||
*/
|
||||
public function get_allowed_target_langs( $post ) {
|
||||
global $sitepress;
|
||||
|
||||
$active_languages = $sitepress->get_active_languages ();
|
||||
$can_translate = array_keys ( $active_languages );
|
||||
$can_translate = array_diff (
|
||||
$can_translate,
|
||||
array( $this->get_element_lang_code ( $post->ID ) )
|
||||
);
|
||||
|
||||
return apply_filters ( 'wpml_allowed_target_langs', $can_translate, $post->ID, 'post' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Before setting the language of the post to be saved, check if a translation in this language already exists
|
||||
* This check is necessary, so that synchronization actions like thrashing or un-trashing of posts, do not lead to
|
||||
* database corruption, due to erroneously changing a posts language into a state,
|
||||
* where it collides with an existing translation. While the UI prevents this sort of action for the most part,
|
||||
* this is not necessarily the case for other plugins like TM.
|
||||
* The logic here first of all checks if an existing translation id is present in the desired language_code.
|
||||
* If so but this translation is actually not the currently to be saved post,
|
||||
* then this post will be saved to its current language. If the translation already exists,
|
||||
* the existing translation id will be used. In all other cases a new entry in icl_translations will be created.
|
||||
*
|
||||
* @param Integer $trid
|
||||
* @param String $post_type
|
||||
* @param String $language_code
|
||||
* @param Integer $post_id
|
||||
* @param String $source_language
|
||||
*/
|
||||
private function maybe_set_elid( $trid, $post_type, $language_code, $post_id, $source_language ) {
|
||||
global $sitepress;
|
||||
|
||||
$element_type = 'post_' . $post_type;
|
||||
$sitepress->set_element_language_details (
|
||||
$post_id,
|
||||
$element_type,
|
||||
$trid,
|
||||
$language_code,
|
||||
$source_language
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return WPML_Post_Synchronization
|
||||
*/
|
||||
private function get_sync_helper() {
|
||||
global $sitepress;
|
||||
|
||||
$this->post_translation_sync = $this->post_translation_sync
|
||||
? $this->post_translation_sync : new WPML_Post_Synchronization( $this->settings, $this, $sitepress );
|
||||
|
||||
return $this->post_translation_sync;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return WPML_Debug_BackTrace
|
||||
*/
|
||||
private function get_debug_backtrace() {
|
||||
if ( ! $this->debug_backtrace ) {
|
||||
$this->debug_backtrace = new WPML\Utils\DebugBackTrace( 20 );
|
||||
}
|
||||
|
||||
return $this->debug_backtrace;
|
||||
}
|
||||
|
||||
public function set_debug_backtrace( WPML_Debug_BackTrace $debug_backtrace ) {
|
||||
$this->debug_backtrace = $debug_backtrace;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
protected function is_inner_post_insertion() {
|
||||
$debug_backtrace = $this->get_debug_backtrace();
|
||||
return 1 < $debug_backtrace->count_function_in_call_stack( 'wp_insert_post' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WP_Post $post
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function get_post_vars( $post ) {
|
||||
$post_vars = array();
|
||||
|
||||
if ( ! $this->is_inner_post_insertion() ) {
|
||||
$post_vars = (array) $_POST;
|
||||
}
|
||||
|
||||
foreach ( (array) $post as $k => $v ) {
|
||||
$post_vars[ $k ] = $v;
|
||||
}
|
||||
|
||||
$post_vars['post_type'] = isset( $post_vars['post_type'] ) ? $post_vars['post_type'] : $post->post_type;
|
||||
|
||||
return $post_vars;
|
||||
}
|
||||
|
||||
protected function defer_term_counting() {
|
||||
if ( ! self::$defer_term_counting ) {
|
||||
self::$defer_term_counting = true;
|
||||
wp_defer_term_counting( true );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return self|WPML_Frontend_Post_Actions|WPML_Admin_Post_Actions
|
||||
*/
|
||||
public static function getGlobalInstance() {
|
||||
global $wpml_post_translations, $sitepress;
|
||||
|
||||
if ( ! isset( $wpml_post_translations ) ) {
|
||||
wpml_load_post_translation( is_admin(), $sitepress->get_settings() );
|
||||
}
|
||||
|
||||
return $wpml_post_translations;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,310 @@
|
||||
<?php
|
||||
|
||||
class WPML_Root_Page_Actions {
|
||||
|
||||
/** @var array $sp_settings */
|
||||
private $sp_settings;
|
||||
|
||||
public function __construct( &$sitepress_settings ) {
|
||||
$this->sp_settings = &$sitepress_settings;
|
||||
}
|
||||
|
||||
public function delete_root_page_lang() {
|
||||
global $wpdb;
|
||||
$root_id = $this->get_root_page_id ();
|
||||
|
||||
if ( $root_id ) {
|
||||
|
||||
$update_args = array(
|
||||
'element_id' => $root_id,
|
||||
'element_type' => 'post_page',
|
||||
'context' => 'post'
|
||||
);
|
||||
|
||||
do_action( 'wpml_translation_update', array_merge( $update_args, array( 'type' => 'before_delete' ) ) );
|
||||
|
||||
$wpdb->delete (
|
||||
$wpdb->prefix . 'icl_translations', array( 'element_id' => $root_id, 'element_type' => 'post_page' ), array( '%d', '%s' )
|
||||
);
|
||||
|
||||
do_action( 'wpml_translation_update', array_merge( $update_args, array( 'type' => 'after_delete' ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a given $url points at the root page
|
||||
*
|
||||
* @param string $url
|
||||
*
|
||||
* @return bool
|
||||
*
|
||||
* @uses \WPML_Root_Page::is_root_page
|
||||
*/
|
||||
public function is_url_root_page( $url ) {
|
||||
$ret = false;
|
||||
|
||||
if ( $this->get_root_page_id() ) {
|
||||
$ret = WPML_Root_Page::is_root_page( $url );
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* If a page is used as the root page, returns the id of that page, otherwise false.
|
||||
*
|
||||
* @return bool|false|int
|
||||
*/
|
||||
public function get_root_page_id() {
|
||||
$urls_in_dirs = isset($this->sp_settings['language_negotiation_type']) && (int)$this->sp_settings['language_negotiation_type'] === 1;
|
||||
$urls = isset( $this->sp_settings['urls'] ) ? $this->sp_settings['urls'] : array();
|
||||
|
||||
return $urls_in_dirs && isset( $urls['root_page'] )
|
||||
&& ! empty( $urls['directory_for_default_language'] )
|
||||
&& isset( $urls['show_on_root'] )
|
||||
&& $urls['show_on_root'] === 'page'
|
||||
&& $urls['root_page']
|
||||
? $urls['root_page'] : false;
|
||||
}
|
||||
|
||||
function wpml_home_url_init() {
|
||||
global $pagenow, $sitepress;
|
||||
|
||||
if ( $pagenow == 'post.php' || $pagenow == 'post-new.php' ) {
|
||||
|
||||
$root_id = $this->get_root_page_id();
|
||||
if ( ! empty( $_GET['wpml_root_page'] ) && ! empty( $root_id ) ) {
|
||||
$rp = get_post( $root_id );
|
||||
if ( $rp && $rp->post_status != 'trash' ) {
|
||||
wp_redirect( get_edit_post_link( $root_id, 'no-display' ) );
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
if ( isset( $_GET['wpml_root_page'] ) && $_GET['wpml_root_page'] || ( isset( $_GET['post'] ) && $_GET['post'] == $root_id ) ) {
|
||||
remove_action( 'admin_head', array( $sitepress, 'post_edit_language_options' ) );
|
||||
add_action( 'admin_head', array( $this, 'wpml_home_url_language_box_setup' ) );
|
||||
remove_action( 'page_link', array( $sitepress, 'permalink_filter' ), 1 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function wpml_home_url_exclude_root_page_from_menus( $args ) {
|
||||
if ( !empty( $args[ 'exclude' ] ) ) {
|
||||
$args[ 'exclude' ] .= ',';
|
||||
} else {
|
||||
$args[ 'exclude' ] = '';
|
||||
}
|
||||
$args[ 'exclude' ] .= $this->get_root_page_id();
|
||||
|
||||
return $args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters out all page menu items that point to the root page.
|
||||
*
|
||||
* @param object[] $items
|
||||
*
|
||||
* @return array
|
||||
*
|
||||
* @hook wp_get_nav_menu_items
|
||||
*/
|
||||
function exclude_root_page_menu_item( $items ) {
|
||||
$root_id = $this->get_root_page_id();
|
||||
foreach ( $items as $key => $item ) {
|
||||
if ( isset( $item->object_id )
|
||||
&& isset( $item->type )
|
||||
&& $item->object_id == $root_id
|
||||
&& $item->type === 'post_type'
|
||||
) {
|
||||
unset( $items[ $key ] );
|
||||
}
|
||||
}
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
function wpml_home_url_exclude_root_page( $excludes ) {
|
||||
$excludes[ ] = $this->get_root_page_id();
|
||||
|
||||
return $excludes;
|
||||
|
||||
}
|
||||
|
||||
function wpml_home_url_exclude_root_page2( $args ) {
|
||||
$args[ 'exclude' ][ ] = $this->get_root_page_id();
|
||||
|
||||
return $args;
|
||||
}
|
||||
|
||||
function wpml_home_url_get_pages( $pages ) {
|
||||
$root_id = $this->get_root_page_id();
|
||||
foreach ( $pages as $k => $page ) {
|
||||
if ( $page->ID == $root_id ) {
|
||||
unset( $pages[ $k ] );
|
||||
$pages = array_values ( $pages );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $pages;
|
||||
}
|
||||
|
||||
function wpml_home_url_language_box_setup() {
|
||||
add_meta_box(
|
||||
WPML_Meta_Boxes_Post_Edit_HTML::WRAPPER_ID,
|
||||
__( 'Language', 'sitepress' ),
|
||||
array( $this, 'wpml_home_url_language_box' ),
|
||||
'page',
|
||||
/**
|
||||
* Filter meta box position.
|
||||
*
|
||||
* The context within the screen where the boxes should display. Available contexts vary from screen to screen.
|
||||
* Post edit screen contexts include 'normal', 'side', and 'advanced'.
|
||||
*
|
||||
* @param String WPML_Meta_Boxes_Post_Edit_HTML::WRAPPER_ID Meta box ID.
|
||||
*
|
||||
* @since 4.2.8
|
||||
*
|
||||
*/
|
||||
apply_filters( 'wpml_post_edit_meta_box_context', 'side', WPML_Meta_Boxes_Post_Edit_HTML::WRAPPER_ID ),
|
||||
apply_filters( 'wpml_post_edit_meta_box_priority', 'high' )
|
||||
);
|
||||
}
|
||||
|
||||
function wpml_home_url_language_box( $post ) {
|
||||
$root_id = $this->get_root_page_id();
|
||||
if ( isset( $_GET[ 'wpml_root_page' ] )
|
||||
|| ( !empty( $root_id )
|
||||
&& $post->ID == $root_id ) ) {
|
||||
_e ( "This page does not have a language since it's the site's root page." );
|
||||
echo '<input type="hidden" name="_wpml_root_page" value="1" />';
|
||||
}
|
||||
}
|
||||
|
||||
function wpml_home_url_save_post_actions( $pidd, $post ) {
|
||||
global $sitepress, $wpdb, $iclTranslationManagement;
|
||||
|
||||
if ( (bool) filter_input ( INPUT_POST, '_wpml_root_page' ) === true ) {
|
||||
|
||||
if ( isset( $_POST[ 'autosave' ] ) || ( isset( $post->post_type ) && $post->post_type == 'revision' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$iclsettings[ 'urls' ][ 'root_page' ] = $post->ID;
|
||||
$sitepress->save_settings ( $iclsettings );
|
||||
|
||||
remove_action( 'save_post', array( $sitepress, 'save_post_actions' ), 10 );
|
||||
|
||||
if ( !is_null ( $iclTranslationManagement ) ) {
|
||||
remove_action( 'save_post', array( $iclTranslationManagement, 'save_post_actions' ), 11 );
|
||||
}
|
||||
|
||||
$update_args = array(
|
||||
'element_id' => $post->ID,
|
||||
'element_type' => 'post_page',
|
||||
'context' => 'post'
|
||||
);
|
||||
|
||||
do_action( 'wpml_translation_update', array_merge( $update_args, array( 'type' => 'before_delete' ) ) );
|
||||
|
||||
$wpdb->query (
|
||||
$wpdb->prepare (
|
||||
"DELETE FROM {$wpdb->prefix}icl_translations WHERE element_type='post_page' AND element_id=%d",
|
||||
$post->ID
|
||||
)
|
||||
);
|
||||
|
||||
do_action( 'wpml_translation_update', array_merge( $update_args, array( 'type' => 'after_delete' ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
function wpml_home_url_setup_root_page() {
|
||||
global $sitepress, $wpml_query_filter;
|
||||
|
||||
remove_action( 'template_redirect', 'redirect_canonical' );
|
||||
add_action( 'parse_query', array( $this, 'wpml_home_url_parse_query' ) );
|
||||
|
||||
remove_filter( 'posts_join', array( $wpml_query_filter, 'posts_join_filter' ), 10 );
|
||||
remove_filter( 'posts_where', array( $wpml_query_filter, 'posts_where_filter' ), 10 );
|
||||
$root_id = $this->get_root_page_id();
|
||||
$rp = get_post( $root_id );
|
||||
if ( $rp && $rp->post_status != 'trash' ) {
|
||||
$sitepress->ROOT_URL_PAGE_ID = $root_id;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WP_Query $q
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
function wpml_home_url_parse_query( $q ) {
|
||||
if ( ! $q->is_main_query() ) {
|
||||
return $q;
|
||||
}
|
||||
if ( ! WPML_Root_Page::is_current_request_root() ) {
|
||||
return $q;
|
||||
} else {
|
||||
remove_action( 'parse_query', array( $this, 'wpml_home_url_parse_query' ) );
|
||||
|
||||
$uri_path = trim( wpml_parse_url( $_SERVER['REQUEST_URI'], PHP_URL_PATH ), '/' );
|
||||
$uri_parts = explode( '/', $uri_path );
|
||||
$potential_pagination_parameter = array_pop( $uri_parts );
|
||||
|
||||
$query_args = array();
|
||||
wp_parse_str( wpml_parse_url( $_SERVER['REQUEST_URI'], PHP_URL_QUERY ), $query_args );
|
||||
|
||||
if ( is_numeric( $potential_pagination_parameter ) ) {
|
||||
$query_args['page'] = $potential_pagination_parameter;
|
||||
}
|
||||
|
||||
$q->parse_query( $query_args );
|
||||
$root_id = $this->get_root_page_id();
|
||||
add_action( 'parse_query', array( $this, 'wpml_home_url_parse_query' ) );
|
||||
|
||||
if ( false !== $root_id ) {
|
||||
$q = $this->set_page_query_parameters( $q, $root_id );
|
||||
} else {
|
||||
$front_page = get_option( 'page_on_front' );
|
||||
if ( $front_page ) {
|
||||
$q = $this->set_page_query_parameters( $q, $front_page );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $q;
|
||||
}
|
||||
|
||||
private function set_page_query_parameters( $q, $page_id ) {
|
||||
$q->query_vars['page_id'] = $page_id;
|
||||
$q->query['page_id'] = $page_id;
|
||||
$q->is_page = 1;
|
||||
$q->queried_object = new WP_Post( get_post( $page_id ) );
|
||||
$q->queried_object_id = $page_id;
|
||||
$q->query_vars['error'] = '';
|
||||
$q->is_404 = false;
|
||||
$q->query['error'] = null;
|
||||
$q->is_home = false;
|
||||
$q->is_singular = true;
|
||||
|
||||
return $q;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the language switcher is to be displayed.
|
||||
* Used to check if the displayed page is a root page and the switcher is to be hidden because of it.
|
||||
*
|
||||
* @return bool true if the switcher is to be hidden
|
||||
*/
|
||||
function wpml_home_url_ls_hide_check() {
|
||||
global $sitepress;
|
||||
|
||||
return $sitepress->get_setting( 'language_negotiation_type' ) == 1
|
||||
&& (bool) ( $urls = $sitepress->get_setting( 'urls' ) ) === true
|
||||
&& ! empty( $urls['directory_for_default_language'] )
|
||||
&& isset( $urls['show_on_root'] ) && $urls['show_on_root'] === 'page'
|
||||
&& ! empty( $urls['hide_language_switchers'] )
|
||||
&& WPML_Root_Page::is_current_request_root();
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class WPML_WordPress_Actions
|
||||
* @package wpml-core
|
||||
* @subpackage post-translation
|
||||
*/
|
||||
class WPML_WordPress_Actions {
|
||||
|
||||
/**
|
||||
* @param int $post_id
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_bulk_trash( $post_id ) {
|
||||
if ( self::is_trash_action() && self::post_id_in_bulk( $post_id ) ) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $post_id
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_bulk_untrash( $post_id ) {
|
||||
if ( self::is_untrash_action() && self::post_id_in_bulk( $post_id, true ) ) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static function is_heartbeat( ) {
|
||||
return self::is_action( 'heartbeat', 'post' );
|
||||
}
|
||||
|
||||
protected static function is_trash_action() {
|
||||
return self::is_action( 'trash' );
|
||||
}
|
||||
|
||||
protected static function is_untrash_action() {
|
||||
return self::is_action( 'untrash' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $action
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected static function is_action( $action, $type = 'get' ) {
|
||||
if ( $type == 'get' ) {
|
||||
return ( isset( $_GET[ 'action' ] ) && $_GET[ 'action' ] == $action ) || ( isset( $_GET[ 'action2' ] ) && $_GET[ 'action2' ] == $action );
|
||||
} elseif ( $type == 'post' ) {
|
||||
return ( isset( $_POST[ 'action' ] ) && $_POST[ 'action' ] == $action ) || ( isset( $_POST[ 'action2' ] ) && $_POST[ 'action2' ] == $action );
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $post_id
|
||||
* @param bool $check_ids
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected static function post_id_in_bulk( $post_id, $check_ids = false ) {
|
||||
if ( isset( $_GET[ 'post' ] ) && is_array( $_GET[ 'post' ] ) && in_array( $post_id, $_GET[ 'post' ] ) ) {
|
||||
return true;
|
||||
} elseif ( $check_ids ) {
|
||||
// We need to check the ids parameter when user clicks on 'undo' after trashing.
|
||||
return isset( $_GET[ 'ids' ] ) && is_string( $_GET[ 'ids' ] ) && in_array( $post_id, explode( ',', $_GET[ 'ids' ] ) );
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user