first commit
This commit is contained in:
@@ -0,0 +1,158 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\Utils;
|
||||
|
||||
use SitePress;
|
||||
use WPML_WP_API;
|
||||
|
||||
class AutoAdjustIds {
|
||||
const WITH = true;
|
||||
const WITHOUT = false;
|
||||
|
||||
/** @var SitePress $sitepress */
|
||||
private $sitepress;
|
||||
|
||||
/** @var WPML_WP_API $wp */
|
||||
private $wp;
|
||||
|
||||
/**
|
||||
* @param SitePress $sitepress
|
||||
* @param WPML_WP_API $wp
|
||||
*/
|
||||
public function __construct(
|
||||
SitePress $sitepress,
|
||||
WPML_WP_API $wp = null
|
||||
) {
|
||||
$this->sitepress = $sitepress;
|
||||
$this->wp = $wp ?: $sitepress->get_wp_api();
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables adjusting ids to retrieve translated post instead of original, runs
|
||||
* the given $function and afterwards restore the original behaviour again.
|
||||
*
|
||||
* @param callable $function
|
||||
*/
|
||||
public function runWith( callable $function ) {
|
||||
return $this->runWithOrWithout( self::WITH, $function );
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables adjusting ids to retrieve translated post instead of original, runs
|
||||
* the given $function and afterwards restore the original behaviour again.
|
||||
*
|
||||
* @param callable $function
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function runWithout( callable $function ) {
|
||||
return $this->runWithOrWithout( self::WITHOUT, $function );
|
||||
}
|
||||
|
||||
private function runWithOrWithout( $withOrWithout, callable $function ) {
|
||||
// Enable / Disable adjusting of ids.
|
||||
$adjust_id_original_state =
|
||||
$this->adjustSettingAutoAdjustId( $withOrWithout );
|
||||
$get_term_original_state =
|
||||
$this->adjustGetTermFilter( $withOrWithout );
|
||||
$get_page_original_state =
|
||||
$this->adjustGetPagesFilter( $withOrWithout );
|
||||
|
||||
// Run given $function.
|
||||
$result = $function();
|
||||
|
||||
// Restore previous behaviour.
|
||||
$this->adjustSettingAutoAdjustId( $adjust_id_original_state );
|
||||
$this->adjustGetTermFilter( $get_term_original_state );
|
||||
$this->adjustGetPagesFilter( $get_page_original_state );
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjusts setting 'auto_adjust_ids' to enable or disable.
|
||||
* It will only be switched if the setting differs from the current state
|
||||
* of the setting.
|
||||
*
|
||||
* @param bool $enable
|
||||
*
|
||||
* @return bool The state of the setting before adjusting it.
|
||||
*/
|
||||
private function adjustSettingAutoAdjustId( $enable = true ) {
|
||||
$is_setting_enabled =
|
||||
$this->sitepress->get_setting( 'auto_adjust_ids', false );
|
||||
|
||||
if ( $enable !== $is_setting_enabled ) {
|
||||
$this->sitepress->set_setting( 'auto_adjust_ids', $enable );
|
||||
}
|
||||
|
||||
return $is_setting_enabled;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add or remove to filter 'get_term' SitePress::get_term_adjust_id().
|
||||
* It will only be added/removed if the current state differs from
|
||||
* expected.
|
||||
*
|
||||
* @param bool $add_filter
|
||||
*
|
||||
* @return bool The state of callback being added before adjusting it.
|
||||
*/
|
||||
private function adjustGetTermFilter( $add_filter = true ) {
|
||||
$is_filter_added =
|
||||
$this->wp->has_filter(
|
||||
'get_term',
|
||||
[ $this->sitepress, 'get_term_adjust_id' ]
|
||||
);
|
||||
|
||||
if ( $add_filter !== $is_filter_added ) {
|
||||
// State differs. Add/Remove filter callback.
|
||||
$add_filter ? $this->wp->add_filter(
|
||||
'get_term',
|
||||
[ $this->sitepress, 'get_term_adjust_id' ],
|
||||
1
|
||||
) : $this->wp->remove_filter(
|
||||
'get_term',
|
||||
[ $this->sitepress, 'get_term_adjust_id' ],
|
||||
1
|
||||
);
|
||||
}
|
||||
|
||||
return $is_filter_added;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add or remove to filter 'get_pages' SitePress::get_pages_adjust_ids().
|
||||
* It will only be added/removed if the current state differs from
|
||||
* expected.
|
||||
*
|
||||
* @param bool $add_filter
|
||||
*
|
||||
* @return bool The state of callback being added before adjusting it.
|
||||
*/
|
||||
private function adjustGetPagesFilter( $add_filter = true ) {
|
||||
$is_filter_added =
|
||||
$this->wp->has_filter(
|
||||
'get_pages',
|
||||
[ $this->sitepress, 'get_pages_adjust_ids' ]
|
||||
);
|
||||
|
||||
if ( $add_filter !== $is_filter_added ) {
|
||||
// State differs. Add/Remove filter callback.
|
||||
$add_filter ? $this->wp->add_filter(
|
||||
'get_pages',
|
||||
[ $this->sitepress, 'get_pages_adjust_ids' ],
|
||||
1,
|
||||
2
|
||||
) : $this->wp->remove_filter(
|
||||
'get_pages',
|
||||
[ $this->sitepress, 'get_pages_adjust_ids' ],
|
||||
1
|
||||
);
|
||||
}
|
||||
|
||||
return $is_filter_added;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\Utils;
|
||||
|
||||
class AutoAdjustIdsFactory {
|
||||
/**
|
||||
* @return AutoAdjustIds
|
||||
*/
|
||||
public static function create() {
|
||||
global $sitepress;
|
||||
|
||||
return new AutoAdjustIds( $sitepress, $sitepress->get_wp_api() );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\Utils;
|
||||
|
||||
use WPML\Collect\Support\Collection;
|
||||
|
||||
class Pager {
|
||||
/** @var string */
|
||||
protected $optionName;
|
||||
|
||||
/** @var int */
|
||||
protected $pageSize;
|
||||
|
||||
/**
|
||||
* @param string $optionName
|
||||
* @param int $pageSize
|
||||
*/
|
||||
public function __construct( $optionName, $pageSize = 10 ) {
|
||||
$this->optionName = $optionName;
|
||||
$this->pageSize = $pageSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection $collection
|
||||
* @param callable $callback
|
||||
* @param int $timeout
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function iterate( Collection $collection, callable $callback, $timeout = PHP_INT_MAX ) {
|
||||
$processedItems = $this->getProcessedCount();
|
||||
|
||||
$this->getItemsToProcess( $collection, $processedItems )->eachWithTimeout(
|
||||
function ( $item ) use (
|
||||
&$processedItems,
|
||||
$callback
|
||||
) {
|
||||
return $callback( $item ) && ++ $processedItems;
|
||||
},
|
||||
$timeout
|
||||
);
|
||||
|
||||
$remainingPages = $this->getRemainingPages( $collection, $processedItems );
|
||||
|
||||
if ( $remainingPages ) {
|
||||
\update_option( $this->optionName, $processedItems );
|
||||
} else {
|
||||
\delete_option( $this->optionName );
|
||||
}
|
||||
|
||||
return $remainingPages;
|
||||
}
|
||||
|
||||
private function getItemsToProcess( Collection $collection, $processedItems ) {
|
||||
return $collection->slice( $processedItems, $this->pageSize );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Collection $collection
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getPagesCount( Collection $collection ) {
|
||||
return (int) ceil( $collection->count() / $this->pageSize );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \WPML\Collect\Support\Collection $collection
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
protected function getRemainingPages( Collection $collection, $processedItems ) {
|
||||
return (int) ceil( $collection->slice( $processedItems )->count() / $this->pageSize );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function getProcessedCount() {
|
||||
return get_option( $this->optionName, 0 );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\Core\WP\App;
|
||||
|
||||
use function WPML\FP\partial;
|
||||
|
||||
class Resources {
|
||||
// enqueueApp :: string $app -> ( string $localizeData )
|
||||
public static function enqueueApp( $app ) {
|
||||
return partial( [ '\WPML\LIB\WP\App\Resources', 'enqueue' ],
|
||||
$app, ICL_PLUGIN_URL, WPML_PLUGIN_PATH, ICL_SITEPRESS_VERSION, 'sitepress'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
class WPML_Admin_URL {
|
||||
|
||||
public static function multilingual_setup( $section = null ) {
|
||||
if ( defined( 'WPML_TM_VERSION' ) ) {
|
||||
$url = admin_url( 'admin.php?page=' . WPML_TM_FOLDER . WPML_Translation_Management::PAGE_SLUG_SETTINGS . '&sm=mcsetup' );
|
||||
} else {
|
||||
$url = admin_url( 'admin.php?page=' . ICL_PLUGIN_FOLDER . '/menu/translation-options.php' );
|
||||
}
|
||||
|
||||
if ( $section ) {
|
||||
$url .= '#ml-content-setup-sec-' . $section;
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
class WPML_Admin_Pagination_Factory {
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $items_per_page;
|
||||
|
||||
public function __construct( $items_per_page ) {
|
||||
$this->items_per_page = $items_per_page;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return WPML_Admin_Pagination_Render
|
||||
*/
|
||||
public function create( $total_items, $page_param_name = 'paged' ) {
|
||||
$pagination = new WPML_Admin_Pagination();
|
||||
$pagination->set_total_items( $total_items );
|
||||
$pagination->set_items_per_page( $this->items_per_page );
|
||||
$pagination->set_page_param_name( $page_param_name );
|
||||
|
||||
$page = 1;
|
||||
if ( isset( $_GET[ $page_param_name ] ) ) {
|
||||
$page = filter_var( $_GET[ $page_param_name ], FILTER_SANITIZE_NUMBER_INT );
|
||||
}
|
||||
$pagination->set_current_page( $page );
|
||||
|
||||
$template = new WPML_Twig_Template_Loader(
|
||||
array(
|
||||
WPML_PLUGIN_PATH . '/templates/pagination',
|
||||
)
|
||||
);
|
||||
|
||||
return new WPML_Admin_Pagination_Render( $template->get_template(), $pagination );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
class WPML_Admin_Pagination_Render {
|
||||
|
||||
const TEMPLATE = 'pagination.twig';
|
||||
|
||||
/**
|
||||
* @var IWPML_Template_Service
|
||||
*/
|
||||
private $template;
|
||||
|
||||
/**
|
||||
* @var WPML_Admin_Pagination
|
||||
*/
|
||||
private $pagination;
|
||||
|
||||
public function __construct( IWPML_Template_Service $template, WPML_Admin_Pagination $pagination ) {
|
||||
$this->template = $template;
|
||||
$this->pagination = $pagination;
|
||||
}
|
||||
|
||||
public function get_model() {
|
||||
return [
|
||||
'strings' => self::get_strings( $this->pagination->get_total_items() ),
|
||||
'pagination' => $this->pagination,
|
||||
'total_items' => $this->pagination->get_total_items(),
|
||||
];
|
||||
}
|
||||
|
||||
public static function get_strings( $totalItems ) {
|
||||
return [
|
||||
'listNavigation' => __( 'Navigation', 'sitepress' ),
|
||||
'firstPage' => __( 'First page', 'sitepress' ),
|
||||
'previousPage' => __( 'Previous page', 'sitepress' ),
|
||||
'nextPage' => __( 'Next page', 'sitepress' ),
|
||||
'lastPage' => __( 'Last page', 'sitepress' ),
|
||||
'currentPage' => __( 'Current page', 'sitepress' ),
|
||||
'of' => __( 'of', 'sitepress' ),
|
||||
'totalItemsText' => sprintf(
|
||||
_n( '%s item', '%s items', $totalItems, 'sitepress' ),
|
||||
$totalItems
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $items
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function paginate( $items ) {
|
||||
$total = count( $items );
|
||||
$limit = $this->pagination->get_items_per_page(); // per page
|
||||
$total_pages = ceil( $total / $limit );
|
||||
$page = max( $this->pagination->get_current_page(), 1 );
|
||||
$page = min( $page, $total_pages );
|
||||
$offset = ( $page - 1 ) * $limit;
|
||||
|
||||
if ( $offset < 0 ) {
|
||||
$offset = 0;
|
||||
}
|
||||
|
||||
return array_slice( $items, $offset, $limit );
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class WPML_Admin_Pagination
|
||||
*
|
||||
* @author OnTheGoSystems
|
||||
*/
|
||||
class WPML_Admin_Pagination {
|
||||
|
||||
/** @var int $items_per_page */
|
||||
private $items_per_page;
|
||||
|
||||
/** @var int $total_items */
|
||||
private $total_items;
|
||||
|
||||
/** @var int $current_page */
|
||||
private $current_page;
|
||||
|
||||
/** @var string $current_url */
|
||||
private $current_url;
|
||||
|
||||
/** @var string */
|
||||
private $page_param_name = 'paged';
|
||||
|
||||
/**
|
||||
* @param string $page_param_name
|
||||
*/
|
||||
public function set_page_param_name( $page_param_name ) {
|
||||
$this->page_param_name = $page_param_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function get_page_param_name() {
|
||||
return $this->page_param_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $items_per_page
|
||||
*/
|
||||
public function set_items_per_page( $items_per_page ) {
|
||||
$this->items_per_page = (int) $items_per_page;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function get_items_per_page() {
|
||||
return $this->items_per_page;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $total_items
|
||||
*/
|
||||
public function set_total_items( $total_items ) {
|
||||
$this->total_items = (int) $total_items;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function get_total_items() {
|
||||
return $this->total_items;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function get_total_pages() {
|
||||
return ceil( $this->get_total_items() / $this->get_items_per_page() );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $page
|
||||
*/
|
||||
public function set_current_page( $page ) {
|
||||
$this->current_page = (int) $page;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function get_current_page() {
|
||||
return $this->current_page;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null|string
|
||||
*/
|
||||
public function get_first_page_url() {
|
||||
$url = null;
|
||||
|
||||
if ( 2 < $this->get_current_page() ) {
|
||||
$url = remove_query_arg( $this->page_param_name, $this->get_current_url() );
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null|string
|
||||
*/
|
||||
public function get_previous_page_url() {
|
||||
$url = null;
|
||||
|
||||
if ( 1 < $this->get_current_page() ) {
|
||||
$url = add_query_arg( $this->page_param_name, $this->get_current_page() - 1, $this->get_current_url() );
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null|string
|
||||
*/
|
||||
public function get_next_page_url() {
|
||||
$url = null;
|
||||
|
||||
if ( $this->get_current_page() < $this->get_total_pages() ) {
|
||||
$url = add_query_arg( $this->page_param_name, $this->get_current_page() + 1, $this->get_current_url() );
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null|string
|
||||
*/
|
||||
public function get_last_page_url() {
|
||||
$url = null;
|
||||
|
||||
if ( $this->get_current_page() < $this->get_total_pages() - 1 ) {
|
||||
$url = add_query_arg( $this->page_param_name, $this->get_total_pages(), $this->get_current_url() );
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
private function get_current_url() {
|
||||
if ( ! $this->current_url ) {
|
||||
$removable_query_args = wp_removable_query_args();
|
||||
$this->current_url = set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
|
||||
$this->current_url = remove_query_arg( $removable_query_args, $this->current_url );
|
||||
}
|
||||
|
||||
return $this->current_url;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
<?php
|
||||
|
||||
class WPML_Admin_Table_Sort {
|
||||
|
||||
/** @var string $primary_column */
|
||||
private $primary_column;
|
||||
|
||||
/** @var string $url_args */
|
||||
private $url_args;
|
||||
|
||||
/** @var string $current_url */
|
||||
private $current_url;
|
||||
|
||||
/** @var string */
|
||||
private $orderby_param;
|
||||
|
||||
/** @var string */
|
||||
private $order_param;
|
||||
|
||||
/**
|
||||
* @param string $orderby_param
|
||||
* @param string $order_param
|
||||
*/
|
||||
public function __construct( $orderby_param = 'orderby', $order_param = 'order' ) {
|
||||
$this->orderby_param = $orderby_param;
|
||||
$this->order_param = $order_param;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $primary_column
|
||||
*/
|
||||
public function set_primary_column( $primary_column ) {
|
||||
$this->primary_column = $primary_column;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $column
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_column_url( $column ) {
|
||||
$query_args = array(
|
||||
$this->orderby_param => $column,
|
||||
$this->order_param => 'desc',
|
||||
);
|
||||
|
||||
if ( $this->get_current_orderby() === $column && $this->get_current_order() === 'desc' ) {
|
||||
$query_args[ $this->order_param ] = 'asc';
|
||||
}
|
||||
|
||||
return add_query_arg( $query_args, $this->get_current_url() );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $column
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_column_classes( $column ) {
|
||||
$classes = 'manage-column column-' . $column;
|
||||
|
||||
if ( $this->is_primary( $column ) ) {
|
||||
$classes .= ' column-primary';
|
||||
}
|
||||
|
||||
if ( $this->get_current_orderby() === $column ) {
|
||||
$classes .= ' sorted ' . $this->get_current_order();
|
||||
} else {
|
||||
$classes .= ' sortable asc';
|
||||
}
|
||||
|
||||
return $classes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $column
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function is_primary( $column ) {
|
||||
return $this->primary_column === $column;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
private function get_current_orderby() {
|
||||
$url_args = $this->get_url_args();
|
||||
return isset( $url_args[ $this->orderby_param ] ) ? $url_args[ $this->orderby_param ] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
private function get_current_order() {
|
||||
$url_args = $this->get_url_args();
|
||||
return isset( $url_args[ $this->order_param ] ) ? $url_args[ $this->order_param ] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function get_current_sorters() {
|
||||
return array(
|
||||
$this->orderby_param => $this->get_current_orderby(),
|
||||
$this->order_param => $this->get_current_order(),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
private function get_url_args() {
|
||||
if ( ! $this->url_args ) {
|
||||
$this->url_args = array();
|
||||
$url_query = wpml_parse_url( $this->get_current_url(), PHP_URL_QUERY );
|
||||
parse_str( $url_query, $this->url_args );
|
||||
}
|
||||
|
||||
return $this->url_args;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
private function get_current_url() {
|
||||
if ( ! $this->current_url ) {
|
||||
$this->current_url = set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
|
||||
$this->current_url = remove_query_arg( 'paged', $this->current_url );
|
||||
}
|
||||
|
||||
return $this->current_url;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\Utils;
|
||||
|
||||
/**
|
||||
* Class DebugBackTrace
|
||||
*
|
||||
* @package WPML\Utils
|
||||
*/
|
||||
class DebugBackTrace {
|
||||
|
||||
/** @var array */
|
||||
private $debug_backtrace = [];
|
||||
|
||||
/** @var int */
|
||||
private $limit;
|
||||
|
||||
/** @var bool */
|
||||
private $provide_object;
|
||||
|
||||
/** @var bool */
|
||||
private $ignore_args;
|
||||
|
||||
/** @var string */
|
||||
private $debug_backtrace_function;
|
||||
|
||||
/**
|
||||
* DebugBackTrace constructor.
|
||||
*
|
||||
* @param int $limit
|
||||
* @param bool $provide_object
|
||||
* @param bool $ignore_args
|
||||
* @param null $debug_backtrace_function
|
||||
*/
|
||||
public function __construct(
|
||||
$limit = 0,
|
||||
$provide_object = false,
|
||||
$ignore_args = true,
|
||||
$debug_backtrace_function = null
|
||||
) {
|
||||
if ( ! $debug_backtrace_function ) {
|
||||
$debug_backtrace_function = 'debug_backtrace';
|
||||
}
|
||||
$this->limit = $limit;
|
||||
$this->provide_object = $provide_object;
|
||||
$this->ignore_args = $ignore_args;
|
||||
$this->debug_backtrace_function = $debug_backtrace_function;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $functions
|
||||
* @param bool $refresh
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function are_functions_in_call_stack( array $functions, $refresh = true ) {
|
||||
if ( empty( $this->debug_backtrace ) || $refresh ) {
|
||||
$this->get_backtrace();
|
||||
}
|
||||
|
||||
$found = false;
|
||||
foreach ( $this->debug_backtrace as $frame ) {
|
||||
if ( isset( $frame['class'] ) ) {
|
||||
$frame_function = [ $frame['class'], $frame['function'] ];
|
||||
} else {
|
||||
$frame_function = $frame['function'];
|
||||
}
|
||||
if ( in_array( $frame_function, $functions, true ) ) {
|
||||
$found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return $found;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $function_name
|
||||
* @param bool $refresh
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_function_in_call_stack( $function_name, $refresh = true ) {
|
||||
return $this->are_functions_in_call_stack( [ $function_name ], $refresh );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $function_name
|
||||
* @param bool $refresh
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function count_function_in_call_stack( $function_name, $refresh = true ) {
|
||||
if ( empty( $this->debug_backtrace ) || $refresh ) {
|
||||
$this->get_backtrace();
|
||||
}
|
||||
|
||||
$count = 0;
|
||||
foreach ( $this->debug_backtrace as $frame ) {
|
||||
if ( ! isset( $frame['class'] ) && $frame['function'] === $function_name ) {
|
||||
$count ++;
|
||||
}
|
||||
}
|
||||
|
||||
return $count;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $class_name
|
||||
* @param string $function_name
|
||||
* @param bool $refresh
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function is_class_function_in_call_stack( $class_name, $function_name, $refresh = true ) {
|
||||
return $this->are_functions_in_call_stack( [ [ $class_name, $function_name ] ], $refresh );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function get_backtrace() {
|
||||
$options = false;
|
||||
|
||||
// As of 5.3.6, 'options' parameter is a bit mask for the following options.
|
||||
if ( $this->provide_object ) {
|
||||
$options |= DEBUG_BACKTRACE_PROVIDE_OBJECT;
|
||||
}
|
||||
if ( $this->ignore_args ) {
|
||||
$options |= DEBUG_BACKTRACE_IGNORE_ARGS;
|
||||
}
|
||||
|
||||
$actual_limit = 0 === $this->limit ? 0 : $this->limit + 4;
|
||||
$this->debug_backtrace = (array) call_user_func_array(
|
||||
$this->debug_backtrace_function,
|
||||
[
|
||||
$options,
|
||||
$actual_limit,
|
||||
]
|
||||
); // Add one item to include the current frame.
|
||||
|
||||
$this->remove_frames_for_this_class();
|
||||
|
||||
return $this->debug_backtrace;
|
||||
}
|
||||
|
||||
private function remove_frames_for_this_class() {
|
||||
/**
|
||||
* We cannot rely on number of frames to remove.
|
||||
* php 5.6 and 7+ provides different call stacks.
|
||||
* php 5.6 adds call_user_func_array from get_backtrace()
|
||||
*/
|
||||
do {
|
||||
$found = false;
|
||||
|
||||
if ( ! isset( $this->debug_backtrace[0] ) ) {
|
||||
break;
|
||||
}
|
||||
$frame = $this->debug_backtrace[0];
|
||||
|
||||
if (
|
||||
( isset( $frame['file'] ) && __FILE__ === $frame['file'] )
|
||||
|| ( isset( $frame['class'] ) && self::class === $frame['class'] )
|
||||
) {
|
||||
$found = true;
|
||||
$this->remove_last_frame();
|
||||
}
|
||||
} while ( $found );
|
||||
|
||||
$this->remove_last_frame(); // Remove frame with the function called this class.
|
||||
}
|
||||
|
||||
public function remove_last_frame() {
|
||||
if ( $this->debug_backtrace ) {
|
||||
array_shift( $this->debug_backtrace );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?php
|
||||
|
||||
class WPML_Ajax {
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_frontend_ajax_request() {
|
||||
return wpml_is_ajax() && isset( $_SERVER['HTTP_REFERER'] ) && false === strpos( $_SERVER['HTTP_REFERER'], admin_url() );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $url
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_admin_ajax_request_called_from_frontend( $url ) {
|
||||
if ( false === strpos( $url, 'admin-ajax.php' ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// is not frontend
|
||||
if ( isset( $_SERVER['HTTP_REFERER'] )
|
||||
&& ( strpos( $_SERVER['HTTP_REFERER'], 'wp-admin' ) || strpos( $_SERVER['HTTP_REFERER'], 'admin-ajax' ) )
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
class WPML_Cache_Factory {
|
||||
|
||||
/** @var array */
|
||||
private $valid_caches = [
|
||||
'TranslationManagement::get_translation_job_id' => [
|
||||
'clear_actions' => [ 'wpml_tm_save_post', 'wpml_cache_clear' ],
|
||||
],
|
||||
|
||||
'WPML_Element_Type_Translation::get_language_for_element' => [
|
||||
'clear_actions' => [ 'wpml_translation_update' ],
|
||||
],
|
||||
|
||||
'WPML_Post_Status::needs_update' => [
|
||||
'clear_actions' => [ 'wpml_translation_status_update' ],
|
||||
],
|
||||
];
|
||||
|
||||
public function __construct() {
|
||||
foreach ( $this->valid_caches as $cache_name => $clear_actions ) {
|
||||
$this->init_clear_actions( $cache_name, $clear_actions['clear_actions'] );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $cache_name
|
||||
*
|
||||
* @return WPML_WP_Cache
|
||||
* @throws InvalidArgumentException Exception.
|
||||
*/
|
||||
public function get( $cache_name ) {
|
||||
if ( isset( $this->valid_caches[ $cache_name ] ) ) {
|
||||
return new WPML_WP_Cache( $cache_name );
|
||||
} else {
|
||||
throw new InvalidArgumentException( $cache_name . ' is not a valid cache for the WPML_Cache_Factory' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $cache_name
|
||||
* @param array $clear_actions
|
||||
*/
|
||||
public function define( $cache_name, array $clear_actions ) {
|
||||
if ( isset( $this->valid_caches[ $cache_name ] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->valid_caches[ $cache_name ] = [
|
||||
'clear_actions' => $clear_actions,
|
||||
];
|
||||
$this->init_clear_actions( $cache_name, $clear_actions );
|
||||
}
|
||||
|
||||
private function init_clear_actions( $cache_name, array $clear_actions ) {
|
||||
foreach ( $clear_actions as $clear_action ) {
|
||||
add_action(
|
||||
$clear_action,
|
||||
function () use ( $cache_name ) {
|
||||
$cache = new WPML_WP_Cache( $cache_name );
|
||||
$cache->flush_group_cache();
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
class WPML_Deactivate_Old_Media_Factory implements IWPML_Backend_Action_Loader {
|
||||
|
||||
public function create() {
|
||||
return new WPML_Deactivate_Old_Media( new WPML_PHP_Functions() );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
class WPML_Deactivate_Old_Media {
|
||||
|
||||
private $php_functions;
|
||||
|
||||
public function __construct( WPML_PHP_Functions $php_functions ) {
|
||||
$this->php_functions = $php_functions;
|
||||
}
|
||||
|
||||
public function add_hooks() {
|
||||
add_action( 'admin_init', array( $this, 'deactivate_media' ) );
|
||||
}
|
||||
|
||||
public function deactivate_media() {
|
||||
if ( $this->php_functions->defined( 'WPML_MEDIA_VERSION' ) && $this->php_functions->constant( 'WPML_MEDIA_VERSION' ) < '2.3' ) {
|
||||
deactivate_plugins( $this->php_functions->constant( 'WPML_MEDIA_PATH' ) . '/plugin.php' );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class WPML_Debug_BackTrace
|
||||
*
|
||||
* @deprecated 4.2.8
|
||||
*/
|
||||
class WPML_Debug_BackTrace extends WPML\Utils\DebugBackTrace {
|
||||
|
||||
/**
|
||||
* @param string $php_version Deprecated.
|
||||
* @param int $limit
|
||||
* @param bool $provide_object
|
||||
* @param bool $ignore_args
|
||||
* @param string $debug_backtrace_function
|
||||
* @phpstan-ignore-next-line
|
||||
*/
|
||||
public function __construct(
|
||||
$php_version = null,
|
||||
$limit = 0,
|
||||
$provide_object = false,
|
||||
$ignore_args = true,
|
||||
$debug_backtrace_function = null
|
||||
) {
|
||||
parent::__construct( $limit, $provide_object, $ignore_args, $debug_backtrace_function );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
class WPML_Encoding_Validation {
|
||||
|
||||
const MIN_CHAR_SIZE = 26;
|
||||
|
||||
/**
|
||||
* @param string $string
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function is_base64( $string ) {
|
||||
return self::MIN_CHAR_SIZE < strlen( $string ) && preg_match_all( '#^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{4}|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)$#', $string, $matches );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
class WPML_Encoding {
|
||||
|
||||
/**
|
||||
* @param string $string The string to decode.
|
||||
* @param string $encodings A comma separated list of encodings in the order that the data was encoded
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public static function decode( $string, $encodings ) {
|
||||
$decoded_data = $string;
|
||||
|
||||
// NOTE: We decode in the reverse order of the encodings given
|
||||
foreach ( array_reverse( explode( ',', $encodings ) ) as $encoding ) {
|
||||
switch ( $encoding ) {
|
||||
case 'json':
|
||||
$decoded_data = json_decode( $decoded_data, true );
|
||||
break;
|
||||
|
||||
case 'base64':
|
||||
$decoded_data = base64_decode( $decoded_data );
|
||||
break;
|
||||
|
||||
case 'urlencode':
|
||||
$decoded_data = urldecode( $decoded_data );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 4.1.0
|
||||
*/
|
||||
return apply_filters( 'wpml_decode_string', $decoded_data, $string, $encodings );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $data The data to encode.
|
||||
* @param string $encodings A comma separated list of encodings in the order that the data was encoded
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function encode( $data, $encodings ) {
|
||||
$encoded_data = $data;
|
||||
|
||||
foreach ( explode( ',', $encodings ) as $encoding ) {
|
||||
switch ( $encoding ) {
|
||||
case 'json':
|
||||
$encoded_data = wp_json_encode( $encoded_data );
|
||||
break;
|
||||
|
||||
case 'base64':
|
||||
$encoded_data = base64_encode( $encoded_data );
|
||||
break;
|
||||
|
||||
case 'urlencode':
|
||||
$encoded_data = urlencode( $encoded_data );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 4.1.0
|
||||
*/
|
||||
return apply_filters( 'wpml_encode_string', $encoded_data, $data, $encodings );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
class WPML_Flags_Factory {
|
||||
/** @var wpdb */
|
||||
private $wpdb;
|
||||
|
||||
/**
|
||||
* @param wpdb $wpdb
|
||||
*/
|
||||
public function __construct( wpdb $wpdb ) {
|
||||
$this->wpdb = $wpdb;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return WPML_Flags
|
||||
*/
|
||||
public function create() {
|
||||
if ( ! class_exists( 'WP_Filesystem_Direct' ) ) {
|
||||
require_once ABSPATH . 'wp-admin/includes/class-wp-filesystem-base.php';
|
||||
require_once ABSPATH . 'wp-admin/includes/class-wp-filesystem-direct.php';
|
||||
}
|
||||
|
||||
return new WPML_Flags( $this->wpdb, new icl_cache( 'flags', true ), new WP_Filesystem_Direct( null ) );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
<?php
|
||||
use WPML\FP\Obj;
|
||||
|
||||
/**
|
||||
* Class WPML_Flags
|
||||
*
|
||||
* @package wpml-core
|
||||
*/
|
||||
class WPML_Flags {
|
||||
/** @var icl_cache */
|
||||
private $cache;
|
||||
|
||||
/** @var wpdb $wpdb */
|
||||
private $wpdb;
|
||||
|
||||
/** @var WP_Filesystem_Direct */
|
||||
private $filesystem;
|
||||
|
||||
/**
|
||||
* @param wpdb $wpdb
|
||||
* @param icl_cache $cache
|
||||
* @param WP_Filesystem_Direct $filesystem
|
||||
*/
|
||||
public function __construct( $wpdb, icl_cache $cache, WP_Filesystem_Direct $filesystem ) {
|
||||
$this->wpdb = $wpdb;
|
||||
$this->cache = $cache;
|
||||
$this->filesystem = $filesystem;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $lang_code
|
||||
*
|
||||
* @return \stdClass|null
|
||||
*/
|
||||
public function get_flag( $lang_code ) {
|
||||
$flag = $this->cache->get( $lang_code );
|
||||
|
||||
if ( ! $flag ) {
|
||||
$flag = $this->wpdb->get_row(
|
||||
$this->wpdb->prepare(
|
||||
"SELECT flag, from_template
|
||||
FROM {$this->wpdb->prefix}icl_flags
|
||||
WHERE lang_code=%s",
|
||||
$lang_code
|
||||
)
|
||||
);
|
||||
|
||||
$this->cache->set( $lang_code, $flag );
|
||||
}
|
||||
|
||||
return $flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $lang_code
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_flag_url( $lang_code ) {
|
||||
$flag = $this->get_flag( $lang_code );
|
||||
if ( ! $flag ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$path = '';
|
||||
if ( $flag->from_template ) {
|
||||
$wp_upload_dir = wp_upload_dir();
|
||||
$base_path = $wp_upload_dir['basedir'] . '/';
|
||||
$base_url = $wp_upload_dir['baseurl'];
|
||||
$path = 'flags/';
|
||||
} else {
|
||||
$base_path = self::get_wpml_flags_directory();
|
||||
$base_url = self::get_wpml_flags_url();
|
||||
}
|
||||
$path .= $flag->flag;
|
||||
|
||||
if ( $this->flag_file_exists( $base_path . $path ) ) {
|
||||
return $this->append_path_to_url( $base_url, $path );
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $lang_code
|
||||
* @param int[] $size An array describing [ $width, $height ]. It defaults to [18, 12].
|
||||
* @param string $fallback_text
|
||||
* @param string[] $css_classes Array of CSS class strings.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_flag_image( $lang_code, $size = [], $fallback_text = '', $css_classes = [] ) {
|
||||
$url = $this->get_flag_url( $lang_code );
|
||||
|
||||
if ( ! $url ) {
|
||||
return $fallback_text;
|
||||
}
|
||||
|
||||
$class_attribute = is_array( $css_classes ) && ! empty( $css_classes )
|
||||
? ' class="' . implode( ' ', $css_classes ) . '"'
|
||||
: '';
|
||||
|
||||
return '<img' . $class_attribute . '
|
||||
width="' . Obj::propOr( 18, 0, $size ) . '"
|
||||
height="' . Obj::propOr( 12, 1, $size ) . '"
|
||||
src="' . esc_url( $url ) . '"
|
||||
alt="' . esc_attr( sprintf( __( 'Flag for %s', 'sitepress' ), $lang_code ) ) . '"
|
||||
/>';
|
||||
}
|
||||
|
||||
public function clear() {
|
||||
$this->cache->clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $allowed_file_types
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function get_wpml_flags( $allowed_file_types = null ) {
|
||||
if ( null === $allowed_file_types ) {
|
||||
$allowed_file_types = array( 'gif', 'jpeg', 'png', 'svg' );
|
||||
}
|
||||
|
||||
$files = array_keys( $this->filesystem->dirlist( $this->get_wpml_flags_directory(), false ) );
|
||||
|
||||
$result = $this->filter_flag_files( $allowed_file_types, $files );
|
||||
sort( $result );
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
final public function get_wpml_flags_directory() {
|
||||
return WPML_PLUGIN_PATH . '/res/flags/';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
final public static function get_wpml_flags_url() {
|
||||
return ICL_PLUGIN_URL . '/res/flags/';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function flag_file_exists( $path ) {
|
||||
return $this->filesystem->exists( $path );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $allowed_file_types
|
||||
* @param array $files
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function filter_flag_files( $allowed_file_types, $files ) {
|
||||
$result = array();
|
||||
foreach ( $files as $file ) {
|
||||
$path = $this->get_wpml_flags_directory() . $file;
|
||||
if ( $this->flag_file_exists( $path ) ) {
|
||||
$ext = pathinfo( $path, PATHINFO_EXTENSION );
|
||||
if ( in_array( $ext, $allowed_file_types, true ) ) {
|
||||
$result[] = $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $base_url
|
||||
* @param string $path
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function append_path_to_url( $base_url, $path ) {
|
||||
$base_url_parts = wp_parse_url( $base_url );
|
||||
|
||||
$base_url_path_components = array();
|
||||
if ( array_key_exists( 'path', $base_url_parts ) ) {
|
||||
$base_url_path_components = explode( '/', untrailingslashit( $base_url_parts['path'] ) );
|
||||
}
|
||||
|
||||
$sub_dir_path_components = explode( '/', trim( $path, '/' ) );
|
||||
foreach ( $sub_dir_path_components as $sub_dir_path_part ) {
|
||||
$base_url_path_components[] = $sub_dir_path_part;
|
||||
}
|
||||
|
||||
$base_url_parts['path'] = implode( '/', $base_url_path_components );
|
||||
|
||||
return http_build_url( $base_url_parts );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
<?php
|
||||
|
||||
class WPML_Global_AJAX extends WPML_SP_User {
|
||||
|
||||
/**
|
||||
* WPML_Global_AJAX constructor.
|
||||
*
|
||||
* @param SitePress $sitepress
|
||||
*/
|
||||
public function __construct( &$sitepress ) {
|
||||
parent::__construct( $sitepress );
|
||||
add_action( 'wp_ajax_save_language_negotiation_type', array( $this, 'save_language_negotiation_type_action' ) );
|
||||
}
|
||||
|
||||
public function save_language_negotiation_type_action() {
|
||||
$errors = array();
|
||||
$response = false;
|
||||
$nonce = filter_input( INPUT_POST, 'nonce' );
|
||||
$action = filter_input( INPUT_POST, 'action' );
|
||||
$is_valid_nonce = wp_verify_nonce( $nonce, $action );
|
||||
|
||||
if ( $is_valid_nonce ) {
|
||||
$icl_language_negotiation_type = filter_input( INPUT_POST, 'icl_language_negotiation_type', FILTER_SANITIZE_NUMBER_INT, FILTER_NULL_ON_FAILURE );
|
||||
$language_domains = filter_input( INPUT_POST, 'language_domains', FILTER_SANITIZE_FULL_SPECIAL_CHARS, FILTER_REQUIRE_ARRAY | FILTER_NULL_ON_FAILURE );
|
||||
$use_directory = filter_input( INPUT_POST, 'use_directory', FILTER_SANITIZE_NUMBER_INT, FILTER_NULL_ON_FAILURE );
|
||||
$show_on_root = filter_input( INPUT_POST, 'show_on_root', FILTER_SANITIZE_FULL_SPECIAL_CHARS, FILTER_NULL_ON_FAILURE );
|
||||
$root_html_file_path = filter_input( INPUT_POST, 'root_html_file_path', FILTER_SANITIZE_FULL_SPECIAL_CHARS, FILTER_NULL_ON_FAILURE );
|
||||
$hide_language_switchers = filter_input( INPUT_POST, 'hide_language_switchers', FILTER_SANITIZE_NUMBER_INT, FILTER_NULL_ON_FAILURE );
|
||||
$icl_xdomain_data = filter_input( INPUT_POST, 'xdomain', FILTER_SANITIZE_NUMBER_INT, FILTER_NULL_ON_FAILURE );
|
||||
$sso_enabled = filter_input( INPUT_POST, 'sso_enabled', FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE );
|
||||
|
||||
if ( $icl_language_negotiation_type ) {
|
||||
$this->sitepress->set_setting( 'language_negotiation_type', $icl_language_negotiation_type );
|
||||
$response = true;
|
||||
|
||||
if ( ! empty( $language_domains ) ) {
|
||||
$this->sitepress->set_setting( 'language_domains', $language_domains );
|
||||
}
|
||||
if ( 1 === (int) $icl_language_negotiation_type ) {
|
||||
$urls = $this->sitepress->get_setting( 'urls' );
|
||||
$urls['directory_for_default_language'] = $use_directory ? true : 0;
|
||||
if ( $use_directory ) {
|
||||
$urls['show_on_root'] = $use_directory ? $show_on_root : '';
|
||||
if ( 'html_file' === $show_on_root ) {
|
||||
$root_page_url = $root_html_file_path ? $root_html_file_path : '';
|
||||
$response = $this->validateRootPageUrl( $root_page_url, $errors );
|
||||
if ( $response ) {
|
||||
$urls['root_html_file_path'] = $root_page_url;
|
||||
}
|
||||
} else {
|
||||
$urls['hide_language_switchers'] = $hide_language_switchers ? $hide_language_switchers : 0;
|
||||
}
|
||||
}
|
||||
$this->sitepress->set_setting( 'urls', $urls );
|
||||
}
|
||||
|
||||
$this->sitepress->set_setting( 'xdomain_data', $icl_xdomain_data );
|
||||
$this->sitepress->set_setting( 'language_per_domain_sso_enabled', $sso_enabled );
|
||||
$this->sitepress->save_settings();
|
||||
}
|
||||
|
||||
if ( $response ) {
|
||||
$permalinks_settings_url = get_admin_url( null, 'options-permalink.php' );
|
||||
$save_permalinks_link = '<a href="' . $permalinks_settings_url . '">' . _x( 're-save the site permalinks', 'You may need to {re-save the site permalinks} - 2/2', 'sitepress' ) . '</a>';
|
||||
$save_permalinks_message = sprintf( _x( 'You may need to %s.', 'You may need to {re-save the site permalinks} - 1/2', 'sitepress' ), $save_permalinks_link );
|
||||
wp_send_json_success( $save_permalinks_message );
|
||||
} else {
|
||||
if ( ! $errors ) {
|
||||
$errors[] = __( 'Error', 'sitepress' );
|
||||
}
|
||||
wp_send_json_error( $errors );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $url
|
||||
* @param array $errors
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function validateRootPageUrl( $url, array &$errors ) {
|
||||
$wp_http = new WP_Http();
|
||||
if ( '' === trim( $url ) ) {
|
||||
$errors[] = __( 'The URL of the HTML file is required', 'sitepress' );
|
||||
|
||||
return false;
|
||||
}
|
||||
if ( 0 !== strpos( $url, 'http' ) ) {
|
||||
$url = get_site_url( null, $url );
|
||||
}
|
||||
|
||||
if ( $this->is_external( $url ) ) {
|
||||
$errors[] = __( 'You are trying to use an external URL: this is not allowed.', 'sitepress' );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
$response = $wp_http->get( $url );
|
||||
if ( is_wp_error( $response ) ) {
|
||||
$errors[] = $response->get_error_code() . ' - ' . $response->get_error_message( $response->get_error_code() );
|
||||
|
||||
return false;
|
||||
}
|
||||
if ( 200 !== (int) $response['response']['code'] ) {
|
||||
$errors[] = __( 'An attempt to open the URL specified as a root page failed with the following error:', 'sitepress' );
|
||||
$errors[] = $response['response']['code'] . ': ' . $response['response']['message'];
|
||||
|
||||
return false;
|
||||
}
|
||||
} catch ( Exception $ex ) {
|
||||
$errors[] = $ex->getMessage();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $url
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function is_external( $url ) {
|
||||
$site_url = get_site_url();
|
||||
$site_components = wp_parse_url( $site_url );
|
||||
$site_host = strtolower( $site_components['host'] );
|
||||
|
||||
$url_components = wp_parse_url( $url );
|
||||
$url_host = strtolower( $url_components['host'] );
|
||||
|
||||
if ( empty( $url_host ) || 0 === strcasecmp( $url_host, $site_host ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$site_host = $this->remove_www_prefix( $site_host );
|
||||
|
||||
$subdomain_position = strrpos( $url_host, '.' . $site_host );
|
||||
$subdomain_length = strlen( $url_host ) - strlen( '.' . $site_host );
|
||||
|
||||
return $subdomain_position !== $subdomain_length; // check if the url host is a subdomain
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $site_host
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function remove_www_prefix( $site_host ) {
|
||||
$site_host_levels = explode( '.', $site_host );
|
||||
if ( 2 > count( $site_host_levels ) && 'www' === $site_host_levels[0] ) {
|
||||
$site_host_levels = array_slice( $site_host_levels, - ( count( $site_host_levels ) - 1 ) );
|
||||
$site_host = implode( '.', $site_host_levels );
|
||||
}
|
||||
|
||||
return $site_host;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,184 @@
|
||||
<?php
|
||||
|
||||
class WPML_Inactive_Content {
|
||||
|
||||
/** @var wpdb $wpdb */
|
||||
private $wpdb;
|
||||
|
||||
/** @var string $current_language */
|
||||
private $current_language;
|
||||
|
||||
/** @var array $content_types */
|
||||
private $content_types;
|
||||
|
||||
/** @var array $inactive */
|
||||
private $inactive;
|
||||
|
||||
public function __construct( wpdb $wpdb, $current_language ) {
|
||||
$this->wpdb = $wpdb;
|
||||
$this->current_language = $current_language;
|
||||
}
|
||||
|
||||
/** @return bool */
|
||||
public function has_entries() {
|
||||
return (bool) $this->get_inactive();
|
||||
}
|
||||
|
||||
/** @return array */
|
||||
public function get_content_types() {
|
||||
|
||||
foreach ( $this->get_inactive() as $types ) {
|
||||
|
||||
foreach ( $types as $type => $slugs ) {
|
||||
|
||||
foreach ( $slugs as $slug => $count ) {
|
||||
$this->content_types[ $type ][ $slug ] = $this->get_label( $type, $slug );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->content_types;
|
||||
}
|
||||
|
||||
/** @return array */
|
||||
public function get_languages() {
|
||||
return array_keys( $this->get_inactive() );
|
||||
}
|
||||
|
||||
/** @return array */
|
||||
public function get_language_counts_rows() {
|
||||
$counts = array();
|
||||
|
||||
foreach ( $this->get_languages() as $language ) {
|
||||
|
||||
foreach ( $this->get_content_types() as $type => $slugs ) {
|
||||
|
||||
foreach ( $slugs as $slug => $label ) {
|
||||
|
||||
$counts[ $language ][] = $this->count( $language, $type, $slug );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $counts;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $lang
|
||||
* @param string $type
|
||||
* @param string $slug
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
private function count( $lang, $type, $slug ) {
|
||||
|
||||
if ( isset( $this->inactive[ $lang ][ $type ][ $slug ] ) ) {
|
||||
return (int) $this->inactive[ $lang ][ $type ][ $slug ];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $langName
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getLangCode( $langName ) {
|
||||
return \WPML\Element\API\Languages::getCodeByName($langName);
|
||||
}
|
||||
|
||||
/** @return array */
|
||||
private function get_inactive() {
|
||||
|
||||
if ( null === $this->inactive ) {
|
||||
$this->inactive = array();
|
||||
$post_query = $this->wpdb->prepare(
|
||||
"
|
||||
SELECT COUNT(posts.ID) AS c, posts.post_type, languages_translations.name AS language
|
||||
FROM {$this->wpdb->prefix}icl_translations translations
|
||||
JOIN {$this->wpdb->posts} posts
|
||||
ON translations.element_id = posts.ID AND translations.element_type LIKE %s
|
||||
JOIN {$this->wpdb->prefix}icl_languages languages
|
||||
ON translations.language_code = languages.code AND languages.active = 0
|
||||
JOIN {$this->wpdb->prefix}icl_languages_translations languages_translations
|
||||
ON languages_translations.language_code = languages.code
|
||||
AND languages_translations.display_language_code = %s
|
||||
GROUP BY posts.post_type, translations.language_code
|
||||
",
|
||||
array( wpml_like_escape( 'post_' ) . '%', $this->current_language )
|
||||
);
|
||||
|
||||
$post_results = $this->wpdb->get_results( $post_query );
|
||||
|
||||
if ( $post_results ) {
|
||||
foreach ( $post_results as $r ) {
|
||||
$this->inactive[ $r->language ]['post'][ $r->post_type ] = $r->c;
|
||||
}
|
||||
}
|
||||
|
||||
$tax_query = $this->wpdb->prepare(
|
||||
"
|
||||
SELECT COUNT(posts.term_taxonomy_id) AS c, posts.taxonomy, languages_translations.name AS language
|
||||
FROM {$this->wpdb->prefix}icl_translations translations
|
||||
JOIN {$this->wpdb->term_taxonomy} posts
|
||||
ON translations.element_id = posts.term_taxonomy_id
|
||||
JOIN {$this->wpdb->prefix}icl_languages languages
|
||||
ON translations.language_code = languages.code AND languages.active = 0
|
||||
JOIN {$this->wpdb->prefix}icl_languages_translations languages_translations
|
||||
ON languages_translations.language_code = languages.code
|
||||
AND languages_translations.display_language_code = %s
|
||||
WHERE translations.element_type LIKE %s AND translations.element_type NOT LIKE %s
|
||||
GROUP BY posts.taxonomy, translations.language_code
|
||||
",
|
||||
[
|
||||
$this->current_language,
|
||||
wpml_like_escape( 'tax_' ) . '%',
|
||||
'%'. wpml_like_escape('tax_translation_priority') . '%'
|
||||
]
|
||||
);
|
||||
|
||||
$tax_results = $this->wpdb->get_results( $tax_query );
|
||||
|
||||
if ( $tax_results ) {
|
||||
foreach ( $tax_results as $r ) {
|
||||
if ( ! $this->is_only_default_category( $r ) ) {
|
||||
$this->inactive[ $r->language ]['taxonomy'][ $r->taxonomy ] = $r->c;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $this->inactive;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param stdClass $r
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function is_only_default_category( $r ) {
|
||||
return $r->taxonomy === 'category' && $r->c == 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $type
|
||||
* @param string $slug
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
private function get_label( $type, $slug ) {
|
||||
if ( 'post' === $type ) {
|
||||
$type_object = get_post_type_object( $slug );
|
||||
} else {
|
||||
$type_object = get_taxonomy( $slug );
|
||||
}
|
||||
|
||||
if ( isset( $type_object->label ) ) {
|
||||
return $type_object->label;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,231 @@
|
||||
<?php
|
||||
|
||||
use WPML\Collect\Support\Collection;
|
||||
|
||||
class WPML_Locale {
|
||||
/**
|
||||
* @var wpdb
|
||||
*/
|
||||
private $wpdb;
|
||||
/**
|
||||
* @var SitePress
|
||||
*/
|
||||
private $sitepress;
|
||||
/**
|
||||
* @var string $locale
|
||||
*/
|
||||
private $locale;
|
||||
private $locale_cache;
|
||||
|
||||
/** @var Collection $all_locales */
|
||||
private $all_locales;
|
||||
|
||||
/**
|
||||
* WPML_Locale constructor.
|
||||
*
|
||||
* @param wpdb $wpdb
|
||||
* @param SitePress $sitepress
|
||||
* @param string $locale
|
||||
*/
|
||||
public function __construct( wpdb &$wpdb, SitePress &$sitepress, &$locale ) {
|
||||
$this->wpdb =& $wpdb;
|
||||
$this->sitepress =& $sitepress;
|
||||
$this->locale =& $locale;
|
||||
$this->locale_cache = null;
|
||||
}
|
||||
|
||||
public function init() {
|
||||
if ( $this->language_needs_title_sanitization() ) {
|
||||
add_filter( 'sanitize_title', array( $this, 'filter_sanitize_title' ), 10, 2 );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \Test_Admin_Settings::test_locale
|
||||
* @fixme
|
||||
* Due to the way these tests work (global state issues) I had to create this method
|
||||
* to ensure we have full coverage of the code.
|
||||
* This method shouldn't be used anywhere else and should be removed once tests are migrated
|
||||
* to the new tests framework.
|
||||
*/
|
||||
public function reset_cached_data() {
|
||||
$this->locale_cache = null;
|
||||
$this->all_locales = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hooked to 'sanitize_title' in case the user is using a language that has either German or Danish locale, to
|
||||
* ensure that WP Core sanitization functions handle special chars accordingly.
|
||||
*
|
||||
* @param string $title
|
||||
* @param string $raw_title
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function filter_sanitize_title( $title, $raw_title ) {
|
||||
if ( $title !== $raw_title ) {
|
||||
remove_filter( 'sanitize_title', array( $this, 'filter_sanitize_title' ), 10 );
|
||||
$chars = array();
|
||||
$chars[ chr( 195 ) . chr( 132 ) ] = 'Ae';
|
||||
$chars[ chr( 195 ) . chr( 133 ) ] = 'Aa';
|
||||
$chars[ chr( 195 ) . chr( 134 ) ] = 'Ae';
|
||||
$chars[ chr( 195 ) . chr( 150 ) ] = 'Oe';
|
||||
$chars[ chr( 195 ) . chr( 152 ) ] = 'Oe';
|
||||
$chars[ chr( 195 ) . chr( 156 ) ] = 'Ue';
|
||||
$chars[ chr( 195 ) . chr( 159 ) ] = 'ss';
|
||||
$chars[ chr( 195 ) . chr( 164 ) ] = 'ae';
|
||||
$chars[ chr( 195 ) . chr( 165 ) ] = 'aa';
|
||||
$chars[ chr( 195 ) . chr( 166 ) ] = 'ae';
|
||||
$chars[ chr( 195 ) . chr( 182 ) ] = 'oe';
|
||||
$chars[ chr( 195 ) . chr( 184 ) ] = 'oe';
|
||||
$chars[ chr( 195 ) . chr( 188 ) ] = 'ue';
|
||||
$title = sanitize_title( strtr( $raw_title, $chars ) );
|
||||
add_filter( 'sanitize_title', array( $this, 'filter_sanitize_title' ), 10, 2 );
|
||||
}
|
||||
|
||||
return $title;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool|mixed
|
||||
*/
|
||||
public function locale() {
|
||||
if ( ! $this->locale_cache ) {
|
||||
add_filter( 'language_attributes', array( $this, '_language_attributes' ) );
|
||||
|
||||
$wp_api = $this->sitepress->get_wp_api();
|
||||
$is_ajax = $wp_api->is_ajax();
|
||||
if ( $is_ajax && isset( $_REQUEST['action'], $_REQUEST['lang'] ) ) {
|
||||
$locale_lang_code = $_REQUEST['lang'];
|
||||
} elseif ( $wp_api->is_admin()
|
||||
&& ( ! $is_ajax
|
||||
|| $this->sitepress->check_if_admin_action_from_referer() )
|
||||
) {
|
||||
$locale_lang_code = $this->sitepress->user_lang_by_authcookie();
|
||||
} else {
|
||||
$locale_lang_code = $this->sitepress->get_current_language();
|
||||
}
|
||||
$locale = $this->get_locale( $locale_lang_code );
|
||||
|
||||
if ( did_action( 'plugins_loaded' ) ) {
|
||||
$this->locale_cache = $locale;
|
||||
}
|
||||
|
||||
return $locale;
|
||||
}
|
||||
|
||||
return $this->locale_cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $code
|
||||
*
|
||||
* @return false|string
|
||||
*/
|
||||
public function get_locale( $code ) {
|
||||
if ( ! $code ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->get_all_locales()->get( $code, $code );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Collection
|
||||
*/
|
||||
public function get_all_locales() {
|
||||
if ( ! $this->all_locales ) {
|
||||
$sql = "
|
||||
SELECT
|
||||
l.code,
|
||||
m.locale,
|
||||
l.default_locale
|
||||
FROM {$this->wpdb->prefix}icl_languages AS l
|
||||
LEFT JOIN {$this->wpdb->prefix}icl_locale_map AS m ON m.code = l.code
|
||||
";
|
||||
|
||||
$this->all_locales = wpml_collect( $this->wpdb->get_results( $sql ) )
|
||||
->mapWithKeys(
|
||||
function( $row ) {
|
||||
if ( $row->locale ) {
|
||||
$locale = $row->locale;
|
||||
} elseif ( $row->default_locale ) {
|
||||
$locale = $row->default_locale;
|
||||
} else {
|
||||
$locale = $row->code;
|
||||
}
|
||||
|
||||
return [ $row->code => $locale ];
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return $this->all_locales;
|
||||
}
|
||||
|
||||
public function switch_locale( $lang_code = false ) {
|
||||
global $l10n;
|
||||
static $original_l10n;
|
||||
if ( ! empty( $lang_code ) ) {
|
||||
$original_l10n = isset( $l10n['sitepress'] ) ? $l10n['sitepress'] : null;
|
||||
if ( $original_l10n !== null ) {
|
||||
unset( $l10n['sitepress'] );
|
||||
}
|
||||
load_textdomain(
|
||||
'sitepress',
|
||||
WPML_PLUGIN_PATH . '/locale/sitepress-' . $this->get_locale( $lang_code ) . '.mo'
|
||||
);
|
||||
} else { // switch back
|
||||
$l10n['sitepress'] = $original_l10n;
|
||||
}
|
||||
}
|
||||
|
||||
public function get_locale_file_names() {
|
||||
$locales = array();
|
||||
$res = $this->wpdb->get_results(
|
||||
"
|
||||
SELECT lm.code, locale
|
||||
FROM {$this->wpdb->prefix}icl_locale_map lm JOIN {$this->wpdb->prefix}icl_languages l ON lm.code = l.code AND l.active=1"
|
||||
);
|
||||
foreach ( $res as $row ) {
|
||||
$locales[ $row->code ] = $row->locale;
|
||||
}
|
||||
|
||||
return $locales;
|
||||
}
|
||||
|
||||
private function language_needs_title_sanitization() {
|
||||
$lang_needs_filter = array( 'de_DE', 'da_DK' );
|
||||
$current_lang = $this->sitepress->get_language_details( $this->sitepress->get_current_language() );
|
||||
$needs_filter = false;
|
||||
|
||||
if ( ! isset( $current_lang['default_locale'] ) ) {
|
||||
return $needs_filter;
|
||||
}
|
||||
|
||||
if ( in_array( $current_lang['default_locale'], $lang_needs_filter, true ) ) {
|
||||
$needs_filter = true;
|
||||
}
|
||||
|
||||
return $needs_filter;
|
||||
}
|
||||
|
||||
function _language_attributes( $latr ) {
|
||||
|
||||
return preg_replace(
|
||||
'#lang="([a-z]+)"#i',
|
||||
'lang="' . str_replace( '_', '-', $this->locale ) . '"',
|
||||
$latr
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return WPML_Locale
|
||||
*/
|
||||
public static function get_instance_from_sitepress() {
|
||||
/** SitePress $sitepress */
|
||||
global $sitepress;
|
||||
|
||||
return $sitepress->get_wpml_locale();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class WPML_Non_Persistent_Cache
|
||||
*
|
||||
* Implements non-persistent cache based on an array. Suitable to cache objects during single page load.
|
||||
*/
|
||||
class WPML_Non_Persistent_Cache {
|
||||
|
||||
/**
|
||||
* @var array Cached objects.
|
||||
*/
|
||||
private static $cache = array();
|
||||
|
||||
/**
|
||||
* Retrieves the data contents from the cache, if it exists.
|
||||
*
|
||||
* @param string $key Cache key.
|
||||
* @param string $group Cache group.
|
||||
* @param bool $found Whether the key was found in the cache (passed by reference).
|
||||
* Disambiguates a return of false, a storable value.
|
||||
*
|
||||
* @return mixed|bool
|
||||
*/
|
||||
public static function get( $key, $group = 'default', &$found = null ) {
|
||||
if (
|
||||
isset( self::$cache[ $group ] ) &&
|
||||
( isset( self::$cache[ $group ][ $key ] ) || array_key_exists( $key, self::$cache[ $group ] ) )
|
||||
) {
|
||||
$found = true;
|
||||
|
||||
return self::$cache[ $group ][ $key ];
|
||||
}
|
||||
$found = false;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the data contents into the cache.
|
||||
*
|
||||
* @param string $key Cache key.
|
||||
* @param mixed $data Data to store in cache.
|
||||
* @param string $group Cache group.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function set( $key, $data, $group = 'default' ) {
|
||||
if ( is_object( $data ) ) {
|
||||
$data = clone $data;
|
||||
}
|
||||
self::$cache[ $group ][ $key ] = $data;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes callback function and caches its result.
|
||||
*
|
||||
* @param string $key Cache key.
|
||||
* @param callable $callback Callback function.
|
||||
* @param string $group Cache group.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function execute_and_cache( $key, $callback, $group = 'default' ) {
|
||||
$data = self::get( $key, $group, $found );
|
||||
if ( ! $found ) {
|
||||
$data = $callback();
|
||||
self::set( $key, $data, $group );
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush cache.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function flush() {
|
||||
self::$cache = array();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush cache group.
|
||||
*
|
||||
* @param array|string $groups Cache group name.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function flush_group( $groups = 'default' ) {
|
||||
$groups = (array) $groups;
|
||||
foreach ( $groups as $group ) {
|
||||
unset( self::$cache[ $group ] );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
<?php
|
||||
|
||||
class WPML_Simple_Language_Selector extends WPML_SP_User {
|
||||
|
||||
function __construct( &$sitepress ) {
|
||||
parent::__construct( $sitepress );
|
||||
|
||||
self::enqueue_scripts();
|
||||
}
|
||||
|
||||
function render( $options = array() ) {
|
||||
|
||||
$options = array_merge(
|
||||
array(
|
||||
'id' => '',
|
||||
'name' => '',
|
||||
'show_please_select' => true,
|
||||
'please_select_text' => __( '-- Please select --', 'sitepress' ),
|
||||
'selected' => '',
|
||||
'echo' => false,
|
||||
'class' => '',
|
||||
'data' => array(),
|
||||
'show_flags' => true,
|
||||
'languages' => null,
|
||||
'disabled' => false,
|
||||
'style' => '',
|
||||
),
|
||||
$options
|
||||
);
|
||||
|
||||
if ( $options['languages'] ) {
|
||||
$languages = $options['languages'];
|
||||
} else {
|
||||
$languages = $this->sitepress->get_languages( $this->sitepress->get_admin_language() );
|
||||
}
|
||||
$active_languages = $this->sitepress->get_active_languages();
|
||||
|
||||
$data = '';
|
||||
foreach ( $options['data'] as $key => $value ) {
|
||||
$data .= ' data-' . $key . '="' . $value . '"';
|
||||
}
|
||||
|
||||
if ( $options['show_flags'] ) {
|
||||
$options['class'] .= ' js-simple-lang-selector-flags';
|
||||
}
|
||||
|
||||
if ( $options['disabled'] ) {
|
||||
$disabled = ' disabled="disabled" ';
|
||||
} else {
|
||||
$disabled = '';
|
||||
}
|
||||
|
||||
if ( ! $options['echo'] ) {
|
||||
ob_start();
|
||||
}
|
||||
|
||||
?>
|
||||
<select
|
||||
title="wpml-simple-language-selector"
|
||||
<?php
|
||||
if ( $options['id'] ) {
|
||||
echo ' id="' . esc_attr( $options['id'] ) . '"';
|
||||
}
|
||||
|
||||
if ( $options['name'] ) {
|
||||
echo ' name="' . esc_attr( $options['name'] ) . '"';
|
||||
}
|
||||
?>
|
||||
class="wpml-simple-lang-selector js-simple-lang-selector <?php echo esc_attr( $options['class'] ); ?>"
|
||||
<?php echo esc_attr( $data ); ?>
|
||||
<?php echo esc_attr( $disabled ); ?>
|
||||
style="<?php echo esc_attr( $options['style'] ); ?>">
|
||||
<?php
|
||||
if ( $options['show_please_select'] ) {
|
||||
?>
|
||||
<option value=""
|
||||
<?php
|
||||
if ( '' == $options['selected'] ) {
|
||||
echo 'selected="selected"';
|
||||
}
|
||||
?>
|
||||
>
|
||||
<?php echo esc_html( $options['please_select_text'] ); ?>
|
||||
</option>
|
||||
<?php
|
||||
}
|
||||
foreach ( $languages as $lang ) {
|
||||
?>
|
||||
<option value="<?php echo esc_attr( $lang['code'] ); ?>"
|
||||
<?php
|
||||
if ( $options['selected'] == $lang['code'] ) {
|
||||
echo 'selected="selected"';
|
||||
}
|
||||
?>
|
||||
data-flag_url="<?php echo esc_url( $this->sitepress->get_flag_url( $lang['code'] ) ); ?>" data-status="<?php echo in_array( $lang['code'], array_keys( $active_languages ) ) ? 'active' : ''; ?>">
|
||||
<?php echo esc_html( $lang['display_name'] ); ?>
|
||||
</option>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</select>
|
||||
<?php
|
||||
|
||||
if ( ! $options['echo'] ) {
|
||||
return ob_get_clean();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static function enqueue_scripts() {
|
||||
if ( ! wp_script_is( 'wpml-select-2' ) ) {
|
||||
// Enqueue in the footer because this is usually called late.
|
||||
wp_enqueue_script( 'wpml-select-2', ICL_PLUGIN_URL . '/lib/select2/select2.min.js', array( 'jquery' ), ICL_SITEPRESS_VERSION, true );
|
||||
wp_enqueue_script( 'wpml-simple_language-selector', ICL_PLUGIN_URL . '/res/js/wpml-simple-language-selector.js', array( 'jquery' ), ICL_SITEPRESS_VERSION, true );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
<?php
|
||||
|
||||
class WPML_Slash_Management {
|
||||
|
||||
public function match_trailing_slash_to_reference( $url, $reference_url ) {
|
||||
if ( trailingslashit( $reference_url ) === $reference_url && ! $this->has_lang_param( $url ) ) {
|
||||
return trailingslashit( $url );
|
||||
} else {
|
||||
return untrailingslashit( $url );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $url
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function has_lang_param( $url ) {
|
||||
return strpos( $url, '?lang=' ) !== false || strpos( $url, '&lang=' ) !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $url
|
||||
* @param string $method Deprecated.
|
||||
*
|
||||
* @return mixed|string
|
||||
*/
|
||||
public function maybe_user_trailingslashit( $url, $method = '' ) {
|
||||
$url_parts = wpml_parse_url( $url );
|
||||
|
||||
if ( ! $url_parts || ! is_array( $url_parts ) ) {
|
||||
return $url;
|
||||
}
|
||||
|
||||
$url_parts = $this->parse_missing_host_from_path( $url_parts );
|
||||
|
||||
if ( $this->is_root_url_with_trailingslash( $url_parts )
|
||||
|| $this->is_root_url_without_trailingslash_and_without_query_args( $url_parts )
|
||||
) {
|
||||
return $url;
|
||||
}
|
||||
|
||||
$path = isset( $url_parts['path'] ) ? $url_parts['path'] : '';
|
||||
|
||||
if ( ! $path && isset( $url_parts['query'] ) ) {
|
||||
$url_parts['path'] = '/';
|
||||
} elseif ( $this->is_file_path( $path ) ) {
|
||||
$url_parts['path'] = untrailingslashit( $path );
|
||||
} elseif ( $method ) {
|
||||
$url_parts['path'] = 'untrailingslashit' === $method ? untrailingslashit( $path ) : trailingslashit( $path );
|
||||
} else {
|
||||
$url_parts['path'] = $this->user_trailingslashit( $path );
|
||||
}
|
||||
|
||||
return http_build_url( $url_parts );
|
||||
}
|
||||
|
||||
/**
|
||||
* Follows the logic of WordPress core user_trailingslashit().
|
||||
* Can be called on plugins_loaded event, when $wp_rewrite is not set yet.
|
||||
*
|
||||
* @param string $path
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function user_trailingslashit( $path ) {
|
||||
global $wp_rewrite;
|
||||
|
||||
if ( $wp_rewrite ) {
|
||||
return user_trailingslashit( $path );
|
||||
}
|
||||
|
||||
$permalink_structure = get_option( 'permalink_structure' );
|
||||
$use_trailing_slashes = ( '/' === substr( $permalink_structure, - 1, 1 ) );
|
||||
|
||||
if ( $use_trailing_slashes ) {
|
||||
$path = trailingslashit( $path );
|
||||
} else {
|
||||
$path = untrailingslashit( $path );
|
||||
}
|
||||
|
||||
return apply_filters( 'user_trailingslashit', $path, '' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $url_parts
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function is_root_url_without_trailingslash_and_without_query_args( array $url_parts ) {
|
||||
return ! isset( $url_parts['path'] ) && ! isset( $url_parts['query'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $url_parts
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function is_root_url_with_trailingslash( array $url_parts ) {
|
||||
return isset( $url_parts['path'] ) && '/' === $url_parts['path'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @see Test_WPML_Lang_Domains_Converter::check_domains_and_subdir
|
||||
*
|
||||
* @param array $url_parts
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function parse_missing_host_from_path( array $url_parts ) {
|
||||
if ( ! isset( $url_parts['host'] ) && isset( $url_parts['path'] ) ) {
|
||||
$domain_and_subdir = explode( '/', $url_parts['path'] );
|
||||
$domain = $domain_and_subdir[0];
|
||||
$url_parts['host'] = $domain;
|
||||
array_shift( $domain_and_subdir );
|
||||
|
||||
if ( $domain_and_subdir ) {
|
||||
$url_parts['path'] = preg_replace( '/^(' . $url_parts['host'] . ')/', '', $url_parts['path'] );
|
||||
} else {
|
||||
unset( $url_parts['path'] );
|
||||
}
|
||||
}
|
||||
|
||||
return $url_parts;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $path
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function is_file_path( $path ) {
|
||||
$pathinfo = pathinfo( $path );
|
||||
return isset( $pathinfo['extension'] ) && $pathinfo['extension'];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
class WPML_String_Functions {
|
||||
|
||||
public static function is_css_color( $string ) {
|
||||
return (bool) preg_match( '/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/im', $string );
|
||||
}
|
||||
|
||||
public static function is_css_length( $string ) {
|
||||
$parts = explode( ' ', $string );
|
||||
foreach ( $parts as $part ) {
|
||||
if ( ! (bool) preg_match( '/^[+-]?[0-9]+.?([0-9]+)?(px|em|ex|ch|rem|vw|vh|vmin|vmax|%|in|cm|mm|pt|pc)$/im', $part ) &&
|
||||
'0' !== $part ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function is_numeric( $string ) {
|
||||
return (bool) is_numeric( $string );
|
||||
}
|
||||
|
||||
public static function is_not_translatable( $string ) {
|
||||
return self::is_css_color( $string ) ||
|
||||
self::is_css_length( $string ) ||
|
||||
self::is_numeric( $string );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
class WPML_Temporary_Switch_Admin_Language extends WPML_SP_User {
|
||||
|
||||
private $old_lang = false;
|
||||
|
||||
/**
|
||||
* @param SitePress $sitepress
|
||||
* @param string $target_lang
|
||||
*/
|
||||
public function __construct( &$sitepress, $target_lang ) {
|
||||
parent::__construct( $sitepress );
|
||||
$this->old_lang = $sitepress->get_admin_language();
|
||||
$sitepress->set_admin_language( $target_lang );
|
||||
}
|
||||
|
||||
public function __destruct() {
|
||||
$this->restore_lang();
|
||||
}
|
||||
|
||||
public function restore_lang () {
|
||||
if ( $this->old_lang ) {
|
||||
$this->sitepress->set_admin_language( $this->old_lang );
|
||||
$this->old_lang = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
class WPML_Temporary_Switch_Language extends WPML_SP_User {
|
||||
|
||||
private $old_lang = false;
|
||||
|
||||
/**
|
||||
* @param SitePress $sitepress
|
||||
* @param string $target_lang
|
||||
*/
|
||||
public function __construct( &$sitepress, $target_lang ) {
|
||||
parent::__construct( $sitepress );
|
||||
$this->old_lang = $sitepress->get_current_language();
|
||||
$sitepress->switch_lang( $target_lang );
|
||||
}
|
||||
|
||||
public function __destruct() {
|
||||
$this->restore_lang();
|
||||
}
|
||||
|
||||
public function restore_lang () {
|
||||
if ( $this->old_lang ) {
|
||||
$this->sitepress->switch_lang( $this->old_lang );
|
||||
$this->old_lang = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class WPML_Transient
|
||||
*
|
||||
* Due to some conflicts between cached environments (e.g. using W3TC) and the normal
|
||||
* WP Transients API, we've added this class which should behaves almost like the normal
|
||||
* transients API. Except for the fact that it is stored as normal options, so WP won't
|
||||
* recognize/treat it as a transient.
|
||||
*/
|
||||
class WPML_Transient {
|
||||
|
||||
const WPML_TRANSIENT_PREFIX = '_wpml_transient_';
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param string $value
|
||||
* @param string $expiration
|
||||
*/
|
||||
public function set( $name, $value, $expiration = '' ) {
|
||||
$data = array(
|
||||
'value' => $value,
|
||||
'expiration' => $expiration ? time() + (int) $expiration : '',
|
||||
);
|
||||
|
||||
update_option( self::WPML_TRANSIENT_PREFIX . $name, $data );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get( $name ) {
|
||||
$data = get_option( self::WPML_TRANSIENT_PREFIX . $name );
|
||||
|
||||
if ( $data ) {
|
||||
if ( (int) $data['expiration'] < time() ) {
|
||||
delete_option( self::WPML_TRANSIENT_PREFIX . $name );
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
return $data['value'];
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
*/
|
||||
public function delete( $name ) {
|
||||
delete_option( self::WPML_TRANSIENT_PREFIX . $name );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
class WPML_Translate_Link_Targets {
|
||||
|
||||
/* @var AbsoluteLinks $absolute_links */
|
||||
private $absolute_links;
|
||||
/* @var WPML_Absolute_To_Permalinks $permalinks_converter */
|
||||
private $permalinks_converter;
|
||||
|
||||
/**
|
||||
* WPML_Translate_Link_Targets constructor.
|
||||
*
|
||||
* @param AbsoluteLinks $absolute_links
|
||||
* @param WPML_Absolute_To_Permalinks $permalinks_converter
|
||||
*/
|
||||
public function __construct( AbsoluteLinks $absolute_links, WPML_Absolute_To_Permalinks $permalinks_converter ) {
|
||||
$this->absolute_links = $absolute_links;
|
||||
$this->permalinks_converter = $permalinks_converter;
|
||||
}
|
||||
|
||||
/**
|
||||
* convert_text
|
||||
*
|
||||
* @param string $text
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
|
||||
public function convert_text( $text ) {
|
||||
if ( is_string( $text ) ) {
|
||||
$text = $this->absolute_links->convert_text( $text );
|
||||
$text = $this->permalinks_converter->convert_text( $text );
|
||||
}
|
||||
|
||||
return $text;
|
||||
}
|
||||
|
||||
public function is_internal_url( $url ) {
|
||||
$absolute_url = $this->absolute_links->convert_url( $url );
|
||||
return $url != $absolute_url || $this->absolute_links->is_home( $url );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $url
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function convert_url( $url ) {
|
||||
$link = '<a href="' . $url . '">removeit</a>';
|
||||
$link = $this->convert_text( $link );
|
||||
return str_replace( array( '<a href="', '">removeit</a>' ), array( '', '' ), $link );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
class WPML_WP_Cache_Factory {
|
||||
|
||||
public function create_cache_group( $group ) {
|
||||
return new WPML_WP_Cache( $group );
|
||||
}
|
||||
|
||||
public function create_cache_item( $group, $key ) {
|
||||
return new WPML_WP_Cache_Item( $this->create_cache_group( $group ), $key );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
class WPML_WP_Cache_Item {
|
||||
|
||||
/** @var string $key */
|
||||
private $key;
|
||||
|
||||
/** @var WPML_WP_Cache $cache */
|
||||
private $cache;
|
||||
|
||||
/**
|
||||
* WPML_WP_Cache_Item constructor.
|
||||
*
|
||||
* @param WPML_WP_Cache $cache
|
||||
* @param string|array $key
|
||||
*/
|
||||
public function __construct( WPML_WP_Cache $cache, $key ) {
|
||||
if ( is_array( $key ) ) {
|
||||
$key = md5( json_encode( $key ) );
|
||||
}
|
||||
$this->cache = $cache;
|
||||
$this->key = $key;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function exists() {
|
||||
|
||||
$found = false;
|
||||
$this->cache->get( $this->key, $found );
|
||||
return $found;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function get() {
|
||||
$found = false;
|
||||
return $this->cache->get( $this->key, $found );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function set( $value ) {
|
||||
$this->cache->set( $this->key, $value );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
<?php
|
||||
|
||||
class WPML_WP_Cache {
|
||||
|
||||
/** @var string Key name under which array of all group keys is stored */
|
||||
const KEYS = 'WPML_WP_Cache__group_keys';
|
||||
|
||||
/** @var string Group name */
|
||||
private $group;
|
||||
|
||||
/**
|
||||
* WPML_WP_Cache constructor.
|
||||
*
|
||||
* @param string $group Optional. Where the cache contents are grouped. Default empty.
|
||||
*/
|
||||
public function __construct( $group = '' ) {
|
||||
$this->group = $group;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the cache contents from the cache by key and group.
|
||||
*
|
||||
* @param int|string $key The key under which the cache contents are stored.
|
||||
* @param bool $found Optional. Whether the key was found in the cache (passed by reference).
|
||||
* Disambiguates a return of false, a storable value. Default null.
|
||||
*
|
||||
* @return bool|mixed False on failure to retrieve contents or the cache
|
||||
* contents on success
|
||||
*/
|
||||
public function get( $key, &$found = null ) {
|
||||
$value = wp_cache_get( $key, $this->group, false, $found );
|
||||
if ( is_array( $value ) && array_key_exists( 'data', $value ) ) {
|
||||
// We know that we have set something in the cache.
|
||||
$found = true;
|
||||
|
||||
return $value['data'];
|
||||
} else {
|
||||
$found = false;
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the data to the cache.
|
||||
*
|
||||
* @param int|string $key The cache key to use for retrieval later.
|
||||
* @param mixed $data The contents to store in the cache.
|
||||
* @param int $expire Optional. When to expire the cache contents, in seconds.
|
||||
* Default 0 (no expiration).
|
||||
*
|
||||
* @return bool False on failure, true on success
|
||||
*/
|
||||
public function set( $key, $data, $expire = 0 ) {
|
||||
$keys = $this->get_keys();
|
||||
if ( ! in_array( $key, $keys, true ) ) {
|
||||
$keys[] = $key;
|
||||
wp_cache_set( self::KEYS, $keys, $this->group );
|
||||
}
|
||||
|
||||
// Save $value in an array. We need to do this because W3TC and Redis have bug with saving null.
|
||||
return wp_cache_set( $key, [ 'data' => $data ], $this->group, $expire );
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the cache contents matching key and group.
|
||||
*/
|
||||
public function flush_group_cache() {
|
||||
$keys = $this->get_keys();
|
||||
|
||||
foreach ( $keys as $key ) {
|
||||
wp_cache_delete( $key, $this->group );
|
||||
}
|
||||
|
||||
wp_cache_delete( self::KEYS, $this->group );
|
||||
}
|
||||
|
||||
public function execute_and_cache( $key, $callback ) {
|
||||
list( $result, $found ) = $this->get_with_found( $key );
|
||||
if ( ! $found ) {
|
||||
$result = $callback();
|
||||
$this->set( $key, $result );
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
*
|
||||
* @return array {
|
||||
* @type mixed $result @see Return value of \wp_cache_get.
|
||||
* @type bool $found @see `$found` argument of \wp_cache_get.
|
||||
* }
|
||||
*/
|
||||
public function get_with_found( $key ) {
|
||||
$found = false;
|
||||
$result = $this->get( $key, $found );
|
||||
|
||||
return [ $result, $found ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get stored group keys.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_keys() {
|
||||
$found = false;
|
||||
$keys = wp_cache_get( self::KEYS, $this->group, false, $found );
|
||||
if ( $found && is_array( $keys ) ) {
|
||||
return $keys;
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
class WPML_WP_Post {
|
||||
/** @var wpdb $wpdb */
|
||||
public $wpdb;
|
||||
|
||||
/** @var int */
|
||||
private $post_id;
|
||||
|
||||
/**
|
||||
* @param wpdb $wpdb
|
||||
* @param int $post_id
|
||||
*/
|
||||
public function __construct( wpdb $wpdb, $post_id ) {
|
||||
$this->wpdb = $wpdb;
|
||||
$this->post_id = $post_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $post_data_array
|
||||
* @param bool $direct_db_update
|
||||
*/
|
||||
public function update( array $post_data_array, $direct_db_update = false) {
|
||||
if ( $direct_db_update ) {
|
||||
$this->wpdb->update( $this->wpdb->posts, $post_data_array, array( 'ID' => $this->post_id ) );
|
||||
clean_post_cache( $this->post_id );
|
||||
} else {
|
||||
$post_data_array['ID'] = $this->post_id;
|
||||
wpml_update_escaped_post( $post_data_array );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
class WPML_WP_Query_API {
|
||||
|
||||
private $wp_query;
|
||||
|
||||
public function __construct( &$wp_query ) {
|
||||
$this->wp_query = $wp_query;
|
||||
}
|
||||
|
||||
public function get_first_post_type() {
|
||||
$post_type = null;
|
||||
if ( isset( $this->wp_query->query_vars['post_type'] ) ) {
|
||||
$post_type = $this->wp_query->query_vars['post_type'];
|
||||
if ( is_array( $post_type ) ) {
|
||||
if ( count( $post_type ) ) {
|
||||
$post_type = $post_type[0];
|
||||
} else {
|
||||
$post_type = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $post_type;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
class WPML_WP_Taxonomy_Query {
|
||||
private $taxonomies_query_vars;
|
||||
|
||||
public function __construct( $wp_api ) {
|
||||
|
||||
$wp_taxonomies = $wp_api->get_wp_taxonomies();
|
||||
|
||||
$this->taxonomies_query_vars = array();
|
||||
|
||||
foreach ( $wp_taxonomies as $k => $v ) {
|
||||
if ( $k === 'category' ) {
|
||||
continue;
|
||||
}
|
||||
if ( $k == 'post_tag' && ! $v->query_var ) {
|
||||
$tag_base = $wp_api->get_option( 'tag_base', 'tag' );
|
||||
$v->query_var = $tag_base;
|
||||
}
|
||||
if ( $v->query_var ) {
|
||||
$this->taxonomies_query_vars[ $k ] = $v->query_var;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function get_query_vars() {
|
||||
return $this->taxonomies_query_vars;
|
||||
}
|
||||
|
||||
public function find( $taxonomy ) {
|
||||
$tax = false;
|
||||
if ( isset( $this->taxonomies_query_vars ) && is_array( $this->taxonomies_query_vars ) ) {
|
||||
$tax = array_search( $taxonomy, $this->taxonomies_query_vars );
|
||||
}
|
||||
return $tax;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\Utilities;
|
||||
|
||||
class KeyedLock extends Lock {
|
||||
|
||||
/** @var string $keyName */
|
||||
private $keyName;
|
||||
|
||||
/**
|
||||
* Lock constructor.
|
||||
*
|
||||
* @param \wpdb $wpdb
|
||||
* @param string $name
|
||||
*/
|
||||
public function __construct( \wpdb $wpdb, $name ) {
|
||||
$this->keyName = 'wpml.' . $name . '.lock.key';
|
||||
parent::__construct( $wpdb, $name );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param int $release_timeout
|
||||
*
|
||||
* @return string|false The key or false if could not acquire the lock
|
||||
*/
|
||||
public function create( $key = null, $release_timeout = null ) {
|
||||
$acquired = parent::create( $release_timeout );
|
||||
|
||||
if ( $acquired ) {
|
||||
|
||||
if ( ! $key ) {
|
||||
$key = wp_generate_uuid4();
|
||||
}
|
||||
|
||||
update_option( $this->keyName, $key );
|
||||
return $key;
|
||||
} elseif ( $key === get_option( $this->keyName ) ) {
|
||||
$this->extendTimeout();
|
||||
return $key;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function release() {
|
||||
delete_option( $this->keyName );
|
||||
return parent::release();
|
||||
}
|
||||
|
||||
private function extendTimeout() {
|
||||
update_option( $this->name, time() );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\Utilities;
|
||||
|
||||
class NullLock implements ILock {
|
||||
|
||||
public function create( $release_timeout = null ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function release() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
class WPML_User extends WP_User {
|
||||
|
||||
/**
|
||||
* @see \get_user_meta
|
||||
*
|
||||
* @param string $key
|
||||
* @param bool $single
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function get_meta( $key = '', $single = false ) {
|
||||
return get_user_meta( $this->ID, $key, $single );
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \update_meta
|
||||
*
|
||||
* @param string $key
|
||||
* @param mixed $value
|
||||
* @param mixed $prev_value
|
||||
*/
|
||||
public function update_meta( $key, $value, $prev_value = '' ) {
|
||||
update_user_meta( $this->ID, $key, $value, $prev_value );
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \get_user_option
|
||||
*
|
||||
* @param string $option
|
||||
* @return mixed
|
||||
*/
|
||||
public function get_option( $option ) {
|
||||
return get_user_option( $option, $this->ID );
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \update_user_option
|
||||
*
|
||||
* @param string $option_name
|
||||
* @param mixed $new_value
|
||||
* @param bool $global
|
||||
* @return int|bool
|
||||
*/
|
||||
function update_option( $option_name, $new_value, $global = false ) {
|
||||
return update_user_option( $this->ID, $option_name, $new_value, $global );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
class WPML_WP_User_Factory {
|
||||
|
||||
public function create( $user_id ) {
|
||||
return new WPML_User( $user_id );
|
||||
}
|
||||
|
||||
public function create_by_email( $user_email ) {
|
||||
$user = get_user_by( 'email', $user_email );
|
||||
return new WPML_User( $user->ID );
|
||||
}
|
||||
|
||||
public function create_current() {
|
||||
return new WPML_User( get_current_user_id() );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
class WPML_WP_User_Query_Factory {
|
||||
|
||||
public function create( $args ) {
|
||||
return new WP_User_Query( $args );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
<?php
|
||||
|
||||
class WPML_Languages_Notices {
|
||||
const NOTICE_ID_MISSING_MENU_ITEMS = 'wpml-missing-menu-items';
|
||||
const NOTICE_GROUP = 'wpml-core';
|
||||
const NOTICE_ID_MISSING_DOWNLOADED_LANGUAGES = 'wpml-missing-downloaded-languages';
|
||||
/** @var WPML_Notices */
|
||||
private $admin_notices;
|
||||
private $translations = array();
|
||||
|
||||
/**
|
||||
* WPML_Languages_Notices constructor.
|
||||
*
|
||||
* @param WPML_Notices $admin_notices
|
||||
*/
|
||||
public function __construct( WPML_Notices $admin_notices ) {
|
||||
$this->admin_notices = $admin_notices;
|
||||
}
|
||||
|
||||
function maybe_create_notice_missing_menu_items( $languages_count ) {
|
||||
if ( 1 === $languages_count ) {
|
||||
$text = __( 'You need to configure at least one more language in order to access "Theme and plugins localization" and "Media translation".', 'sitepress' );
|
||||
$notice = new WPML_Notice( self::NOTICE_ID_MISSING_MENU_ITEMS, $text, self::NOTICE_GROUP );
|
||||
$notice->set_css_class_types( 'info' );
|
||||
$notice->set_dismissible( true );
|
||||
$this->admin_notices->add_notice( $notice );
|
||||
} else {
|
||||
$this->admin_notices->remove_notice( self::NOTICE_GROUP, self::NOTICE_ID_MISSING_MENU_ITEMS );
|
||||
}
|
||||
}
|
||||
|
||||
public function missing_languages( $not_found_languages ) {
|
||||
$list_items = array();
|
||||
if ( $not_found_languages ) {
|
||||
$list_item_pattern = __( '%1$s (current locale: %2$s) - suggested locale(s): %3$s', 'sitepress' );
|
||||
|
||||
foreach ( (array) $not_found_languages as $not_found_language ) {
|
||||
$suggested_codes = $this->get_suggestions( $not_found_language );
|
||||
if ( $suggested_codes ) {
|
||||
$suggestions = '<strong>' . implode( '</strong>, <strong>', $suggested_codes ) . '</strong>';
|
||||
$current = $not_found_language['code'];
|
||||
if ( $not_found_language['default_locale'] ) {
|
||||
$current = $not_found_language['default_locale'];
|
||||
}
|
||||
$list_items[] = sprintf( $list_item_pattern, $not_found_language['display_name'], $current, $suggestions );
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( $list_items ) {
|
||||
$text = '';
|
||||
|
||||
$text .= '<p>';
|
||||
$text .= __( 'WordPress cannot automatically download translations for the following languages:', 'sitepress' );
|
||||
$text .= '</p>';
|
||||
|
||||
$text .= '<ul>';
|
||||
$text .= '<li>';
|
||||
$text .= implode( '</li><li>', $list_items );
|
||||
$text .= '</li>';
|
||||
$text .= '</ul>';
|
||||
|
||||
$languages_edit_url = admin_url( 'admin.php?page=' . WPML_PLUGIN_FOLDER . '/menu/languages.php&trop=1' );
|
||||
$languages_edit_link = '<a href="' . $languages_edit_url . '">';
|
||||
$languages_edit_link .= __( 'Edit Languages', 'sitepress' );
|
||||
$languages_edit_link .= '</a>';
|
||||
|
||||
$text .= '<p>';
|
||||
$text .= sprintf( __( 'To fix, open "%s" and set the "default locale" values as shown above.', 'sitepress' ), $languages_edit_link );
|
||||
$text .= '</p>';
|
||||
|
||||
$notice = new WPML_Notice( self::NOTICE_ID_MISSING_DOWNLOADED_LANGUAGES, $text, self::NOTICE_GROUP );
|
||||
$notice->set_css_class_types( 'warning' );
|
||||
$notice->add_display_callback( array( $this, 'is_not_languages_edit_page' ) );
|
||||
$notice->set_dismissible( true );
|
||||
$this->admin_notices->add_notice( $notice, true );
|
||||
} else {
|
||||
$this->admin_notices->remove_notice( self::NOTICE_GROUP, self::NOTICE_ID_MISSING_DOWNLOADED_LANGUAGES );
|
||||
}
|
||||
}
|
||||
|
||||
public function is_not_languages_edit_page() {
|
||||
$result = isset( $_GET['page'], $_GET['trop'] ) && WPML_PLUGIN_FOLDER . '/menu/languages.php' === $_GET['page'] && 1 === (int) $_GET['trop'];
|
||||
|
||||
return ! $result;
|
||||
}
|
||||
|
||||
private function get_suggestions( array $language ) {
|
||||
$suggestions = array();
|
||||
if ( function_exists( 'translations_api' ) ) {
|
||||
if ( ! $this->translations ) {
|
||||
$api = translations_api( 'core', array( 'version' => $GLOBALS['wp_version'] ) );
|
||||
|
||||
if ( ! is_wp_error( $api ) ) {
|
||||
$this->translations = $api['translations'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( $this->translations ) {
|
||||
foreach ( $this->translations as $translation ) {
|
||||
$default_locale = $this->get_matching_language( $language, $translation );
|
||||
if ( $default_locale ) {
|
||||
$suggestions[] = $default_locale;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $suggestions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $language_attribute
|
||||
* @param array $language
|
||||
* @param array $translation
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
private function find_matching_attribute( $language_attribute, array $language, array $translation ) {
|
||||
if ( $translation && $language[ $language_attribute ] ) {
|
||||
$attribute_value = $language[ $language_attribute ];
|
||||
$attribute_value = str_replace( '-', '_', $attribute_value );
|
||||
$attribute_value = strtolower( $attribute_value );
|
||||
$iso_1 = $iso_2 = '';
|
||||
|
||||
if ( array_key_exists( 1, $translation['iso'] ) ) {
|
||||
$iso_1 = strtolower( $translation['iso'][1] );
|
||||
}
|
||||
if ( array_key_exists( 2, $translation['iso'] ) ) {
|
||||
$iso_2 = strtolower( $translation['iso'][2] );
|
||||
}
|
||||
|
||||
if ( $iso_1 === $attribute_value ) {
|
||||
return $translation['language'];
|
||||
}
|
||||
if ( $iso_2 === $attribute_value ) {
|
||||
return $translation['language'];
|
||||
}
|
||||
if ( $iso_1 . '_' . $iso_2 === $attribute_value ) {
|
||||
return $translation['language'];
|
||||
}
|
||||
if ( $iso_2 . '_' . $iso_1 === $attribute_value ) {
|
||||
return $translation['language'];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $language
|
||||
* @param array $translation
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
private function get_matching_language( array $language, array $translation ) {
|
||||
$default_locale = $this->find_matching_attribute( 'default_locale', $language, $translation );
|
||||
if ( ! $default_locale ) {
|
||||
$default_locale = $this->find_matching_attribute( 'tag', $language, $translation );
|
||||
if ( ! $default_locale ) {
|
||||
$default_locale = $this->find_matching_attribute( 'code', $language, $translation );
|
||||
}
|
||||
}
|
||||
|
||||
return $default_locale;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class WPML_Queried_Object
|
||||
*
|
||||
* @author OnTheGoSystems
|
||||
*/
|
||||
class WPML_Queried_Object {
|
||||
|
||||
/** @var SitePress $sitepress */
|
||||
private $sitepress;
|
||||
|
||||
/** @var null|object */
|
||||
private $queried_object;
|
||||
|
||||
/** @var stdClass $queried_object_details */
|
||||
private $queried_object_details;
|
||||
|
||||
/**
|
||||
* WPML_TF_Queried_Object constructor.
|
||||
*
|
||||
* @param SitePress $sitepress
|
||||
*/
|
||||
public function __construct( SitePress $sitepress ) {
|
||||
$this->sitepress = $sitepress;
|
||||
$this->queried_object = get_queried_object();
|
||||
}
|
||||
|
||||
public function has_object() {
|
||||
return (bool) $this->queried_object;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null|string
|
||||
*/
|
||||
public function get_source_language_code() {
|
||||
return $this->get_queried_object_detail( 'source_language_code' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function get_language_code() {
|
||||
return $this->get_queried_object_detail( 'language_code' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
*
|
||||
* @return null|mixed
|
||||
*/
|
||||
private function get_queried_object_detail( $key ) {
|
||||
$detail = null;
|
||||
|
||||
if ( ! $this->queried_object_details ) {
|
||||
|
||||
if ( $this->is_post() ) {
|
||||
|
||||
$this->queried_object_details = $this->sitepress->get_element_language_details(
|
||||
$this->get_id(),
|
||||
$this->get_element_type()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ( isset( $this->queried_object_details->{$key} ) ) {
|
||||
$detail = $this->queried_object_details->{$key};
|
||||
}
|
||||
|
||||
return $detail;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function is_post() {
|
||||
return isset( $this->queried_object->ID, $this->queried_object->post_type );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null|int
|
||||
*/
|
||||
public function get_id() {
|
||||
$id = null;
|
||||
|
||||
if ( isset( $this->queried_object->ID ) ) {
|
||||
$id = $this->queried_object->ID;
|
||||
}
|
||||
|
||||
return $id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null|string
|
||||
*/
|
||||
public function get_element_type() {
|
||||
$type = null;
|
||||
|
||||
if ( $this->is_instance_of_post_type() ) {
|
||||
$type = 'post_' . $this->get_post_type_name();
|
||||
}
|
||||
if ( $this->is_instance_of_post() ) {
|
||||
$type = 'post_' . $this->get_post_type();
|
||||
}
|
||||
if ( $this->is_instance_of_taxonomy() ) {
|
||||
$type = 'tax_' . $this->get_taxonomy();
|
||||
}
|
||||
|
||||
return $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null|string
|
||||
*/
|
||||
public function get_source_url() {
|
||||
$url = null;
|
||||
$language_links = $this->sitepress->get_ls_languages();
|
||||
|
||||
if ( isset( $language_links[ $this->get_source_language_code() ]['url'] ) ) {
|
||||
$url = $language_links[ $this->get_source_language_code() ]['url'];
|
||||
}
|
||||
|
||||
return $url;
|
||||
}
|
||||
|
||||
public function get_post_type() {
|
||||
if ( $this->is_instance_of_post() ) {
|
||||
return $this->queried_object->post_type;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function get_taxonomy() {
|
||||
if ( $this->is_instance_of_taxonomy() ) {
|
||||
return $this->queried_object->taxonomy;
|
||||
}
|
||||
}
|
||||
|
||||
public function get_post_type_name() {
|
||||
if ( $this->is_instance_of_post_type() ) {
|
||||
return $this->queried_object->name;
|
||||
}
|
||||
}
|
||||
|
||||
public function is_instance_of_post() {
|
||||
return $this->queried_object instanceof WP_Post;
|
||||
}
|
||||
|
||||
public function is_instance_of_taxonomy() {
|
||||
return $this->queried_object instanceof WP_Term;
|
||||
}
|
||||
|
||||
public function is_instance_of_post_type() {
|
||||
return $this->queried_object instanceof WP_Post_Type;
|
||||
}
|
||||
|
||||
public function is_instance_of_user() {
|
||||
return $this->queried_object instanceof WP_User;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
class WPML_UUID {
|
||||
/**
|
||||
* @param string $object_id
|
||||
* @param string $object_type
|
||||
* @param int $timestamp
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get( $object_id, $object_type, $timestamp = null ) {
|
||||
$timestamp = $timestamp ? $timestamp : time();
|
||||
$name = $object_id . ':' . $object_type . ':' . $timestamp;
|
||||
|
||||
return $this->get_uuid_v5( $name, wpml_get_site_id() );
|
||||
}
|
||||
|
||||
/**
|
||||
* RFC 4122 compliant UUIDs.
|
||||
*
|
||||
* The RFC 4122 specification defines a Uniform Resource Name namespace for
|
||||
* UUIDs (Universally Unique Identifier), also known as GUIDs (Globally
|
||||
* Unique Identifier). A UUID is 128 bits long, and requires no central
|
||||
* registration process.
|
||||
*
|
||||
* @package UUID
|
||||
* @license https://www.gnu.org/licenses/gpl-2.0.txt GPLv2
|
||||
* @author bjornjohansen
|
||||
* @see https://bjornjohansen.no/uuid-as-wordpress-guid
|
||||
*
|
||||
* RFC 4122 compliant UUID version 5.
|
||||
*
|
||||
* @param string $name The name to generate the UUID from.
|
||||
* @param string $ns_uuid Namespace UUID. Default is for the NS when name string is a URL.
|
||||
*
|
||||
* @return string The UUID string.
|
||||
*/
|
||||
public function get_uuid_v5( $name, $ns_uuid = '6ba7b811-9dad-11d1-80b4-00c04fd430c8' ) {
|
||||
// Compute the hash of the name space ID concatenated with the name.
|
||||
$hash = sha1( $ns_uuid . $name );
|
||||
|
||||
// Intialize the octets with the 16 first octets of the hash, and adjust specific bits later.
|
||||
$octets = str_split( substr( $hash, 0, 16 ), 1 );
|
||||
|
||||
/*
|
||||
* Set version to 0101 (UUID version 5).
|
||||
*
|
||||
* Set the four most significant bits (bits 12 through 15) of the
|
||||
* time_hi_and_version field to the appropriate 4-bit version number
|
||||
* from Section 4.1.3.
|
||||
*
|
||||
* That is 0101 for version 5.
|
||||
* time_hi_and_version is octets 6–7
|
||||
*/
|
||||
$octets[6] = chr( ord( $octets[6] ) & 0x0f | 0x50 );
|
||||
|
||||
/*
|
||||
* Set the UUID variant to the one defined by RFC 4122, according to RFC 4122 section 4.1.1.
|
||||
*
|
||||
* Set the two most significant bits (bits 6 and 7) of the
|
||||
* clock_seq_hi_and_reserved to zero and one, respectively.
|
||||
*
|
||||
* clock_seq_hi_and_reserved is octet 8
|
||||
*/
|
||||
$octets[8] = chr( ord( $octets[8] ) & 0x3f | 0x80 );
|
||||
|
||||
// Hex encode the octets for string representation.
|
||||
$octets = array_map( 'bin2hex', $octets );
|
||||
|
||||
// Return the octets in the format specified by the ABNF in RFC 4122 section 3.
|
||||
return vsprintf( '%s%s-%s-%s-%s-%s%s%s', str_split( implode( '', $octets ), 4 ) );
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user