first commit
This commit is contained in:
@@ -0,0 +1,237 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\TM\Menu\TranslationBasket;
|
||||
|
||||
use WPML\FP\Obj;
|
||||
use WPML\Notices\DismissNotices;
|
||||
use WPML\TM\API\ATE\Account;
|
||||
use WPML\WP\OptionManager;
|
||||
|
||||
class Strings {
|
||||
|
||||
const ATE_AUTOMATIC_TRANSLATION_SUGGESTION = 'wpml-ate-automatic-translation-suggestion';
|
||||
|
||||
/** @var Utility */
|
||||
private $utility;
|
||||
|
||||
/** @var DismissNotices */
|
||||
private $dismissNotices;
|
||||
|
||||
/**
|
||||
* @param Utility $utility
|
||||
* @param DismissNotices $dismissNotices
|
||||
*/
|
||||
public function __construct( Utility $utility, DismissNotices $dismissNotices ) {
|
||||
$this->utility = $utility;
|
||||
$this->dismissNotices = $dismissNotices;
|
||||
}
|
||||
|
||||
|
||||
public function getAll() {
|
||||
$isCurrentUserOnlyTranslator = $this->utility->isTheOnlyAvailableTranslator();
|
||||
|
||||
return [
|
||||
'jobs_sent_to_local_translator' => $this->jobsSentToLocalTranslator(),
|
||||
'jobs_emails_local_did_not_sent' => $this->emailNotSentError(),
|
||||
'jobs_committed' => $isCurrentUserOnlyTranslator ? $this->jobsSentToCurrentUserWhoIsTheOnlyTranslator() : $this->jobsSentDefaultMessage(),
|
||||
'jobs_committing' => __( 'Working...', 'wpml-translation-management' ),
|
||||
'error_occurred' => __( 'An error occurred:', 'wpml-translation-management' ),
|
||||
'error_not_allowed' => __(
|
||||
'You are not allowed to run this action.',
|
||||
'wpml-translation-management'
|
||||
),
|
||||
'batch' => __( 'Batch', 'wpml-translation-management' ),
|
||||
'error_no_translators' => __( 'No selected translators!', 'wpml-translation-management' ),
|
||||
'rollbacks' => __( 'Rollback jobs...', 'wpml-translation-management' ),
|
||||
'rolled' => __( 'Batch rolled back', 'wpml-translation-management' ),
|
||||
'errors' => __( 'Errors:', 'wpml-translation-management' ),
|
||||
'sending_batch' => $isCurrentUserOnlyTranslator ?
|
||||
__( 'Preparing your content for translation', 'wpml-translation-management' )
|
||||
: __( 'Sending your jobs to translation', 'wpml-translation-management' ),
|
||||
'sending_batch_to_ts' => __(
|
||||
'Sending your jobs to professional translation',
|
||||
'wpml-translation-management'
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function duplicatePostTranslationWarning() {
|
||||
$message = esc_html_x(
|
||||
'You are about to translate duplicated posts.',
|
||||
'1/2 Confirm to disconnect duplicates',
|
||||
'wpml-translation-management'
|
||||
);
|
||||
|
||||
$message .= "\n";
|
||||
|
||||
$message .= esc_html_x(
|
||||
'These items will be automatically disconnected from originals, so translation is not lost when you update the originals.',
|
||||
'2/2 Confirm to disconnect duplicates',
|
||||
'wpml-translation-management'
|
||||
);
|
||||
|
||||
return $message;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function jobsSentToLocalTranslator() {
|
||||
$translation_dashboard_url = admin_url( 'admin.php?page=' . WPML_TM_FOLDER . '/menu/main.php' );
|
||||
$translation_dashboard_text = esc_html__( 'Translation Dashboard', 'wpml-translation-management' );
|
||||
$translation_dashboard_link = '<a href="' . esc_url( $translation_dashboard_url ) . '">' . $translation_dashboard_text . '</a>';
|
||||
|
||||
$translation_notifications_url = admin_url( 'admin.php?page=' . WPML_TM_FOLDER . \WPML_Translation_Management::PAGE_SLUG_SETTINGS . '&sm=notifications' );
|
||||
$translation_notifications_text = esc_html__(
|
||||
'WPML → Settings → Translation notifications',
|
||||
'wpml-translation-management'
|
||||
);
|
||||
$translation_notifications_link = '<a href="' . esc_url( $translation_notifications_url ) . '">' . $translation_notifications_text . '</a>';
|
||||
|
||||
$template = '
|
||||
<p>%1$s</p>
|
||||
<ul>
|
||||
<li>%2$s</li>
|
||||
<li>%3$s</li>
|
||||
<li>%4$s</li>
|
||||
<li>%5$s</li>
|
||||
</ul>
|
||||
';
|
||||
|
||||
return sprintf(
|
||||
$template,
|
||||
esc_html__( 'All done. What happens next?', 'wpml-translation-management' ),
|
||||
esc_html__(
|
||||
'WPML sent emails to the translators, telling them about the new work from you.',
|
||||
'wpml-translation-management'
|
||||
),
|
||||
sprintf(
|
||||
esc_html__(
|
||||
'Your translators should log-in to their accounts in this site and go to %1$sWPML → Translations%2$s. There, they will see the jobs that are waiting for them.',
|
||||
'wpml-translation-management'
|
||||
),
|
||||
'<strong>',
|
||||
'</strong>'
|
||||
),
|
||||
sprintf(
|
||||
esc_html__(
|
||||
'You can always follow the progress of translation in the %1$s. For a more detailed view and to cancel jobs, visit the %2$s list.',
|
||||
'wpml-translation-management'
|
||||
),
|
||||
$translation_dashboard_link,
|
||||
$this->getJobsLink()
|
||||
),
|
||||
sprintf(
|
||||
esc_html__(
|
||||
'You can control email notifications to translators and yourself in %s.',
|
||||
'wpml-translation-management'
|
||||
),
|
||||
$translation_notifications_link
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function jobsSentToCurrentUserWhoIsTheOnlyTranslator() {
|
||||
return sprintf(
|
||||
'<p>%s</p><p>%s <a href="%s"><strong>%s</strong></a></p>',
|
||||
__( 'Ready!', 'wpml-translation-management' ),
|
||||
/* translators: This text is followed by 'Translation Queue'. eg To translate those jobs, go to the Translation Queue */
|
||||
__( 'To translate those jobs, go to ', 'wpml-translation-management' ),
|
||||
admin_url( 'admin.php?page=' . WPML_TM_FOLDER . '/menu/translations-queue.php' ),
|
||||
__( 'WPML → Translations', 'wpml-translation-management' )
|
||||
) . $this->automaticTranslationTip();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
private function automaticTranslationTip() {
|
||||
if (
|
||||
$this->dismissNotices->isDismissed( self::ATE_AUTOMATIC_TRANSLATION_SUGGESTION ) ||
|
||||
! \WPML_TM_ATE_Status::is_enabled_and_activated()
|
||||
|| Account::isAbleToTranslateAutomatically()
|
||||
) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$template = "
|
||||
<div id='wpml-tm-basket-automatic-translations-suggestion' >
|
||||
<h5>%s</h5>
|
||||
|
||||
<p>%s</p>
|
||||
|
||||
<p>%s <span>%s</span></p>
|
||||
</div>
|
||||
";
|
||||
|
||||
return sprintf(
|
||||
$template,
|
||||
esc_html__( 'Want to translate your content automatically?', 'wpml-translation-management' ),
|
||||
sprintf(
|
||||
esc_html__(
|
||||
'Go to %s and click the %sAutomatic Translation%s tab to create an account and start each month with 2,000 free translation credits!',
|
||||
'wpml-translation-management'
|
||||
),
|
||||
'<strong>' . $this->getTMLink() . '</strong>',
|
||||
'<strong>',
|
||||
'</strong>'
|
||||
),
|
||||
$this->dismissNotices->renderCheckbox( self::ATE_AUTOMATIC_TRANSLATION_SUGGESTION ),
|
||||
__( 'Don’t offer this again', 'wpml-translation-management' )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function jobsSentDefaultMessage() {
|
||||
$message = '<p>' . esc_html__( 'Ready!', 'wpml-translation-management' ) . '</p>';
|
||||
$message .= '<p>';
|
||||
$message .= sprintf(
|
||||
esc_html__(
|
||||
'You can check the status of these jobs in %s.',
|
||||
'wpml-translation-management'
|
||||
),
|
||||
$this->getJobsLink()
|
||||
);
|
||||
$message .= '</p>';
|
||||
|
||||
return $message;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
private function getJobsLink() {
|
||||
$url = admin_url( 'admin.php?page=' . WPML_TM_FOLDER . '/menu/main.php&sm=jobs' );
|
||||
$text = esc_html__( 'WPML → Translation Jobs', 'wpml-translation-management' );
|
||||
$link = '<a href="' . esc_url( $url ) . '">' . $text . '</a>';
|
||||
|
||||
return $link;
|
||||
}
|
||||
|
||||
private function getTMLink() {
|
||||
$url = admin_url( 'admin.php?page=' . WPML_TM_FOLDER . '/menu/main.php' );
|
||||
$text = esc_html__( 'WPML → Translation Management', 'wpml-translation-management' );
|
||||
$link = '<a href="' . esc_url( $url ) . '">' . $text . '</a>';
|
||||
|
||||
return $link;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function emailNotSentError() {
|
||||
return '<li><strong>' . esc_html__(
|
||||
'WPML could not send notification emails to the translators, telling them about the new work from you.',
|
||||
'wpml-translation-management'
|
||||
) . '</strong></li>';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\TM\Menu\TranslationBasket;
|
||||
|
||||
class Utility {
|
||||
/** @var \SitePress */
|
||||
private $sitepress;
|
||||
|
||||
/** @var \WPML_Translator_Records */
|
||||
private $translatorRecords;
|
||||
|
||||
/**
|
||||
* @param \SitePress $sitepress
|
||||
* @param \WPML_Translator_Records $translatorRecords
|
||||
*/
|
||||
public function __construct( \SitePress $sitepress, \WPML_Translator_Records $translatorRecords ) {
|
||||
$this->sitepress = $sitepress;
|
||||
$this->translatorRecords = $translatorRecords;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getTargetLanguages() {
|
||||
$basketLanguages = \TranslationProxy_Basket::get_target_languages();
|
||||
|
||||
$targetLanguages = [];
|
||||
|
||||
if ( $basketLanguages ) {
|
||||
|
||||
$notBasketLanguage = function ( $lang ) use ( $basketLanguages ) {
|
||||
return ! in_array( $lang['code'], $basketLanguages, true );
|
||||
};
|
||||
$isBasketSourceLanguage = function ( $lang ) {
|
||||
return \TranslationProxy_Basket::get_source_language() === $lang['code'];
|
||||
};
|
||||
$addFlag = function ( $lang ) {
|
||||
$lang['flag'] = $this->sitepress->get_flag_img( $lang['code'] );
|
||||
|
||||
return $lang;
|
||||
};
|
||||
$targetLanguages = wpml_collect( $this->sitepress->get_active_languages() )
|
||||
->reject( $notBasketLanguage )
|
||||
->reject( $isBasketSourceLanguage )
|
||||
->map( $addFlag )
|
||||
->toArray();
|
||||
}
|
||||
|
||||
return $targetLanguages;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $targetLanguages
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isTheOnlyAvailableTranslatorForTargetLanguages( $targetLanguages ) {
|
||||
if ( \TranslationProxy::is_current_service_active_and_authenticated() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$translators = $this->translatorRecords->get_users_with_languages(
|
||||
\TranslationProxy_Basket::get_source_language(),
|
||||
array_keys( $targetLanguages ),
|
||||
false
|
||||
);
|
||||
|
||||
return count( $translators ) === 1 && $translators[0]->ID === get_current_user_id();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isTheOnlyAvailableTranslator() {
|
||||
return $this->isTheOnlyAvailableTranslatorForTargetLanguages( $this->getTargetLanguages() );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined( 'WPINC' ) ) {
|
||||
die;
|
||||
}
|
||||
|
||||
class WPML_TM_Translate_Independently {
|
||||
|
||||
/** @var TranslationManagement $translation_management */
|
||||
private $translation_management;
|
||||
|
||||
/** @var WPML_Translation_Basket $translation_basket */
|
||||
private $translation_basket;
|
||||
|
||||
/** @var SitePress $sitepress */
|
||||
private $sitepress;
|
||||
|
||||
public function __construct(
|
||||
TranslationManagement $translation_management,
|
||||
WPML_Translation_Basket $translation_basket,
|
||||
SitePress $sitepress
|
||||
) {
|
||||
$this->translation_management = $translation_management;
|
||||
$this->translation_basket = $translation_basket;
|
||||
$this->sitepress = $sitepress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Init all plugin actions.
|
||||
*/
|
||||
public function init() {
|
||||
add_action( 'wp_ajax_icl_disconnect_posts', array( $this, 'ajax_disconnect_duplicates' ) );
|
||||
add_action( 'admin_footer', array( $this, 'add_hidden_field' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add hidden fields to TM basket.
|
||||
* #icl_duplicate_post_in_basket with list of duplicated ids in basket target languages.
|
||||
* #icl_disconnect_nonce nonce for AJAX call.
|
||||
*/
|
||||
public function add_hidden_field() {
|
||||
$basket = $this->translation_basket->get_basket( true );
|
||||
if ( ! isset( $basket['post'] ) ) {
|
||||
return;
|
||||
}
|
||||
$posts_ids_to_disconnect = $this->duplicates_to_disconnect( $basket['post'] );
|
||||
if ( $posts_ids_to_disconnect ) :
|
||||
?>
|
||||
<input type="hidden" value="<?php echo implode( ',', $posts_ids_to_disconnect ); ?>" id="icl_duplicate_post_in_basket">
|
||||
<input type="hidden" value="<?php echo wp_create_nonce( 'icl_disconnect_duplicates' ); ?>" id="icl_disconnect_nonce">
|
||||
<?php
|
||||
endif;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $basket_posts
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function duplicates_to_disconnect( $basket_posts ) {
|
||||
/** @var SitePress $sitepress */
|
||||
global $sitepress;
|
||||
$posts_to_disconnect = array();
|
||||
|
||||
foreach ( $basket_posts as $from_post => $data ) {
|
||||
$target_langs = array_keys( $data['to_langs'] );
|
||||
$element_type = 'post_' . get_post_type( $from_post );
|
||||
$trid = $sitepress->get_element_trid( $from_post, $element_type );
|
||||
$translations = $sitepress->get_element_translations( $trid, $element_type );
|
||||
|
||||
foreach ( $translations as $translation ) {
|
||||
if ( ! in_array( $translation->language_code, $target_langs, true ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$is_duplicate = get_post_meta( $translation->element_id, '_icl_lang_duplicate_of', true );
|
||||
|
||||
if ( $is_duplicate ) {
|
||||
$posts_to_disconnect[] = (int) $translation->element_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $posts_to_disconnect;
|
||||
}
|
||||
|
||||
/**
|
||||
* AJAX action to bulk disconnect posts before sending them to translation.
|
||||
*/
|
||||
public function ajax_disconnect_duplicates() {
|
||||
// Check nonce.
|
||||
if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( $_POST['nonce'], 'icl_disconnect_duplicates' ) ) {
|
||||
wp_send_json_error( esc_html__( 'Failed to disconnect posts', 'wpml-translation-management' ) );
|
||||
return;
|
||||
}
|
||||
|
||||
// Get post basket post ids.
|
||||
$post_ids = isset( $_POST['posts'] ) ? explode( ',', $_POST['posts'] ) : array();
|
||||
if ( empty( $post_ids ) ) {
|
||||
wp_send_json_error( esc_html__( 'No duplicate posts found to disconnect.', 'wpml-translation-management' ) );
|
||||
return;
|
||||
}
|
||||
|
||||
$post_ids = array_map( 'intval', $post_ids );
|
||||
array_walk( $post_ids, array( $this->translation_management, 'reset_duplicate_flag' ) );
|
||||
|
||||
wp_send_json_success( esc_html__( 'Successfully disconnected posts', 'wpml-translation-management' ) );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,444 @@
|
||||
<?php
|
||||
|
||||
use WPML\API\Sanitize;
|
||||
use WPML\TM\Menu\TranslationBasket\Strings;
|
||||
use function WPML\Container\make;
|
||||
|
||||
require_once WPML_TM_PATH . '/menu/sitepress-table.class.php';
|
||||
|
||||
class SitePress_Table_Basket extends SitePress_Table {
|
||||
|
||||
public static function enqueue_js() {
|
||||
/** @var WP_Locale $wp_locale */
|
||||
global $wp_locale;
|
||||
|
||||
wp_enqueue_script(
|
||||
'wpml-tm-translation-basket-and-options',
|
||||
WPML_TM_URL . '/res/js/translation-basket-and-options.js',
|
||||
array( 'wpml-tm-scripts', 'jquery-ui-progressbar', 'jquery-ui-datepicker', 'wpml-tooltip', 'wpml-tm-progressbar' ),
|
||||
WPML_TM_VERSION
|
||||
);
|
||||
|
||||
wp_localize_script(
|
||||
'wpml-tm-translation-basket-and-options',
|
||||
'wpml_tm_translation_basket_and_options',
|
||||
array(
|
||||
'day_names' => array_values( $wp_locale->weekday ),
|
||||
'day_initials' => array_values( $wp_locale->weekday_initial ),
|
||||
'month_names' => array_values( $wp_locale->month ),
|
||||
)
|
||||
);
|
||||
|
||||
wp_enqueue_style(
|
||||
'wpml-tm-jquery-ui-datepicker',
|
||||
WPML_TM_URL . '/res/css/jquery-ui/datepicker.css',
|
||||
array( 'wpml-tooltip' ),
|
||||
WPML_TM_VERSION
|
||||
);
|
||||
|
||||
/** @var Strings $strings */
|
||||
$strings = make( Strings::class );
|
||||
|
||||
$tm_basket_data = array(
|
||||
'nonce' => array(),
|
||||
'strings' => $strings->getAll(),
|
||||
'tmi_message' => $strings->duplicatePostTranslationWarning(),
|
||||
);
|
||||
|
||||
$tm_basket_data = apply_filters( 'translation_basket_and_options_js_data', $tm_basket_data );
|
||||
wp_localize_script(
|
||||
'wpml-tm-translation-basket-and-options',
|
||||
'tm_basket_data',
|
||||
$tm_basket_data
|
||||
);
|
||||
|
||||
wp_enqueue_script( 'wpml-tm-translation-basket-and-options' );
|
||||
}
|
||||
|
||||
function prepare_items() {
|
||||
$this->action_callback();
|
||||
|
||||
$this->get_data();
|
||||
|
||||
$columns = $this->get_columns();
|
||||
$hidden = array();
|
||||
$sortable = $this->get_sortable_columns();
|
||||
$this->_column_headers = array( $columns, $hidden, $sortable );
|
||||
|
||||
if ( $this->items ) {
|
||||
usort( $this->items, array( &$this, 'usort_reorder' ) );
|
||||
}
|
||||
}
|
||||
|
||||
function get_columns() {
|
||||
$columns = array(
|
||||
'title' => __( 'Title', 'wpml-translation-management' ),
|
||||
'type' => __( 'Type', 'wpml-translation-management' ),
|
||||
'status' => __( 'Status', 'wpml-translation-management' ),
|
||||
'languages' => __( 'Languages', 'wpml-translation-management' ),
|
||||
'words' => __( 'Words to translate', 'wpml-translation-management' ),
|
||||
'delete' => '',
|
||||
);
|
||||
|
||||
return $columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param object $item
|
||||
* @param string $column_name
|
||||
*
|
||||
* @return mixed|string
|
||||
*/
|
||||
function column_default( $item, $column_name ) {
|
||||
/**
|
||||
* WP base class is expecting an object, but we are using an array in our implementation.
|
||||
* Casting $item into an array prevents IDE warnings.
|
||||
*/
|
||||
$item = (array) $item;
|
||||
|
||||
switch ( $column_name ) {
|
||||
case 'title':
|
||||
case 'notes':
|
||||
return $item[ $column_name ];
|
||||
break;
|
||||
case 'type':
|
||||
return $this->get_post_type_label( $item[ $column_name ], $item );
|
||||
break;
|
||||
case 'status':
|
||||
return $this->get_post_status_label( $item[ $column_name ] );
|
||||
break;
|
||||
case 'words':
|
||||
return $item[ $column_name ];
|
||||
break;
|
||||
case 'languages':
|
||||
$target_languages_data = $item['target_languages'];
|
||||
$source_language_data = $item['source_language'];
|
||||
$target_languages = explode( ',', $target_languages_data );
|
||||
$languages = sprintf(
|
||||
__( '%1$s to %2$s', 'wpml-translation-management' ),
|
||||
$source_language_data,
|
||||
$target_languages_data
|
||||
);
|
||||
if ( count( $target_languages ) > 1 ) {
|
||||
$last_target_language = $target_languages[ count( $target_languages ) - 1 ];
|
||||
$first_target_languages = array_slice( $target_languages, 0, count( $target_languages ) - 1 );
|
||||
$languages = sprintf(
|
||||
__( '%1$s to %2$s and %3$s', 'wpml-translation-management' ),
|
||||
$source_language_data,
|
||||
implode( ',', $first_target_languages ),
|
||||
$last_target_language
|
||||
);
|
||||
}
|
||||
|
||||
return $languages;
|
||||
break;
|
||||
default:
|
||||
return print_r( $item, true ); // Show the whole array for troubleshooting purposes
|
||||
}
|
||||
}
|
||||
|
||||
function column_title( $item ) {
|
||||
return esc_html( $item['title'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $item
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function column_delete( $item ) {
|
||||
$qs = $_GET;
|
||||
$qs['page'] = $_REQUEST['page'];
|
||||
$qs['action'] = 'delete';
|
||||
$qs['id'] = $item['ID'];
|
||||
$qs['item_type'] = $item['item_type'];
|
||||
|
||||
$new_qs = esc_attr( http_build_query( $qs ) );
|
||||
|
||||
return sprintf(
|
||||
'<a href="?%s" title="%s" class="otgs-ico-cancel wpml-tm-delete"></a>',
|
||||
$new_qs,
|
||||
__( 'Remove from Translation Basket', 'wpml-translation-management' )
|
||||
);
|
||||
}
|
||||
|
||||
function no_items() {
|
||||
_e( 'The basket is empty', 'wpml-translation-management' );
|
||||
}
|
||||
|
||||
function get_sortable_columns() {
|
||||
$sortable_columns = array(
|
||||
'title' => array( 'title', true ),
|
||||
'type' => array( 'type', false ),
|
||||
'status' => array( 'status', false ),
|
||||
'languages' => array( 'languages', false ),
|
||||
'words' => array( 'words', false ),
|
||||
);
|
||||
|
||||
return $sortable_columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $post_id
|
||||
* @param $data
|
||||
* @param $item_type
|
||||
*/
|
||||
private function build_basket_item( $post_id, $data, $item_type ) {
|
||||
$this->items[ $item_type . '|' . $post_id ]['ID'] = $post_id;
|
||||
$this->items[ $item_type . '|' . $post_id ]['title'] = $data['post_title'];
|
||||
$this->items[ $item_type . '|' . $post_id ]['notes'] = isset( $data['post_notes'] ) ? $data['post_notes'] : '';
|
||||
$this->items[ $item_type . '|' . $post_id ]['type'] = $data['post_type'];
|
||||
$this->items[ $item_type . '|' . $post_id ]['status'] = isset( $data['post_status'] ) ? $data['post_status'] : '';
|
||||
$this->items[ $item_type . '|' . $post_id ]['source_language'] = $data['from_lang_string'];
|
||||
$this->items[ $item_type . '|' . $post_id ]['target_languages'] = $data['to_langs_string'];
|
||||
$this->items[ $item_type . '|' . $post_id ]['item_type'] = $item_type;
|
||||
$this->items[ $item_type . '|' . $post_id ]['words'] = $this->get_words_count( $post_id, $item_type, count( $data['to_langs'] ) );
|
||||
$this->items[ $item_type . '|' . $post_id ]['auto_added'] = isset( $data['auto_added'] ) && $data['auto_added'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $element_id
|
||||
* @param $element_type
|
||||
* @param $languages_count
|
||||
*/
|
||||
private function get_words_count( $element_id, $element_type, $languages_count ) {
|
||||
$records_factory = new WPML_TM_Word_Count_Records_Factory();
|
||||
$single_process_factory = new WPML_TM_Word_Count_Single_Process_Factory();
|
||||
$st_package_factory = class_exists( 'WPML_ST_Package_Factory' ) ? new WPML_ST_Package_Factory() : null;
|
||||
$element_provider = new WPML_TM_Translatable_Element_Provider( $records_factory->create(), $single_process_factory->create(), $st_package_factory );
|
||||
$translatable_element = $element_provider->get_from_type( $element_type, $element_id );
|
||||
|
||||
$count = null !== $translatable_element ? $translatable_element->get_words_count() : 0;
|
||||
|
||||
return $count * $languages_count;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $cart_items
|
||||
* @param $item_type
|
||||
*/
|
||||
private function build_basket_items( $cart_items, $item_type ) {
|
||||
if ( $cart_items ) {
|
||||
foreach ( $cart_items as $post_id => $data ) {
|
||||
$this->build_basket_item( $post_id, $data, $item_type );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function usort_reorder( $a, $b ) {
|
||||
$sortable_columns_keys = array_keys( $this->get_sortable_columns() );
|
||||
$first_column_key = $sortable_columns_keys[0];
|
||||
// If no sort, default to first column
|
||||
$orderby = ( ! empty( $_GET['orderby'] ) ) ? $_GET['orderby'] : $first_column_key;
|
||||
// If no order, default to asc
|
||||
$order = ( ! empty( $_GET['order'] ) ) ? $_GET['order'] : 'asc';
|
||||
// Determine sort order
|
||||
$result = strcmp( $a[ $orderby ], $b[ $orderby ] );
|
||||
|
||||
// Send final sort direction to usort
|
||||
return ( $order === 'asc' ) ? $result : - $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $post_status
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_post_status_label( $post_status ) {
|
||||
static $post_status_object;
|
||||
// Get and store the post status "as verb", if available
|
||||
if ( ! isset( $post_status_object[ $post_status ] ) ) {
|
||||
$post_status_object[ $post_status ] = get_post_status_object( $post_status );
|
||||
}
|
||||
$post_status_label = ucfirst( $post_status );
|
||||
if ( isset( $post_status_object[ $post_status ] ) ) {
|
||||
$post_status_object_item = $post_status_object[ $post_status ];
|
||||
if ( isset( $post_status_object_item->label ) && $post_status_object_item->label ) {
|
||||
$post_status_label = $post_status_object_item->label;
|
||||
}
|
||||
}
|
||||
|
||||
return $post_status_label;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $post_type
|
||||
* @param array $item
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_post_type_label( $post_type, array $item ) {
|
||||
static $post_type_object;
|
||||
|
||||
if ( ! isset( $post_type_object[ $post_type ] ) ) {
|
||||
$post_type_object[ $post_type ] = get_post_type_object( $post_type );
|
||||
}
|
||||
$post_type_label = ucfirst( $post_type );
|
||||
|
||||
if ( isset( $post_type_object[ $post_type ] ) ) {
|
||||
$post_type_object_item = $post_type_object[ $post_type ];
|
||||
if ( isset( $post_type_object_item->labels->singular_name ) && $post_type_object_item->labels->singular_name ) {
|
||||
$post_type_label = $post_type_object_item->labels->singular_name;
|
||||
}
|
||||
}
|
||||
|
||||
if ( isset( $item['auto_added'] ) && $item['auto_added'] ) {
|
||||
if ( 'wp_block' === $post_type ) {
|
||||
$post_type_label = __( 'Reusable Block', 'wpml-translation-management' );
|
||||
}
|
||||
|
||||
$tooltip = '<a class="js-otgs-popover-tooltip otgs-ico-help"
|
||||
data-tippy-zindex="999999" tabindex="0"
|
||||
title="' . esc_attr__( "WPML added this item because it's linked to another in the basket. If you wish, you can manually remove it.", 'wpml-translation-management' ) . '"
|
||||
</a>';
|
||||
|
||||
$post_type_label .= '<br><small>'
|
||||
. sprintf( esc_html__( 'automatically added %s', 'wpml-translation-management' ), $tooltip ) .
|
||||
'</small>';
|
||||
}
|
||||
|
||||
return $post_type_label;
|
||||
}
|
||||
|
||||
private function action_callback() {
|
||||
if ( isset( $_GET['clear_basket'] ) && isset( $_GET['clear_basket_nonce'] ) && $_GET['clear_basket'] == 1 ) {
|
||||
if ( wp_verify_nonce( $_GET['clear_basket_nonce'], 'clear_basket' ) ) {
|
||||
TranslationProxy_Basket::delete_all_items_from_basket();
|
||||
}
|
||||
}
|
||||
if ( $this->current_action() == 'delete_selected' ) {
|
||||
// Delete basket items from post action
|
||||
TranslationProxy_Basket::delete_items_from_basket( $_POST['icl_translation_basket_delete'] );
|
||||
} elseif ( $this->current_action() == 'delete' && isset( $_GET['id'] ) && isset( $_GET['item_type'] ) ) {
|
||||
// Delete basket item from post action
|
||||
$delete_basket_item_id = filter_input( INPUT_GET, 'id', FILTER_SANITIZE_NUMBER_INT );
|
||||
$delete_basket_item_type = Sanitize::stringProp( 'item_type', $_GET );
|
||||
if ( $delete_basket_item_id && $delete_basket_item_type ) {
|
||||
TranslationProxy_Basket::delete_item_from_basket(
|
||||
$delete_basket_item_id,
|
||||
$delete_basket_item_type,
|
||||
true
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function get_data() {
|
||||
global $iclTranslationManagement;
|
||||
|
||||
$translation_jobs_basket = TranslationProxy_Basket::get_basket();
|
||||
|
||||
$basket_items_types = TranslationProxy_Basket::get_basket_items_types();
|
||||
foreach ( $basket_items_types as $item_type_name => $item_type ) {
|
||||
$translation_jobs_cart[ $item_type_name ] = false;
|
||||
if ( $item_type == 'core' ) {
|
||||
if ( ! empty( $translation_jobs_basket[ $item_type_name ] ) ) {
|
||||
$basket_type_items = $translation_jobs_basket[ $item_type_name ];
|
||||
if ( $item_type_name == 'string' ) {
|
||||
$translation_jobs_cart[ $item_type_name ] = $iclTranslationManagement->get_translation_jobs_basket_strings( $basket_type_items );
|
||||
} else {
|
||||
$translation_jobs_cart[ $item_type_name ] = $iclTranslationManagement->get_translation_jobs_basket_posts( $basket_type_items );
|
||||
}
|
||||
$this->build_basket_items( $translation_jobs_cart[ $item_type_name ], $item_type_name );
|
||||
}
|
||||
} elseif ( $item_type == 'custom' ) {
|
||||
$translation_jobs_cart_externals = apply_filters(
|
||||
'wpml_tm_translation_jobs_basket',
|
||||
array(),
|
||||
$translation_jobs_basket,
|
||||
$item_type_name
|
||||
);
|
||||
$this->build_basket_items( $translation_jobs_cart_externals, $item_type_name );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function display_tablenav( $which ) {
|
||||
return;
|
||||
}
|
||||
|
||||
function display() {
|
||||
parent::display();
|
||||
if ( TranslationProxy_Basket::get_basket_items_count() ) {
|
||||
$clear_basket_nonce = wp_create_nonce( 'clear_basket' );
|
||||
?>
|
||||
<a href="admin.php?page=<?php echo WPML_TM_FOLDER; ?>/menu/main.php&sm=basket&clear_basket=1&clear_basket_nonce=<?php echo $clear_basket_nonce; ?>"
|
||||
class="button-secondary wpml-tm-clear-basket-button" name="clear-basket">
|
||||
<i class="otgs-ico-cancel"></i>
|
||||
<?php _e( 'Clear Basket', 'wpml-translation-management' ); ?>
|
||||
</a>
|
||||
<?php
|
||||
}
|
||||
|
||||
$this->display_total_word_count_info();
|
||||
}
|
||||
|
||||
private function display_total_word_count_info() {
|
||||
|
||||
$grand_total_words_count = 0;
|
||||
|
||||
if ( $this->items ) {
|
||||
foreach ( $this->items as $item ) {
|
||||
$grand_total_words_count += $item['words'];
|
||||
}
|
||||
}
|
||||
|
||||
$service = TranslationProxy::get_current_service();
|
||||
$tm_ate = new WPML_TM_ATE();
|
||||
$is_ate_enabled = $tm_ate->is_translation_method_ate_enabled();
|
||||
$display_message = '';
|
||||
|
||||
$ate_doc_link = '';
|
||||
$ate_name = '';
|
||||
|
||||
if ( $is_ate_enabled ) {
|
||||
$ate_name = __( 'Advanced Translation Editor', 'wpml-translation-management' );
|
||||
$ate_doc_link = 'https://wpml.org/documentation/translating-your-contents/advanced-translation-editor/';
|
||||
}
|
||||
|
||||
if ( $service && $is_ate_enabled ) {
|
||||
$service_message = __( '%1$s and the %2$s use a translation memory, which can reduce the number of words you need to translate.', 'wpml-translation-management' );
|
||||
$display_message = sprintf(
|
||||
$service_message,
|
||||
'<a class="wpml-external-link" href="' . $service->doc_url . '" target="blank">' . $service->name . '</a>',
|
||||
'<a class="wpml-external-link" href="' . $ate_doc_link . '" target="blank">' . $ate_name . '</a>'
|
||||
);
|
||||
} elseif ( $service ) {
|
||||
$service_message = __( '%s uses a translation memory, which can reduce the number of words you need to translate.', 'wpml-translation-management' );
|
||||
$display_message = sprintf( $service_message, '<a class="wpml-external-link" href="' . $service->doc_url . '" target="blank">' . $service->name . '</a>' );
|
||||
} elseif ( $is_ate_enabled ) {
|
||||
$service_message = __( 'The %s uses a translation memory, which can reduce the number of words you need to translate.', 'wpml-translation-management' );
|
||||
$display_message = sprintf( $service_message, '<a class="wpml-external-link" href="' . $ate_doc_link . '" target="blank">' . $ate_name . '</a>' );
|
||||
}
|
||||
|
||||
if ( $service ) {
|
||||
$words_count_url = 'https://wpml.org/documentation/translating-your-contents/getting-a-word-count-of-your-wordpress-site/?utm_source=plugin&utm_medium=gui&utm_campaign=wpmltm#differences-in-word-count-between-wpml-and-translation-service-providers';
|
||||
$words_count_text = '<a class="wpml-external-link" href="' . $words_count_url . '" target="_blank">';
|
||||
|
||||
// translators: "%s" is replaced by the name of a translation service.
|
||||
$words_count_text .= sprintf( __( '%s may produce a different word count', 'wpml-translation-management' ), $service->name );
|
||||
$words_count_text .= '</a>';
|
||||
|
||||
// translators: "%s" is replaced by the the previous string.
|
||||
$words_count_message = sprintf( __( 'The number of words WPML will send to translation (%s):', 'wpml-translation-management' ), $words_count_text );
|
||||
} else {
|
||||
$words_count_message = __( 'The number of words WPML will send to translation:', 'wpml-translation-management' );
|
||||
}
|
||||
|
||||
?>
|
||||
<div class="words-count-summary">
|
||||
<p class="words-count-summary-info">
|
||||
<strong><?php echo $words_count_message; ?></strong>
|
||||
<span class="words-count-total"><?php echo $grand_total_words_count; ?></span>
|
||||
</p>
|
||||
<?php if ( $display_message ) { ?>
|
||||
<p class="words-count-summary-ts">
|
||||
<?php echo $display_message; ?>
|
||||
</p>
|
||||
<?php } ?>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,272 @@
|
||||
<?php
|
||||
|
||||
class WPML_Basket_Tab_Ajax {
|
||||
|
||||
/** @var TranslationProxy_Project $project */
|
||||
private $project;
|
||||
|
||||
/** @var WPML_Translation_Proxy_Basket_Networking $networking */
|
||||
private $networking;
|
||||
|
||||
/** @var WPML_Translation_Basket $basket */
|
||||
private $basket;
|
||||
|
||||
/**
|
||||
* @param TranslationProxy_Project $project
|
||||
* @param WPML_Translation_Proxy_Basket_Networking $networking
|
||||
* @param WPML_Translation_Basket $basket
|
||||
*/
|
||||
function __construct( $project, $networking, $basket ) {
|
||||
$this->project = $project;
|
||||
$this->networking = $networking;
|
||||
$this->basket = $basket;
|
||||
}
|
||||
|
||||
function init() {
|
||||
$request = filter_input( INPUT_POST, 'action' );
|
||||
$nonce = filter_input( INPUT_POST, '_icl_nonce' );
|
||||
if ( $request && $nonce && wp_verify_nonce( $nonce, $request . '_nonce' ) ) {
|
||||
add_action( 'wp_ajax_send_basket_items', [ $this, 'begin_basket_commit' ] );
|
||||
add_action( 'wp_ajax_send_basket_item', [ $this, 'send_basket_chunk' ] );
|
||||
add_action( 'wp_ajax_send_basket_commit', [ $this, 'send_basket_commit' ] );
|
||||
add_action( 'wp_ajax_check_basket_name', [ $this, 'check_basket_name' ] );
|
||||
add_action( 'wp_ajax_rollback_basket', [ $this, 'rollback_basket' ] );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for the ajax call to commit a chunk of the items in a batch provided in the request.
|
||||
*
|
||||
* @uses \WPML_Translation_Proxy_Basket_Networking::commit_basket_chunk
|
||||
*/
|
||||
function send_basket_chunk() {
|
||||
$batch_factory = new WPML_TM_Translation_Batch_Factory( $this->basket );
|
||||
|
||||
try {
|
||||
$batch = $batch_factory->create( $_POST );
|
||||
list( $has_error, $data, $error ) = $this->networking->commit_basket_chunk( $batch );
|
||||
} catch ( InvalidArgumentException $e ) {
|
||||
$has_error = true;
|
||||
$data = $e->getMessage();
|
||||
}
|
||||
|
||||
if ( $has_error ) {
|
||||
wp_send_json_error( $data );
|
||||
} else {
|
||||
wp_send_json_success( $data );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajax handler for the first ajax request call in the basket commit workflow, responding with an message
|
||||
* containing information about the basket's contents.
|
||||
*
|
||||
* @uses \WPML_Basket_Tab_Ajax::create_remote_batch_message
|
||||
*/
|
||||
function begin_basket_commit() {
|
||||
$basket_name = filter_input( INPUT_POST, 'basket_name', FILTER_SANITIZE_FULL_SPECIAL_CHARS, FILTER_FLAG_NO_ENCODE_QUOTES );
|
||||
|
||||
wp_send_json_success( $this->create_remote_batch_message( $basket_name ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Last ajax call in the multiple ajax calls made during the commit of a batch.
|
||||
* Empties the basket in case the commit worked error free responds to the ajax call.
|
||||
*/
|
||||
function send_basket_commit() {
|
||||
$errors = array();
|
||||
try {
|
||||
$translators = isset( $_POST['translators'] ) ? $_POST['translators'] : array();
|
||||
$has_remote_translators = $this->networking->contains_remote_translators( $translators );
|
||||
$response = $this->project && $has_remote_translators ? $this->project->commit_batch_job() : true;
|
||||
$response = ! empty( $this->project->errors ) ? false : $response;
|
||||
if ( $response !== false ) {
|
||||
|
||||
if ( is_object( $response ) ) {
|
||||
$current_service = $this->project->current_service();
|
||||
if ( $current_service->redirect_to_ts ) {
|
||||
$message = sprintf(
|
||||
__(
|
||||
'You\'ve sent the content for translation to %s. Please continue to their site, to make sure that the translation starts.',
|
||||
'wpml-translation-management'
|
||||
),
|
||||
$current_service->name
|
||||
);
|
||||
|
||||
$link_text = sprintf(
|
||||
__( 'Continue to %s', 'wpml-translation-management' ),
|
||||
$current_service->name
|
||||
);
|
||||
} else {
|
||||
$message = sprintf(
|
||||
__(
|
||||
'You\'ve sent the content for translation to %1$s. Currently, we are processing it and delivering to %1$s.',
|
||||
'wpml-translation-management'
|
||||
),
|
||||
$current_service->name
|
||||
);
|
||||
|
||||
$link_text = __( 'Check the batch delivery status', 'wpml-translation-management' );
|
||||
}
|
||||
|
||||
$response->call_to_action = $message;
|
||||
|
||||
$batch_url = OTG_TRANSLATION_PROXY_URL . sprintf( '/projects/%d/external', $this->project->get_batch_job_id() );
|
||||
$response->ts_batch_link = array(
|
||||
'href' => esc_url( $batch_url ),
|
||||
'text' => $link_text,
|
||||
);
|
||||
} elseif ( $this->contains_local_translators_different_than_current_user( $translators ) ) {
|
||||
$response = new stdClass();
|
||||
$response->is_local = true;
|
||||
}
|
||||
}
|
||||
|
||||
$errors = $response === false && $this->project ? $this->project->errors : $errors;
|
||||
} catch ( Exception $e ) {
|
||||
$response = false;
|
||||
$errors[] = $e->getMessage();
|
||||
}
|
||||
|
||||
do_action( 'wpml_tm_basket_committed' );
|
||||
|
||||
if ( isset( $response->is_local ) ) {
|
||||
$batch_jobs = get_option( WPML_TM_Batch_Report::BATCH_REPORT_OPTION );
|
||||
if ( $batch_jobs ) {
|
||||
$response->emails_did_not_sent = true;
|
||||
}
|
||||
}
|
||||
|
||||
$this->send_json_response( $response, $errors );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $translators
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function contains_local_translators_different_than_current_user( $translators ) {
|
||||
$is_first_available_translator = function ( $translator ) {
|
||||
return $translator === '0';
|
||||
};
|
||||
|
||||
return ! \wpml_collect( $translators )
|
||||
->reject( get_current_user_id() )
|
||||
->reject( $is_first_available_translator )
|
||||
->filter(
|
||||
function ( $translator ) {
|
||||
return is_numeric( $translator );
|
||||
}
|
||||
)
|
||||
->isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Ajax handler for checking if a current basket/batch name is valid for use with the currently used translation
|
||||
* service.
|
||||
*
|
||||
* @uses \WPML_Translation_Basket::check_basket_name
|
||||
*/
|
||||
function check_basket_name() {
|
||||
$basket_name_max_length = TranslationProxy::get_current_service_batch_name_max_length();
|
||||
|
||||
wp_send_json_success( $this->basket->check_basket_name( $this->get_basket_name(), $basket_name_max_length ) );
|
||||
}
|
||||
|
||||
public function rollback_basket() {
|
||||
\WPML\TM\API\Batch::rollback( $this->get_basket_name() );
|
||||
wp_send_json_success();
|
||||
}
|
||||
|
||||
/** @return string */
|
||||
private function get_basket_name() {
|
||||
return filter_input( INPUT_POST, 'basket_name', FILTER_SANITIZE_FULL_SPECIAL_CHARS, FILTER_FLAG_NO_ENCODE_QUOTES );
|
||||
}
|
||||
|
||||
private static function sanitize_errors( $source ) {
|
||||
if ( is_array( $source ) ) {
|
||||
if ( $source && array_key_exists( 'errors', $source ) ) {
|
||||
foreach ( $source['errors'] as &$error ) {
|
||||
if ( is_array( $error ) ) {
|
||||
$error = self::sanitize_errors( $error );
|
||||
} else {
|
||||
$error = ICL_AdminNotifier::sanitize_and_format_message( $error );
|
||||
}
|
||||
}
|
||||
unset( $error );
|
||||
}
|
||||
} else {
|
||||
$source = ICL_AdminNotifier::sanitize_and_format_message( $source );
|
||||
}
|
||||
|
||||
return $source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends the response to the ajax for \WPML_Basket_Tab_Ajax::send_basket_commit and rolls back the commit
|
||||
* in case of any errors.
|
||||
*
|
||||
* @see \WPML_Basket_Tab_Ajax::send_basket_commit
|
||||
* @uses \WPML_Translation_Basket::delete_all_items
|
||||
*
|
||||
* @param object|bool $response
|
||||
* @param array $errors
|
||||
*/
|
||||
private function send_json_response( $response, $errors ) {
|
||||
$result = array(
|
||||
'result' => $response,
|
||||
'is_error' => ! ( $response && empty( $errors ) ),
|
||||
'errors' => $errors,
|
||||
);
|
||||
if ( ! empty( $errors ) ) {
|
||||
\WPML\TM\API\Batch::rollback( $this->get_basket_name() );
|
||||
wp_send_json_error( self::sanitize_errors( $result ) );
|
||||
} else {
|
||||
$this->basket->delete_all_items();
|
||||
|
||||
wp_send_json_success( $result );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the message that is shown before committing a batch.
|
||||
*
|
||||
* @see \WPML_Basket_Tab_Ajax::begin_basket_commit
|
||||
*
|
||||
* @param string $basket_name
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function create_remote_batch_message( $basket_name ) {
|
||||
if ( $basket_name ) {
|
||||
$this->basket->set_name( $basket_name );
|
||||
}
|
||||
$basket = $this->basket->get_basket();
|
||||
$basket_items_types = $this->basket->get_item_types();
|
||||
if ( ! $basket ) {
|
||||
$message_content = __( 'No items found in basket', 'wpml-translation-management' );
|
||||
} else {
|
||||
$total_count = 0;
|
||||
$message_content_details = '<ul>';
|
||||
foreach ( $basket_items_types as $item_type_name => $item_type ) {
|
||||
if ( isset( $basket[ $item_type_name ] ) ) {
|
||||
$count_item_type = count( $basket[ $item_type_name ] );
|
||||
$total_count += $count_item_type;
|
||||
|
||||
$message_content_details .= '<li>' . $item_type_name . 's: ' . $count_item_type . '</li>';
|
||||
}
|
||||
}
|
||||
$message_content_details .= '</ul>';
|
||||
|
||||
$message_content = sprintf( __( '%s items in basket:', 'wpml-translation-management' ), $total_count );
|
||||
$message_content .= $message_content_details;
|
||||
}
|
||||
$container = $message_content;
|
||||
|
||||
return array(
|
||||
'message' => $container,
|
||||
'basket' => $basket,
|
||||
'allowed_item_types' => array_keys( $basket_items_types ),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user