first commit

This commit is contained in:
2023-09-12 21:41:04 +02:00
commit 3361a7f053
13284 changed files with 2116755 additions and 0 deletions

View File

@@ -0,0 +1,77 @@
<?php
namespace WPML\TM\Settings;
use WPML\Core\BackgroundTask;
use WPML\FP\Lst;
use WPML\LIB\WP\Hooks;
use WPML\WP\OptionManager;
use function WPML\Container\make;
class CustomFieldChangeDetector implements \IWPML_Backend_Action {
const PREVIOUS_SETTING = 'previous-custom-fields-to-translate';
const DETECTED_SETTING = 'detected-custom-fields-to-translate';
const LOCK_TIME = 2 * MINUTE_IN_SECONDS;
public function add_hooks() {
Hooks::onAction( 'wpml_after_tm_loaded', 1 )
->then( [ self::class, 'getNew' ] )
->then( [ self::class, 'notify' ] )
->then( [ self::class, 'updatePrevious' ] );
}
public static function getNew() {
if ( is_null( OptionManager::getOr( null, 'TM', self::PREVIOUS_SETTING ) ) ) {
self::updatePrevious();
}
return Lst::diff(
Repository::getCustomFieldsToTranslate() ?: [],
OptionManager::getOr( [], 'TM', self::PREVIOUS_SETTING )
);
}
public static function notify( array $newFields ) {
if ( count( $newFields ) ) {
OptionManager::update(
'TM',
self::DETECTED_SETTING,
Lst::concat( self::getDetected(), $newFields )
);
}
}
public static function remove( array $fields ) {
if ( count( $fields ) ) {
OptionManager::update(
'TM',
self::DETECTED_SETTING,
Lst::diff( self::getDetected(), $fields )
);
}
}
public static function updatePrevious() {
OptionManager::update( 'TM', self::PREVIOUS_SETTING, Repository::getCustomFieldsToTranslate() );
}
public static function getDetected() {
return OptionManager::getOr( [], 'TM', self::DETECTED_SETTING );
}
public static function processNewFields() {
$newFields = self::getDetected();
if ( count( $newFields ) ) {
/**
* Create a lock to make sure only one background task will run at a time.
* We wont release the lock so it wont be able to run again until the time out is complete.
*/
$lock = make( 'WPML\Utilities\Lock', [ ':name' => self::class ] );
if ( $lock->create( self::LOCK_TIME ) ) {
BackgroundTask::add( ProcessNewTranslatableFields::class, [ 'newFields' => $newFields ] );
}
}
}
}

View File

@@ -0,0 +1,85 @@
<?php
namespace WPML\TM\Settings;
use WPML\Collect\Support\Collection;
use WPML\Element\API\PostTranslations;
use WPML\FP\Either;
use WPML\Setup\Option;
use WPML\TM\AutomaticTranslation\Actions\Actions;
class ProcessNewTranslatableFields {
const MAX_POSTS = 10;
public function run(
Collection $data,
\wpdb $wpdb,
\WPML_TM_Post_Actions $postActions,
Actions $autoTranslateActions
) {
$fields = $data->get( 'newFields', [] );
$page = (int) $data->get( 'page', 1 );
if ( count( $fields ) ) {
$postIds = self::getPosts( $wpdb, $fields, $page );
$this->updateNeedsUpdate( $postIds, $postActions, $autoTranslateActions );
if ( count( $postIds ) ) {
return self::getFetchNextPageResponse( $fields, $page );
} else {
CustomFieldChangeDetector::remove( $fields );
}
}
return Either::of( null );
}
private static function getPosts( \wpdb $wpdb, array $fields, $page ) {
$fieldsIn = wpml_prepare_in( $fields, '%s' );
$offset = ( $page - 1 ) * self::MAX_POSTS;
$limit = self::MAX_POSTS;
return $wpdb->get_col(
$wpdb->prepare(
"SELECT DISTINCT post_id
FROM {$wpdb->prefix}postmeta
WHERE meta_key IN ({$fieldsIn}) AND meta_key <> ''
LIMIT %d OFFSET %d",
$limit,
$offset
)
);
}
private static function getFetchNextPageResponse( $fields, $page ) {
return Either::of( [
'status' => 'continue',
'data' => [ 'newFields' => $fields, 'page' => $page + 1 ],
] );
}
/**
* @param array $postIds
* @param \WPML_TM_Post_Actions $postActions
*/
private function updateNeedsUpdate(
array $postIds,
\WPML_TM_Post_Actions $postActions,
Actions $autoTranslateActions
) {
foreach ( $postIds as $postId ) {
$translations = PostTranslations::getIfOriginal( $postId );
$updater = $postActions->get_translation_statuses_updater( $postId, $translations );
$needsUpdate = $updater();
if (
$needsUpdate
&& \WPML_TM_ATE_Status::is_enabled_and_activated()
&& Option::shouldTranslateEverything()
) {
$autoTranslateActions->sendToTranslation( $postId );
}
}
}
}

View File

@@ -0,0 +1,56 @@
<?php
namespace WPML\TM\Settings;
class Repository {
public static function getSetting( $indexes ) {
$settings = self::getAllSettings();
/**
* I do not know why the foreach loop looks like that. I have just copied it from WPML_Translation_Job_Helper
* @todo Review it later and try simplify if possible
*/
foreach ( $indexes as $index ) {
$settings = isset( $settings[ $index ] ) ? $settings[ $index ] : null;
if ( ! isset( $settings ) ) {
break;
}
}
return $settings;
}
public static function getCustomFieldsToTranslate() {
return array_values( array_filter( array_keys(
self::getSetting( [ 'custom_fields_translation' ] ) ?: [],
WPML_TRANSLATE_CUSTOM_FIELD
) ) );
}
public static function getCustomFields() {
return \wpml_collect( self::getSetting( [ 'custom_fields_translation' ] ) ?: [] )
->filter( function ( $value, $key ) {
return (bool) $key;
} )->toArray();
}
/**
* @return array
*/
private static function getAllSettings() {
/** @var \TranslationManagement $iclTranslationManagement */
global $iclTranslationManagement;
if ( ! $iclTranslationManagement ) {
return [];
}
if ( empty( $iclTranslationManagement->settings ) ) {
$iclTranslationManagement->init();
}
return $iclTranslationManagement->get_settings();
}
}

View File

@@ -0,0 +1,43 @@
<?php
namespace WPML\Settings;
use WPML\API\PostTypes;
use WPML\Core\WP\App\Resources;
use WPML\FP\Either;
use WPML\FP\Fns;
use WPML\FP\Logic;
use WPML\LIB\WP\Hooks;
use WPML\Setup\Option;
use WPML\TM\ATE\AutoTranslate\Endpoint\GetNumberOfPosts;
use WPML\TM\ATE\AutoTranslate\Endpoint\SetForPostType;
use WPML\UIPage;
class UI implements \IWPML_Backend_Action {
public function add_hooks() {
Hooks::onAction( 'admin_enqueue_scripts' )
->then( Fns::always( $_GET ) )
->then( Logic::anyPass( [ [ UIPage::class, 'isMainSettingsTab' ], [ UIPage::class, 'isTroubleshooting' ] ] ) )
->then( Either::fromBool() )
->then( [ self::class, 'getData' ] )
->then( Resources::enqueueApp( 'settings' ) );
}
public static function getData() {
return [
'name' => 'wpmlSettingsUI',
'data' => [
'endpoints' => [
'getCount' => GetNumberOfPosts::class,
'setAutomatic' => SetForPostType::class,
],
'shouldTranslateEverything' => Option::shouldTranslateEverything(),
'settingsUrl' => admin_url( UIPage::getSettings() ),
'existingPostTypes' => PostTypes::getOnlyTranslatable(),
'isTMLoaded' => ! wpml_is_setup_complete() || Option::isTMAllowed(),
]
];
}
}

View File

@@ -0,0 +1,63 @@
<?php
class WPML_Custom_Field_Setting_Factory extends WPML_TM_User {
public $show_system_fields = false;
/**
* @param string $meta_key
*
* @return WPML_Post_Custom_Field_Setting
*/
public function post_meta_setting( $meta_key ) {
return new WPML_Post_Custom_Field_Setting( $this->tm_instance, $meta_key );
}
/**
* @param string $meta_key
*
* @return WPML_Term_Custom_Field_Setting
*/
public function term_meta_setting( $meta_key ) {
return new WPML_Term_Custom_Field_Setting( $this->tm_instance, $meta_key );
}
/**
* Returns all custom field names for which a site has either a setting
* in the TM settings or that can be found on any post.
*
* @return string[]
*/
public function get_post_meta_keys() {
return $this->filter_custom_field_keys( $this->tm_instance->initial_custom_field_translate_states() );
}
/**
* Returns all term custom field names for which a site has either a setting
* in the TM settings or that can be found on any term.
*
* @return string[]
*/
public function get_term_meta_keys() {
return $this->filter_custom_field_keys( $this->tm_instance->initial_term_custom_field_translate_states() );
}
private function filter_custom_field_key( $custom_fields_key ) {
return $this->show_system_fields || '_' !== substr( $custom_fields_key, 0, 1 );
}
/**
* @param array $keys
*
* @return array
*/
public function filter_custom_field_keys( $keys ) {
if ( is_array( $keys ) ) {
return array_filter( $keys, array( $this, 'filter_custom_field_key' ) );
} else {
return array();
}
}
}

View File

@@ -0,0 +1,97 @@
<?php
class WPML_Custom_Field_Setting_Query_Factory {
const TYPE_POSTMETA = 'postmeta';
const TYPE_TERMMETA = 'termmeta';
public function create( $type ) {
global $wpdb;
if ( self::TYPE_TERMMETA === $type ) {
$excluded_keys = $this->get_excluded_term_meta_keys();
$table = $wpdb->termmeta;
} else {
$excluded_keys = $this->get_excluded_post_meta_keys();
$table = $wpdb->postmeta;
}
return new WPML_Custom_Field_Setting_Query( $wpdb, $excluded_keys, $table );
}
/**
* @return array
*/
private function get_excluded_post_meta_keys() {
return $this->get_excluded_meta_keys(
WPML_Post_Custom_Field_Setting_Keys::get_excluded_keys(),
WPML_Post_Custom_Field_Setting_Keys::get_setting_prefix(),
WPML_Post_Custom_Field_Setting_Keys::get_state_array_setting_index(),
WPML_Post_Custom_Field_Setting_Keys::get_unlocked_setting_index()
);
}
/**
* @return array
*/
private function get_excluded_term_meta_keys() {
return $this->get_excluded_meta_keys(
WPML_Term_Custom_Field_Setting_Keys::get_excluded_keys(),
WPML_Term_Custom_Field_Setting_Keys::get_setting_prefix(),
WPML_Term_Custom_Field_Setting_Keys::get_state_array_setting_index(),
WPML_Term_Custom_Field_Setting_Keys::get_unlocked_setting_index()
);
}
/**
* @param array $hardcoded_excluded_keys
* @param string $settings_prefix
* @param string $settings_state_index
* @param string $settings_unlock_index
*
* @return array
*/
private function get_excluded_meta_keys( array $hardcoded_excluded_keys, $settings_prefix, $settings_state_index, $settings_unlock_index ) {
/** @var TranslationManagement $tm_instance */
$tm_instance = wpml_load_core_tm();
/**
* @see WPML_Custom_Field_Setting::excluded() for the logic ran on a single key
*/
$read_only_keys = isset( $tm_instance->settings[ $settings_prefix . 'read_only' ] )
? $tm_instance->settings[ $settings_prefix . 'read_only' ] : array();
$not_ignore_keys = $this->get_not_ignore_keys( $tm_instance, $settings_state_index );
$unlocked_keys = isset( $tm_instance->settings[ $settings_unlock_index ] )
? $tm_instance->settings[ $settings_unlock_index ] : array();
$read_only_and_ignored_keys = array_diff( $read_only_keys, $not_ignore_keys );
$read_only_and_ignored_and_not_unlocked_keys = array_diff( $read_only_and_ignored_keys, $unlocked_keys );
$excluded_keys = array_merge(
$hardcoded_excluded_keys,
$read_only_and_ignored_and_not_unlocked_keys
);
return $excluded_keys;
}
/**
* @param TranslationManagement $tm_settings
* @param string $index
*
* @return array
*/
private function get_not_ignore_keys( TranslationManagement $tm_settings, $index ) {
$statuses = isset( $tm_settings->settings[ $index ] ) ? $tm_settings->settings[ $index ] : array();
foreach ( $statuses as $meta_key => $status ) {
if ( WPML_IGNORE_CUSTOM_FIELD === (int) $status ) {
unset( $statuses[ $meta_key ] );
}
}
return array_keys( $statuses );
}
}

View File

@@ -0,0 +1,107 @@
<?php
class WPML_Custom_Field_Setting_Query {
/** @var wpdb $wpdb */
private $wpdb;
/** @var array $excluded_keys */
private $excluded_keys;
/** @var string $table */
private $table;
/**
* @param wpdb $wpdb
* @param array $excluded_keys
* @param string $table
*/
public function __construct( wpdb $wpdb, array $excluded_keys, $table ) {
$this->wpdb = $wpdb;
$this->excluded_keys = $excluded_keys;
$this->table = $table;
}
/**
* @param array $args
*
* @return array
*/
public function get( array $args ) {
$args = array_merge(
array(
'search' => null,
'hide_system_fields' => false,
'items_per_page' => null,
'page' => null,
),
$args
);
$where = ' WHERE 1=1';
$where .= $this->add_AND_excluded_fields_condition();
$where .= $this->add_AND_search_condition( $args['search'] );
$where .= $this->add_AND_system_fields_condition( $args['hide_system_fields'] );
$limit_offset = $this->get_limit_offset( $args );
$query = "SELECT SQL_CALC_FOUND_ROWS DISTINCT meta_key FROM {$this->table}" . $where . $limit_offset;
return $this->wpdb->get_col( $query );
}
/**
* @return int
*/
public function get_total_rows() {
return (int) $this->wpdb->get_var( 'SELECT FOUND_ROWS();' );
}
/**
* @return string
*/
private function add_AND_excluded_fields_condition() {
if ( $this->excluded_keys ) {
return ' AND meta_key NOT IN(' . wpml_prepare_in( $this->excluded_keys ) . ')';
}
return '';
}
/**
* @param string $search
*
* @return string
*/
private function add_AND_search_condition( $search ) {
return $search ? $this->wpdb->prepare( " AND meta_key LIKE '%s'", '%' . $search . '%' ) : '';
}
/**
* @param bool $hide_system_fields
*
* @return string
*/
private function add_AND_system_fields_condition( $hide_system_fields ) {
return $hide_system_fields ? " AND meta_key NOT LIKE '\_%'" : '';
}
/**
* @param array $args
*
* @return string
*/
private function get_limit_offset( array $args ) {
$limit_offset = '';
if ( $args['items_per_page'] && 0 < (int) $args['page'] ) {
$limit_offset = $this->wpdb->prepare(
' LIMIT %d OFFSET %d',
$args['items_per_page'],
( $args['page'] - 1 ) * $args['items_per_page']
);
}
return $limit_offset;
}
}

View File

@@ -0,0 +1,208 @@
<?php
use WPML\FP\Logic;
abstract class WPML_Custom_Field_Setting extends WPML_TM_User {
/** @var string $index */
private $index;
/**
* WPML_Custom_Field_Setting constructor.
*
* @param TranslationManagement $tm_instance
* @param string $index
*/
public function __construct( &$tm_instance, $index ) {
parent::__construct( $tm_instance );
$this->index = $index;
}
/**
* @return bool true if the custom field setting is given by a setting in
* a wpml-config.xml
*/
public function is_read_only() {
return in_array(
$this->index,
$this->tm_instance->settings[ $this->get_array_setting_index( 'readonly_config' ) ],
true
);
}
/**
* @return bool
*/
public function is_unlocked() {
return isset( $this->tm_instance->settings[ $this->get_unlocked_setting_index() ][ $this->index ] ) &&
(bool) $this->tm_instance->settings[ $this->get_unlocked_setting_index() ][ $this->index ];
}
/**
* @return bool
*/
public function excluded() {
return in_array( $this->index, $this->get_excluded_keys() ) ||
( $this->is_read_only() &&
$this->status() === WPML_IGNORE_CUSTOM_FIELD &&
! $this->is_unlocked()
);
}
public function status() {
$state_index = $this->get_state_array_setting_index();
if ( ! isset( $this->tm_instance->settings[ $state_index ][ $this->index ] ) ) {
$this->tm_instance->settings[ $state_index ][ $this->index ] = WPML_IGNORE_CUSTOM_FIELD;
}
return (int) $this->tm_instance->settings[ $state_index ][ $this->index ];
}
public function make_read_only() {
$ro_index = $this->get_array_setting_index( 'readonly_config' );
$this->tm_instance->settings[ $ro_index ][] = $this->index;
$this->tm_instance->settings[ $ro_index ] = array_unique( $this->tm_instance->settings[ $ro_index ] );
}
public function set_to_copy() {
$this->set_state( WPML_COPY_CUSTOM_FIELD );
}
public function set_to_copy_once() {
$this->set_state( WPML_COPY_ONCE_CUSTOM_FIELD );
}
public function set_to_translatable() {
$this->set_state( WPML_TRANSLATE_CUSTOM_FIELD );
}
public function set_to_nothing() {
$this->set_state( WPML_IGNORE_CUSTOM_FIELD );
}
public function set_editor_style( $style ) {
$this->tm_instance->settings[ $this->get_array_setting_index( 'editor_style' ) ][ $this->index ] = $style;
}
public function get_editor_style() {
$setting = $this->get_array_setting_index( 'editor_style' );
return isset( $this->tm_instance->settings[ $setting ][ $this->index ] ) ? $this->tm_instance->settings[ $setting ][ $this->index ] : '';
}
public function set_editor_label( $label ) {
$this->tm_instance->settings[ $this->get_array_setting_index( 'editor_label' ) ][ $this->index ] = $label;
}
public function get_editor_label() {
$setting = $this->get_array_setting_index( 'editor_label' );
return isset( $this->tm_instance->settings[ $setting ][ $this->index ] ) ? $this->tm_instance->settings[ $setting ][ $this->index ] : '';
}
public function set_editor_group( $group ) {
$this->tm_instance->settings[ $this->get_array_setting_index( 'editor_group' ) ][ $this->index ] = $group;
}
public function get_editor_group() {
$setting = $this->get_array_setting_index( 'editor_group' );
return isset( $this->tm_instance->settings[ $setting ][ $this->index ] ) ? $this->tm_instance->settings[ $setting ][ $this->index ] : '';
}
public function set_translate_link_target( $state, $sub_fields ) {
if ( isset( $sub_fields['value'] ) ) {
// it's a single sub field
$sub_fields = array( $sub_fields );
}
$this->tm_instance->settings[ $this->get_array_setting_index( 'translate_link_target' ) ][ $this->index ] = array(
'state' => $state,
'sub_fields' => $sub_fields,
);
}
public function is_translate_link_target() {
$array_index = $this->get_array_setting_index( 'translate_link_target' );
return isset( $this->tm_instance->settings[ $array_index ][ $this->index ] ) ?
( $this->tm_instance->settings[ $array_index ][ $this->index ]['state'] ||
$this->get_translate_link_target_sub_fields() ) :
false;
}
public function get_translate_link_target_sub_fields() {
$array_index = $this->get_array_setting_index( 'translate_link_target' );
return isset( $this->tm_instance->settings[ $array_index ][ $this->index ]['sub_fields'] ) ?
$this->tm_instance->settings[ $array_index ][ $this->index ]['sub_fields'] :
array();
}
public function set_convert_to_sticky( $state ) {
$this->tm_instance->settings[ $this->get_array_setting_index( 'convert_to_sticky' ) ][ $this->index ] = $state;
}
public function is_convert_to_sticky() {
$array_index = $this->get_array_setting_index( 'convert_to_sticky' );
return isset( $this->tm_instance->settings[ $array_index ][ $this->index ] ) ?
$this->tm_instance->settings[ $array_index ][ $this->index ] :
false;
}
public function set_encoding( $encoding ) {
if ( Logic::isNotNull( $encoding ) ) {
$this->tm_instance->settings[ $this->get_array_setting_index( 'encoding' ) ][ $this->index ] = $encoding;
} else {
unset( $this->tm_instance->settings[ $this->get_array_setting_index( 'encoding' ) ][ $this->index ] );
}
}
public function get_encoding() {
$setting = $this->get_array_setting_index( 'encoding' );
return isset( $this->tm_instance->settings[ $setting ][ $this->index ] ) ? $this->tm_instance->settings[ $setting ][ $this->index ] : '';
}
/**
* @param array $whitelist
*/
public function set_attributes_whitelist( $whitelist ) {
if ( ! is_array( $whitelist ) ) {
throw new InvalidArgumentException( '$whitelist should be an array.' );
}
$this->tm_instance->settings[ $this->get_array_setting_index( 'attributes_whitelist' ) ][ $this->index ] = $whitelist;
}
public function get_attributes_whitelist() {
$setting = $this->get_array_setting_index( 'attributes_whitelist' );
return isset( $this->tm_instance->settings[ $setting ][ $this->index ] ) ? $this->tm_instance->settings[ $setting ][ $this->index ] : array();
}
private function set_state( $state ) {
$this->tm_instance->settings[ $this->get_state_array_setting_index() ][ $this->index ] = $state;
}
/**
* @return string
*/
private function get_array_setting_index( $index ) {
return $this->get_setting_prefix() . $index;
}
/**
* @return string
*/
abstract protected function get_state_array_setting_index();
abstract protected function get_unlocked_setting_index();
/**
* @return string[]
*/
abstract protected function get_excluded_keys();
/**
* @return string
*/
abstract protected function get_setting_prefix();
}

View File

@@ -0,0 +1,122 @@
<?php
use WPML\FP\Obj;
class WPML_Custom_Field_XML_Settings_Import {
/** @var WPML_Custom_Field_Setting_Factory $setting_factory */
private $setting_factory;
/** @var array $settings_array */
private $settings_array;
/**
* WPML_Custom_Field_XML_Settings_Import constructor.
*
* @param WPML_Custom_Field_Setting_Factory $setting_factory
* @param array $settings_array
*/
public function __construct( $setting_factory, $settings_array ) {
$this->setting_factory = $setting_factory;
$this->settings_array = $settings_array;
}
/**
* Runs the actual import of the xml
*/
public function run() {
$config = $this->settings_array;
foreach (
array(
'post_meta_setting' => array(
WPML_POST_META_CONFIG_INDEX_PLURAL,
WPML_POST_META_CONFIG_INDEX_SINGULAR
),
'term_meta_setting' => array(
WPML_TERM_META_CONFIG_INDEX_PLURAL,
WPML_TERM_META_CONFIG_INDEX_SINGULAR
)
) as $setting_constructor => $settings
) {
if ( ! empty( $config[ $settings[0] ] ) ) {
$field = $config[ $settings[0] ][ $settings[1] ];
$cf = ! is_numeric( key( current( $config[ $settings[0] ] ) ) ) ? array( $field ) : $field;
foreach ( $cf as $c ) {
$setting = call_user_func_array( array(
$this->setting_factory,
$setting_constructor
), array( trim( $c['value'] ) ) );
$this->import_action( $c, $setting );
$setting->make_read_only();
$this->import_editor_settings( $c, $setting );
if ( isset( $c[ 'attr' ][ 'translate_link_target' ] ) || isset( $c[ 'custom-field' ] ) ) {
$setting->set_translate_link_target( isset( $c[ 'attr' ][ 'translate_link_target' ] ) ? (bool) $c[ 'attr' ][ 'translate_link_target' ] : false, isset( $c[ 'custom-field' ] ) ? $c[ 'custom-field' ] : array() );
}
if ( isset( $c[ 'attr' ][ 'convert_to_sticky' ] ) ) {
$setting->set_convert_to_sticky( (bool) $c[ 'attr' ][ 'convert_to_sticky' ] );
}
$setting->set_encoding( Obj::path( [ 'attr', 'encoding' ], $c ) );
}
}
}
$this->import_custom_field_texts();
}
private function import_action( $c, $setting ) {
if ( ! $setting->is_unlocked() ) {
switch ( $c['attr']['action'] ) {
case 'translate':
$setting->set_to_translatable();
break;
case 'copy':
$setting->set_to_copy();
break;
case 'copy-once':
$setting->set_to_copy_once();
break;
default:
$setting->set_to_nothing();
break;
}
}
}
private function import_editor_settings( $c, $setting ) {
if ( isset( $c[ 'attr' ][ 'style' ] ) ) {
$setting->set_editor_style( $c[ 'attr' ][ 'style' ] );
}
if ( isset( $c[ 'attr' ][ 'label' ] ) ) {
$setting->set_editor_label( $c[ 'attr' ][ 'label' ] );
}
if ( isset( $c[ 'attr' ][ 'group' ] ) ) {
$setting->set_editor_group( $c[ 'attr' ][ 'group' ] );
}
}
private function import_custom_field_texts() {
$config = $this->settings_array;
if ( isset( $config['custom-fields-texts']['key'] ) ) {
foreach( $config['custom-fields-texts']['key'] as $field ) {
$setting = $this->setting_factory->post_meta_setting( $field['attr']['name'] );
$setting->set_attributes_whitelist( $this->get_custom_field_texts_keys( $field['key'] ) );
}
}
}
private function get_custom_field_texts_keys( $data ) {
if ( isset( $data['attr'] ) ) { // single
$data = array( $data );
}
$sub_fields = array();
foreach( $data as $key ) {
$sub_fields[ $key['attr']['name'] ] = isset( $key['key'] ) ? $this->get_custom_field_texts_keys( $key['key'] ) : array();
}
return $sub_fields;
}
}

View File

@@ -0,0 +1,39 @@
<?php
class WPML_Element_Sync_Settings_Factory {
const POST = 'post';
const TAX = 'taxonomy';
const KEY_POST_SYNC_OPTION = 'custom_posts_sync_option';
const KEY_TAX_SYNC_OPTION = 'taxonomies_sync_option';
/**
* @param string $type
*
* @return WPML_Element_Sync_Settings
* @throws Exception
*/
public static function create( $type ) {
/** @var SitePress $sitepress */
global $sitepress;
if ( self::POST === $type ) {
$settings = $sitepress->get_setting( self::KEY_POST_SYNC_OPTION, array() );
} elseif ( self::TAX === $type ) {
$settings = $sitepress->get_setting( self::KEY_TAX_SYNC_OPTION, array() );
} else {
throw new Exception( 'Unknown element type.' );
}
return new WPML_Element_Sync_Settings( $settings );
}
public static function createPost() {
return self::create( self::POST );
}
public static function createTax() {
return self::create( self::TAX );
}
}

View File

@@ -0,0 +1,25 @@
<?php
class WPML_Element_Sync_Settings {
/** @var array $settings */
private $settings;
public function __construct( array $settings ) {
$this->settings = $settings;
}
/**
* @param string $type
*
* @return bool
*/
public function is_sync( $type ) {
return isset( $this->settings[ $type ] ) &&
(
$this->settings[ $type ] == WPML_CONTENT_TYPE_TRANSLATE ||
$this->settings[ $type ] == WPML_CONTENT_TYPE_DISPLAY_AS_IF_TRANSLATED
);
}
}

View File

@@ -0,0 +1,48 @@
<?php
class WPML_Page_Builder_Settings {
const OPTION_KEY = 'wpml_page_builders_options';
private $settings;
/** @return bool */
public function is_raw_html_translatable() {
return (bool) $this->get_setting( 'translate_raw_html', true );
}
/** @param bool $is_enabled */
public function set_raw_html_translatable( $is_enabled ) {
$this->set_setting( 'translate_raw_html', $is_enabled );
}
/**
* @param string $key
* @param mixed $value
*/
private function set_setting( $key, $value ) {
$this->settings[ $key ] = $value;
}
/**
* @param string $key
* @param mixed $default
*
* @return mixed
*/
private function get_setting( $key, $default = null ) {
if ( null === $this->settings ) {
$this->settings = get_option( self::OPTION_KEY, array() );
}
if ( array_key_exists( $key, $this->settings ) ) {
return $this->settings[ $key ];
}
return $default;
}
public function save() {
update_option( self::OPTION_KEY, $this->settings );
}
}

View File

@@ -0,0 +1,49 @@
<?php
class WPML_Post_Custom_Field_Setting_Keys {
/**
* @return string
*/
public static function get_state_array_setting_index() {
return 'custom_fields_translation';
}
/**
* @return string
*/
public static function get_unlocked_setting_index() {
return defined( 'WPML_POST_META_UNLOCKED_SETTING_INDEX' )
? WPML_POST_META_UNLOCKED_SETTING_INDEX
: 'custom_fields_unlocked_config';
}
/**
* @return string
*/
public static function get_setting_prefix() {
return 'custom_fields_';
}
/**
* @return string[]
*/
public static function get_excluded_keys() {
return array(
'_edit_last',
'_edit_lock',
'_wp_page_template',
'_wp_attachment_metadata',
'_icl_translator_note',
'_alp_processed',
'_pingme',
'_encloseme',
'_icl_lang_duplicate_of',
'_wpml_media_duplicate',
'wpml_media_processed',
'_wpml_media_featured',
'_thumbnail_id'
);
}
}

View File

@@ -0,0 +1,32 @@
<?php
class WPML_Post_Custom_Field_Setting extends WPML_Custom_Field_Setting {
/**
* @return string
*/
protected function get_state_array_setting_index() {
return WPML_Post_Custom_Field_Setting_Keys::get_state_array_setting_index();
}
/**
* @return string
*/
protected function get_unlocked_setting_index() {
return WPML_Post_Custom_Field_Setting_Keys::get_unlocked_setting_index();
}
/**
* @return string
*/
protected function get_setting_prefix() {
return WPML_Post_Custom_Field_Setting_Keys::get_setting_prefix();
}
/**
* @return string[]
*/
protected function get_excluded_keys() {
return WPML_Post_Custom_Field_Setting_Keys::get_excluded_keys();
}
}

View File

@@ -0,0 +1,41 @@
<?php
/**
* @author OnTheGo Systems
*/
class WPML_Settings_Filters {
/**
* @param array $types
* @param array $read_only_cpt_settings
* @param array $cpt_unlocked_options
*
* @return array
* @see \WPML_Config::maybe_add_filter
*/
function get_translatable_documents( array $types, array $read_only_cpt_settings, array $cpt_unlocked_options ) {
global $wp_post_types;
foreach ( $read_only_cpt_settings as $cp => $translate ) {
if ( $this->is_cpt_unlocked( $cpt_unlocked_options, $cp ) ) {
continue;
}
if ( $translate && ! isset( $types[ $cp ] ) && isset( $wp_post_types[ $cp ] ) ) {
$types[ $cp ] = $wp_post_types[ $cp ];
} elseif ( ! $translate && isset( $types[ $cp ] ) ) {
unset( $types[ $cp ] );
}
}
return $types;
}
/**
* @param array $cpt_unlocked_options
* @param string $cp
*
* @return bool
*/
private function is_cpt_unlocked( array $cpt_unlocked_options, $cp ) {
return isset( $cpt_unlocked_options[ $cp ] ) && (bool) $cpt_unlocked_options[ $cp ];
}
}

View File

@@ -0,0 +1,32 @@
<?php
class WPML_Term_Custom_Field_Setting_Keys {
/**
* @return string
*/
public static function get_state_array_setting_index() {
return WPML_TERM_META_SETTING_INDEX_PLURAL;
}
/**
* @return string
*/
public static function get_unlocked_setting_index() {
return WPML_TERM_META_UNLOCKED_SETTING_INDEX;
}
/**
* @return string
*/
public static function get_setting_prefix() {
return 'custom_term_fields_';
}
/**
* @return string[]
*/
public static function get_excluded_keys() {
return array();
}
}

View File

@@ -0,0 +1,32 @@
<?php
class WPML_Term_Custom_Field_Setting extends WPML_Custom_Field_Setting {
/**
* @return string
*/
protected function get_state_array_setting_index() {
return WPML_Term_Custom_Field_Setting_Keys::get_state_array_setting_index();
}
/**
* @return string
*/
protected function get_unlocked_setting_index() {
return WPML_Term_Custom_Field_Setting_Keys::get_unlocked_setting_index();
}
/**
* @return string
*/
protected function get_setting_prefix() {
return WPML_Term_Custom_Field_Setting_Keys::get_setting_prefix();
}
/**
* @return string[]
*/
protected function get_excluded_keys() {
return WPML_Term_Custom_Field_Setting_Keys::get_excluded_keys();
}
}

View File

@@ -0,0 +1,12 @@
<?php
class WPML_TM_Serialized_Custom_Field_Package_Handler_Factory implements IWPML_Backend_Action_Loader {
public function create() {
$translation_management = wpml_load_core_tm();
return new WPML_TM_Serialized_Custom_Field_Package_Handler(
new WPML_Custom_Field_Setting_Factory( $translation_management )
);
}
}

View File

@@ -0,0 +1,101 @@
<?php
class WPML_TM_Serialized_Custom_Field_Package_Handler {
/** @var WPML_Custom_Field_Setting_Factory $custom_field_setting_factory */
private $custom_field_setting_factory;
public function __construct( WPML_Custom_Field_Setting_Factory $custom_field_setting_factory ) {
$this->custom_field_setting_factory = $custom_field_setting_factory;
}
public function add_hooks() {
add_filter(
'wpml_translation_job_post_meta_value_translated',
array(
$this,
'translate_only_whitelisted_attributes',
),
10,
2
);
}
/**
* @param int $translated
* @param string $custom_field_job_type - e.g: field-my_custom_field-0-my_attribute.
*
* @return int
*/
public function translate_only_whitelisted_attributes( $translated, $custom_field_job_type ) {
if ( $translated ) {
list( $custom_field, $attributes ) = WPML_TM_Field_Type_Encoding::decode( $custom_field_job_type );
if ( $custom_field && $attributes ) {
$settings = $this->custom_field_setting_factory->post_meta_setting( $custom_field );
$attributes_whitelist = $settings->get_attributes_whitelist();
if ( $attributes_whitelist ) {
$translated = $this->match_in_order( $attributes, $attributes_whitelist ) ? $translated : 0;
}
}
}
return $translated;
}
/**
* Matches the attributes array to the whitelist array
* The whitelist array has the attribute as the key to another array for sub keys
* eg. array( 'attribute1' => array( 'subkey1' => array() ) )
*
* @param array $attributes - The attributes in the custom field.
* @param array $whitelist - The whitelist attributes to match against.
* @param int $current_depth - The current depth in the attributes array.
*
* @return bool
*/
private function match_in_order( $attributes, $whitelist, $current_depth = 0 ) {
$current_attribute = $attributes[ $current_depth ];
$wildcard_match = $this->match_with_wildcards( $current_attribute, array_keys( $whitelist ) );
if ( $wildcard_match ) {
if ( count( $attributes ) === $current_depth + 1 ) {
return true;
} else {
return $this->match_in_order( $attributes, $whitelist[ $wildcard_match ], $current_depth + 1 );
}
}
return false;
}
/**
* Matches the attribute to the whitelist array using wildcards.
* Wildcards can only be used at the end of the string.
* eg. 'title-*', 'data*', '*'
* A '*' matches everything.
*
* @param string $attribute - the current attributes.
* @param array $whitelist - the whitelist to match against.
*
* @return string - Returns the whitelist string match.
*/
private function match_with_wildcards( $attribute, $whitelist ) {
foreach ( $whitelist as $white_value ) {
$asterisk_pos = strpos( $white_value, '*' );
if ( false === $asterisk_pos ) {
if ( $attribute === $white_value ) {
return $white_value;
}
} else {
if (
0 === $asterisk_pos ||
substr( $attribute, 0, $asterisk_pos ) === substr( $white_value, 0, $asterisk_pos )
) {
return $white_value;
}
}
}
return '';
}
}

View File

@@ -0,0 +1,46 @@
<?php
class WPML_TM_Settings_Post_Process extends WPML_TM_User {
/**
* Saves TM settings to the database in case they have changed after reading a config file.
*/
public function run() {
$changed = false;
$settings = &$this->tm_instance->settings;
foreach (
array(
WPML_POST_META_READONLY_SETTING_INDEX,
WPML_TERM_META_READONLY_SETTING_INDEX,
WPML_POST_TYPE_READONLY_SETTING_INDEX
) as $index
) {
$prev_index = $this->prev_index( $index );
if ( isset( $settings[ $index ] ) && isset( $settings[ $prev_index ] ) ) {
foreach (
array(
$index => $prev_index,
$prev_index => $index
) as $left_index => $right_index
) {
foreach ( $settings[ $right_index ] as $cf ) {
if ( ! in_array( $cf,
$settings[ $left_index ] )
) {
$changed = true;
break;
}
}
}
}
}
if ( $changed ) {
$this->tm_instance->save_settings();
}
}
private function prev_index( $index ) {
return '__' . $index . '_prev';
}
}

View File

@@ -0,0 +1,121 @@
<?php
use WPML\FP\Obj;
class WPML_TM_Settings_Update extends WPML_SP_User {
private $index_singular;
private $index_ro;
private $index_sync;
private $index_plural;
private $index_unlocked;
/** @var TranslationManagement $tm_instance */
private $tm_instance;
/** @var WPML_Settings_Helper $settings_helper */
private $settings_helper;
/**
* @param string $index_singular
* @param string $index_plural
* @param TranslationManagement $tm_instance
* @param SitePress $sitepress
* @param WPML_Settings_Helper $settings_helper
*/
public function __construct( $index_singular, $index_plural, &$tm_instance, &$sitepress, $settings_helper ) {
parent::__construct( $sitepress );
$this->tm_instance = &$tm_instance;
$this->index_singular = $index_singular;
$this->index_plural = $index_plural;
$this->index_ro = $index_plural . '_readonly_config';
$this->index_sync = $index_plural . '_sync_option';
$this->index_unlocked = 'custom-type' == $index_singular ? 'custom_posts_unlocked_option' : 'taxonomies_unlocked_option';
$this->settings_helper = $settings_helper;
}
/**
* @param array $config
*/
public function update_from_config( array $config ) {
$this->update_tm_settings( Obj::propOr( [], $this->index_plural, $config ) );
}
private function sync_settings( array $config ) {
$section_singular = $this->index_singular;
$section_plural = $this->index_plural;
if ( ! empty( $config[ $section_singular ] ) ) {
$sync_option = $this->sitepress->get_setting( $this->index_sync, [] );
$unlocked_option = $this->sitepress->get_setting( $this->index_unlocked, [] );
if ( ! is_numeric( key( current( $config ) ) ) ) {
$cf[0] = $config[ $section_singular ];
} else {
$cf = $config[ $section_singular ];
}
foreach ( $cf as $c ) {
$val = $c['value'];
if ( ! $this->is_unlocked_type( $val, $unlocked_option ) ) {
$sync_existing_setting = isset( $sync_option[ $val ] ) ? $sync_option[ $val ] : false;
$sync_new_setting = (int) $c['attr']['translate'];
$this->tm_instance->settings[ $this->index_ro ][ $val ] = $sync_new_setting;
$sync_option[ $val ] = $sync_new_setting;
if ( $this->is_making_type_translatable( $sync_new_setting, $sync_existing_setting ) ) {
if ( $section_plural === 'taxonomies' ) {
$this->sitepress->verify_taxonomy_translations( $val );
} else {
$this->sitepress->verify_post_translations( $val );
}
$this->tm_instance->save_settings();
}
}
}
$this->sitepress->set_setting( $this->index_sync, $sync_option );
$this->settings_helper->maybe_add_filter( $section_plural );
}
}
/**
* @param int $new_sync 0, 1 or 2
* @param int $old_sync 0, 1 or 2
*
* @return bool
*/
private function is_making_type_translatable( $new_sync, $old_sync ) {
return in_array(
$new_sync,
[
WPML_CONTENT_TYPE_TRANSLATE,
WPML_CONTENT_TYPE_DISPLAY_AS_IF_TRANSLATED,
]
) && WPML_CONTENT_TYPE_DONT_TRANSLATE === $old_sync;
}
private function update_tm_settings( array $config ) {
$section_singular = $this->index_singular;
$config = array_filter( $config );
$config[ $section_singular ] = Obj::propOr( [], $section_singular, $config );
$this->sync_settings( $config );
// taxonomies - check what's been removed
if ( ! empty( $this->tm_instance->settings[ $this->index_ro ] ) ) {
$config_values = [];
foreach ( $config[ $section_singular ] as $config_value ) {
$config_values[ $config_value['value'] ] = $config_value['attr']['translate'];
}
foreach ( $this->tm_instance->settings[ $this->index_ro ] as $key => $translation_option ) {
if ( ! isset( $config_values[ $key ] ) ) {
unset( $this->tm_instance->settings[ $this->index_ro ][ $key ] );
}
}
$this->tm_instance->save_settings();
}
}
private function is_unlocked_type( $type, $unlocked_options ) {
return isset( $unlocked_options[ $type ] ) && $unlocked_options[ $type ];
}
}

View File

@@ -0,0 +1,116 @@
<?php
/**
* Created by PhpStorm.
* User: bruce
* Date: 5/10/17
* Time: 10:23 PM
*/
class WPML_Verify_SitePress_Settings {
/** @var WPML_WP_API $wp_api */
private $wp_api;
public function __construct( WPML_WP_API $wp_api ) {
$this->wp_api = $wp_api;
}
/**
* @param array $settings
*
* @return array
*/
public function verify( $settings ) {
$default_settings = [
'interview_translators' => 1,
'existing_content_language_verified' => 0,
'language_negotiation_type' => 1,
'icl_lso_link_empty' => 0,
'sync_page_ordering' => 1,
'sync_page_parent' => 1,
'sync_page_template' => 1,
'sync_ping_status' => 1,
'sync_comment_status' => 1,
'sync_sticky_flag' => 1,
'sync_password' => 1,
'sync_private_flag' => 1,
'sync_post_format' => 1,
'sync_delete' => 0,
'sync_delete_tax' => 0,
'sync_post_taxonomies' => 1,
'sync_post_date' => 1,
'sync_taxonomy_parents' => 0,
'translation_pickup_method' => 0,
'notify_complete' => 1,
'translated_document_status' => 1,
'remote_management' => 0,
'auto_adjust_ids' => 1,
'alert_delay' => 0,
'promote_wpml' => 0,
'automatic_redirect' => 0,
'remember_language' => 24,
'icl_lang_sel_copy_parameters' => '',
'translated_document_page_url' => 'auto-generate',
'sync_comments_on_duplicates' => 0,
'seo' => [
'head_langs' => 1,
'canonicalization_duplicates' => 1,
'head_langs_priority' => 1,
],
'posts_slug_translation' => [
/** @deprected key `on`, use option `wpml_base_slug_translation` instead */
'on' => 1,
],
'languages_order' => [],
'urls' => [
'directory_for_default_language' => 0,
'show_on_root' => '',
'root_html_file_path' => '',
'root_page' => 0,
'hide_language_switchers' => 1,
],
'xdomain_data' => $this->wp_api->constant( 'WPML_XDOMAIN_DATA_GET' ),
'custom_posts_sync_option' => [
'post' => WPML_CONTENT_TYPE_TRANSLATE,
'page' => WPML_CONTENT_TYPE_TRANSLATE,
],
'taxonomies_sync_option' => [
'category' => WPML_CONTENT_TYPE_TRANSLATE,
'post_tag' => WPML_CONTENT_TYPE_TRANSLATE,
],
'tm_block_retranslating_terms' => 1,
];
// configured for three levels
$update_settings = false;
foreach ( $default_settings as $key => $value ) {
if ( is_array( $value ) ) {
foreach ( $value as $k2 => $v2 ) {
if ( is_array( $v2 ) ) {
foreach ( $v2 as $k3 => $v3 ) {
if ( ! isset( $settings[ $key ][ $k2 ][ $k3 ] ) ) {
$settings[ $key ][ $k2 ][ $k3 ] = $v3;
$update_settings = true;
}
}
} else {
if ( ! isset( $settings[ $key ][ $k2 ] ) ) {
$settings[ $key ][ $k2 ] = $v2;
$update_settings = true;
}
}
}
} else {
if ( ! isset( $settings[ $key ] ) ) {
$settings[ $key ] = $value;
$update_settings = true;
}
}
}
return [ $settings, $update_settings ];
}
}

View File

@@ -0,0 +1,11 @@
<?php
class WPML_TM_Default_Settings_Factory implements IWPML_Frontend_Action_Loader, IWPML_Backend_Action_Loader {
public function create() {
/** @var TranslationManagement */
global $iclTranslationManagement;
return new WPML_TM_Default_Settings( $iclTranslationManagement );
}
}

View File

@@ -0,0 +1,75 @@
<?php
class WPML_TM_Default_Settings implements IWPML_Action {
/** @var TranslationManagement */
private $tm;
public function __construct( TranslationManagement $tm ) {
$this->tm = $tm;
}
public function add_hooks() {
add_action( 'init', array( $this, 'init_action' ), $this->tm->get_init_priority() );
}
public function init_action() {
$this->maybe_update_notification( 'new-job', WPML_TM_Emails_Settings::NOTIFY_IMMEDIATELY );
$this->maybe_update_notification( 'include_xliff', (int) apply_filters( 'wpml_setting', 0, 'include_xliff_in_notification' ) );
if ( ! $this->has_notification( WPML_TM_Emails_Settings::COMPLETED_JOB_FREQUENCY ) ) {
if ( $this->has_notification( 'completed' ) ) {
$this->update_notification( WPML_TM_Emails_Settings::COMPLETED_JOB_FREQUENCY, $this->get_notification( 'completed' ) );
} else {
$this->update_notification( WPML_TM_Emails_Settings::COMPLETED_JOB_FREQUENCY, WPML_TM_Emails_Settings::NOTIFY_WEEKLY );
}
}
$this->maybe_update_notification( 'completed', WPML_TM_Emails_Settings::NOTIFY_IMMEDIATELY );
$this->maybe_update_notification( 'resigned', WPML_TM_Emails_Settings::NOTIFY_IMMEDIATELY );
$this->maybe_update_notification( 'overdue', WPML_TM_Emails_Settings::NOTIFY_IMMEDIATELY );
$this->maybe_update_notification( 'overdue_offset', 7 );
$this->maybe_update_notification( 'dashboard', true );
$this->maybe_update_notification( 'purge-old', 7 );
}
/**
* @param string $key
* @param mixed $default
*
* @return bool
*/
private function get_notification( $key, $default = null ) {
return isset( $this->tm->settings['notification'][ $key ] )
? $this->tm->settings['notification'][ $key ]
: $default;
}
/**
* @param string $key
*
* @return bool
*/
private function has_notification( $key ) {
return isset( $this->tm->settings['notification'][ $key ] );
}
/**
* @param string $key
* @param mixed $value
*/
private function maybe_update_notification( $key, $value ) {
if ( ! $this->has_notification( $key ) ) {
$this->update_notification( $key, $value );
}
}
/**
* @param string $key
* @param mixed $value
*/
private function update_notification( $key, $value ) {
$this->tm->settings['notification'][ $key ] = $value;
}
}