441 lines
14 KiB
PHP
441 lines
14 KiB
PHP
<?php
|
|
|
|
use WPML\FP\Fns;
|
|
use WPML\FP\Lst;
|
|
use WPML\FP\Maybe;
|
|
use WPML\FP\Obj;
|
|
use WPML\FP\Relation;
|
|
use function WPML\Container\make;
|
|
use function WPML\FP\pipe;
|
|
|
|
class WPML_Menu_Item_Sync extends WPML_Menu_Sync_Functionality {
|
|
|
|
/** @var array $labels_to_add */
|
|
private $labels_to_add = array();
|
|
/** @var array $urls_to_add */
|
|
private $urls_to_add = array();
|
|
|
|
/**
|
|
* @var string
|
|
*/
|
|
const MENU_ITEM_POST_TYPE = 'post_nav_menu_item';
|
|
|
|
/**
|
|
* @return int the number of removed broken page items
|
|
*/
|
|
function cleanup_broken_page_items() {
|
|
|
|
return $this->wpdb->query(
|
|
"
|
|
DELETE o FROM {$this->wpdb->term_relationships} o
|
|
JOIN {$this->wpdb->postmeta} pm
|
|
ON pm.post_id = o.object_id
|
|
JOIN {$this->wpdb->posts} p
|
|
ON p.ID = pm.post_id
|
|
JOIN {$this->wpdb->postmeta} pm_type
|
|
ON pm_type.post_id = pm.post_id
|
|
WHERE p.post_type = 'nav_menu_item'
|
|
AND pm.meta_key = '_menu_item_object_id'
|
|
AND pm_type.meta_key = '_menu_item_type'
|
|
AND pm_type.meta_value = 'post_type'
|
|
AND pm.meta_value = 0"
|
|
);
|
|
}
|
|
|
|
function sync_deleted_menus( $deleted_data ) {
|
|
foreach ( $deleted_data as $languages ) {
|
|
foreach ( $languages as $items ) {
|
|
foreach ( $items as $item_id => $name ) {
|
|
wp_delete_post( $item_id, true );
|
|
$delete_trid = $this->post_translations->get_element_trid( $item_id );
|
|
if ( $delete_trid ) {
|
|
$this->sitepress->delete_element_translation( $delete_trid, 'post_nav_menu_item' );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function sync_menu_options( $options_data ) {
|
|
foreach ( $options_data as $menu_id => $translations ) {
|
|
foreach ( $translations as $language => $option ) {
|
|
$translated_menu_id = $this->term_translations->term_id_in( $menu_id, $language );
|
|
if ( isset( $option['auto_add'] ) ) {
|
|
$nav_menu_option = (array) get_option( 'nav_menu_options' );
|
|
$nav_menu_option['auto_add'] = isset( $nav_menu_option['auto_add'] ) ? $nav_menu_option['auto_add'] : array();
|
|
if ( $option['auto_add'] && ! in_array( $translated_menu_id, $nav_menu_option['auto_add'] ) ) {
|
|
$nav_menu_option['auto_add'][] = $translated_menu_id;
|
|
} elseif ( ! $option['auto_add'] && false !== ( $key = array_search(
|
|
$translated_menu_id,
|
|
$nav_menu_option['auto_add']
|
|
) )
|
|
) {
|
|
unset( $nav_menu_option['auto_add'][ $key ] );
|
|
}
|
|
$nav_menu_option['auto_add'] = array_intersect(
|
|
$nav_menu_option['auto_add'],
|
|
wp_get_nav_menus( array( 'fields' => 'ids' ) )
|
|
);
|
|
update_option( 'nav_menu_options', array_filter( $nav_menu_option ) );
|
|
wp_defer_term_counting( false );
|
|
do_action( 'wp_update_nav_menu', $translated_menu_id );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public function sync_menu_order( array $menus ) {
|
|
global $wpdb;
|
|
|
|
foreach ( $menus as $menu_id => $menu ) {
|
|
$menu_index_by_lang = array();
|
|
foreach ( $menu['items'] as $item_id => $item ) {
|
|
$valid_translations = array_filter(
|
|
$item['translations'],
|
|
function ( $item ) {
|
|
return $item && $item['ID'];
|
|
}
|
|
);
|
|
|
|
foreach ( $valid_translations as $language => $item_translation ) {
|
|
$new_menu_order = empty( $menu_index_by_lang[ $language ] ) ? 1 : $menu_index_by_lang[ $language ] + 1;
|
|
$menu_index_by_lang[ $language ] = $new_menu_order;
|
|
if ( $new_menu_order != $menus[ $menu_id ]['items'][ $item_id ]['translations'][ $language ]['menu_order'] ) {
|
|
$menus[ $menu_id ]['items'][ $item_id ]['translations'][ $language ]['menu_order'] = $new_menu_order;
|
|
$wpdb->update(
|
|
$wpdb->posts,
|
|
[ 'menu_order' => $new_menu_order ],
|
|
[ 'ID' => $item_translation['ID'] ]
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return $menus;
|
|
}
|
|
|
|
function sync_added_items( array $added_data, array $menus ) {
|
|
global $wpdb;
|
|
|
|
foreach ( $added_data as $menu_id => $items ) {
|
|
foreach ( $items as $language => $translations ) {
|
|
foreach ( $translations as $item_id => $name ) {
|
|
$trid = $this->get_or_set_trid( $item_id, $this->sitepress->get_default_language() );
|
|
$translated_object = $menus[ $menu_id ]['items'][ $item_id ]['translations'][ $language ];
|
|
$menu_name = $this->get_menu_name( $menu_id );
|
|
$object_type = $translated_object['object_type'];
|
|
$object_title = $translated_object['title'];
|
|
$object_url = $translated_object['url'];
|
|
$icl_st_label_exists = false;
|
|
$icl_st_url_exists = false;
|
|
if ( $object_type === 'custom' && function_exists( 'icl_t' ) ) {
|
|
$item = new stdClass();
|
|
$item->url = $object_url;
|
|
$item->ID = $item_id;
|
|
$item->post_title = $object_title;
|
|
list( $object_title, $object_url ) = $this->icl_t_menu_item(
|
|
$menu_name,
|
|
$item,
|
|
$language,
|
|
$icl_st_label_exists,
|
|
$icl_st_url_exists
|
|
);
|
|
}
|
|
|
|
$menu_data = array(
|
|
'menu-item-db-id' => 0,
|
|
'menu-item-object-id' => $translated_object['object_id'],
|
|
'menu-item-object' => $translated_object['object'],
|
|
'menu-item-parent-id' => 0,
|
|
'menu-item-position' => 0,
|
|
'menu-item-type' => $object_type,
|
|
'menu-item-title' => $object_title,
|
|
'menu-item-url' => $object_url,
|
|
'menu-item-description' => '',
|
|
'menu-item-attr-title' => $translated_object['attr-title'],
|
|
'menu-item-target' => $translated_object['target'],
|
|
'menu-item-classes' => ( $translated_object['classes'] ? implode(
|
|
' ',
|
|
$translated_object['classes']
|
|
) : '' ),
|
|
'menu-item-xfn' => $translated_object['xfn'],
|
|
'menu-item-status' => 'publish',
|
|
);
|
|
|
|
$translated_menu_id = $menus[ $menu_id ]['translations'][ $language ]['id'];
|
|
|
|
remove_filter( 'get_term', array( $this->sitepress, 'get_term_adjust_id' ), 1 );
|
|
$translated_item_id = wp_update_nav_menu_item( $translated_menu_id, 0, $menu_data );
|
|
|
|
// set language explicitly since the 'wp_update_nav_menu_item' is still TBD
|
|
$this->sitepress->set_element_language_details(
|
|
$translated_item_id,
|
|
'post_nav_menu_item',
|
|
$trid,
|
|
$language
|
|
);
|
|
|
|
$menu_tax_id_prepared = $wpdb->prepare(
|
|
"SELECT term_taxonomy_id FROM {$wpdb->term_taxonomy} WHERE term_id=%d AND taxonomy='nav_menu' LIMIT 1",
|
|
$translated_menu_id
|
|
);
|
|
$menu_tax_id = $wpdb->get_var( $menu_tax_id_prepared );
|
|
|
|
if ( $translated_item_id && $menu_tax_id ) {
|
|
$rel_prepared = $wpdb->prepare(
|
|
"SELECT object_id FROM {$wpdb->term_relationships} WHERE object_id=%d AND term_taxonomy_id=%d LIMIT 1",
|
|
$translated_item_id,
|
|
$menu_tax_id
|
|
);
|
|
$rel = $wpdb->get_var( $rel_prepared );
|
|
if ( ! $rel ) {
|
|
$wpdb->insert(
|
|
$wpdb->term_relationships,
|
|
array(
|
|
'object_id' => $translated_item_id,
|
|
'term_taxonomy_id' => $menu_tax_id,
|
|
)
|
|
);
|
|
}
|
|
}
|
|
|
|
$menus[ $menu_id ]['items'][ $item_id ]['translations'][ $language ]['ID'] = $translated_item_id;
|
|
}
|
|
}
|
|
}
|
|
$this->fix_hierarchy_added_items( $added_data );
|
|
|
|
return $menus;
|
|
}
|
|
|
|
function sync_moved_items( array $moved_data, array $menus ) {
|
|
global $wpdb;
|
|
|
|
foreach ( $moved_data as $menu_id => $items ) {
|
|
foreach ( $items as $language => $changes ) {
|
|
foreach ( $changes as $item_id => $details ) {
|
|
$trid = $this->get_or_set_trid( $item_id, $this->sitepress->get_default_language() );
|
|
$translated_item_id = $menus[ $menu_id ]['items'][ $item_id ]['translations'][ $language ]['ID'];
|
|
|
|
$new_menu_order = key( $details );
|
|
$menus[ $menu_id ]['items'][ $item_id ]['translations'][ $language ]['menu_order'] = $new_menu_order;
|
|
|
|
$wpdb->update(
|
|
$wpdb->posts,
|
|
array( 'menu_order' => $new_menu_order ),
|
|
array( 'ID' => $translated_item_id )
|
|
);
|
|
|
|
if ( $this->post_translations->get_element_trid( $translated_item_id ) != $trid ) {
|
|
$this->sitepress->set_element_language_details(
|
|
$translated_item_id,
|
|
'post_nav_menu_item',
|
|
$trid,
|
|
$language
|
|
);
|
|
}
|
|
|
|
$translated_menu_id = $menus[ $menu_id ]['translations'][ $language ]['id'];
|
|
$this->assign_orphan_item_to_menu( $translated_item_id, $translated_menu_id );
|
|
}
|
|
}
|
|
}
|
|
$this->fix_hierarchy_moved_items( $moved_data );
|
|
|
|
return $menus;
|
|
}
|
|
|
|
/**
|
|
* @param int $item_id
|
|
* @param int $menu_id
|
|
*/
|
|
private function assign_orphan_item_to_menu( $item_id, $menu_id ) {
|
|
if ( ! wp_get_object_terms( $item_id, 'nav_menu' ) ) {
|
|
wp_set_object_terms( $item_id, array( $menu_id ), 'nav_menu' );
|
|
}
|
|
}
|
|
|
|
function sync_caption( $label_change_data ) {
|
|
foreach ( $label_change_data as $languages ) {
|
|
foreach ( $languages as $language => $items ) {
|
|
foreach ( $items as $item_id => $name ) {
|
|
$trid = $this->sitepress->get_element_trid( $item_id, 'post_nav_menu_item' );
|
|
if ( $trid ) {
|
|
$item_translations = $this->sitepress->get_element_translations(
|
|
$trid,
|
|
'post_nav_menu_item',
|
|
true
|
|
);
|
|
if ( isset( $item_translations[ $language ] ) ) {
|
|
$translated_item = get_post( $item_translations[ $language ]->element_id );
|
|
if ( $translated_item->post_title != $name ) {
|
|
$translated_item->post_title = $name;
|
|
wp_update_post( $translated_item );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function sync_urls( $url_change_data ) {
|
|
foreach ( $url_change_data as $languages ) {
|
|
foreach ( $languages as $language => $items ) {
|
|
foreach ( $items as $item_id => $url ) {
|
|
$trid = $this->sitepress->get_element_trid( $item_id, 'post_nav_menu_item' );
|
|
if ( $trid ) {
|
|
$item_translations = $this->sitepress->get_element_translations(
|
|
$trid,
|
|
'post_nav_menu_item',
|
|
true
|
|
);
|
|
if ( isset( $item_translations[ $language ] ) ) {
|
|
$translated_item_id = $item_translations[ $language ]->element_id;
|
|
if ( $url ) {
|
|
update_post_meta( $translated_item_id, '_menu_item_url', $url );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function sync_missing_captions( $label_missing ) {
|
|
foreach ( $label_missing as $menu_id => $languages ) {
|
|
foreach ( $languages as $items ) {
|
|
foreach ( $items as $item_id => $name ) {
|
|
if ( ! in_array( $menu_id . '-' . $item_id, $this->labels_to_add ) ) {
|
|
$item = get_post( $item_id );
|
|
icl_register_string(
|
|
$this->get_menu_name( $menu_id ) . WPML_Menu_Sync_Functionality::STRING_CONTEXT_SUFFIX,
|
|
WPML_Menu_Sync_Functionality::STRING_NAME_LABEL_PREFIX . $item_id,
|
|
$item->post_title
|
|
);
|
|
$this->labels_to_add[] = $menu_id . '-' . $item_id;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function sync_urls_to_add( $url_missing_data ) {
|
|
foreach ( $url_missing_data as $menu_id => $languages ) {
|
|
foreach ( $languages as $items ) {
|
|
foreach ( $items as $item_id => $url ) {
|
|
if ( ! in_array( $menu_id . '-' . $item_id, $this->urls_to_add ) ) {
|
|
icl_register_string(
|
|
$this->get_menu_name( $menu_id ) . WPML_Menu_Sync_Functionality::STRING_CONTEXT_SUFFIX,
|
|
WPML_Menu_Sync_Functionality::STRING_NAME_URL_PREFIX . $item_id,
|
|
$url
|
|
);
|
|
$this->urls_to_add[] = $menu_id . '-' . $item_id;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param array $menus Registered menus.
|
|
*/
|
|
public function sync_custom_fields( $menus ) {
|
|
|
|
$syncMenuItem = function ( $menuItemId ) {
|
|
$this->sync_custom_fields_set_to_copy( $menuItemId );
|
|
$this->sync_custom_fields_set_to_copy_once( $menuItemId );
|
|
};
|
|
|
|
$syncMenu = pipe( Obj::prop( 'items' ), Obj::keys(), Fns::each( $syncMenuItem ) );
|
|
|
|
Fns::each( $syncMenu, $menus );
|
|
}
|
|
|
|
/**
|
|
* @param int $menuItemId
|
|
*/
|
|
private function sync_custom_fields_set_to_copy( $menuItemId ) {
|
|
$copy = new WPML_Sync_Custom_Fields(
|
|
new WPML_Translation_Element_Factory( $this->sitepress ),
|
|
$this->sitepress->get_custom_fields_translation_settings( WPML_COPY_CUSTOM_FIELD )
|
|
);
|
|
$copy->sync_all_custom_fields( $menuItemId );
|
|
}
|
|
|
|
/**
|
|
* @param int $menuItemId
|
|
*/
|
|
private function sync_custom_fields_set_to_copy_once( $menuItemId ) {
|
|
$getItemTranslations = function( $menuItemId ) {
|
|
return $this->sitepress->get_element_translations(
|
|
$this->sitepress->get_element_trid( $menuItemId, self::MENU_ITEM_POST_TYPE ),
|
|
self::MENU_ITEM_POST_TYPE
|
|
);
|
|
};
|
|
|
|
Maybe::of( $menuItemId )
|
|
->map( $getItemTranslations )
|
|
->map( Lst::pluck( 'element_id' ) )
|
|
->map( Fns::reject( Relation::equals( $menuItemId ) ) )
|
|
->map( Fns::map( [ make( WPML_Copy_Once_Custom_Field::class ), 'copy' ] ) );
|
|
}
|
|
|
|
private function fix_hierarchy_added_items( $added_data ) {
|
|
foreach ( $added_data as $menu_id => $items ) {
|
|
foreach ( $items as $language => $translations ) {
|
|
foreach ( $translations as $item_id => $name ) {
|
|
$this->fix_hierarchy_for_item( $item_id, $language );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private function fix_hierarchy_moved_items( $moved_data ) {
|
|
foreach ( $moved_data as $menu_id => $items ) {
|
|
foreach ( $items as $language => $changes ) {
|
|
foreach ( $changes as $item_id => $details ) {
|
|
$this->fix_hierarchy_for_item( $item_id, $language );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private function fix_hierarchy_for_item( $item_id, $language ) {
|
|
$parent_item = get_post_meta( $item_id, '_menu_item_menu_item_parent', true );
|
|
$translated_item_id = $this->post_translations->element_id_in(
|
|
$item_id,
|
|
$language
|
|
);
|
|
$translated_parent_menu_item_id = $this->post_translations->element_id_in(
|
|
$parent_item,
|
|
$language
|
|
);
|
|
$translated_parent_menu_item_id = $translated_parent_menu_item_id == $translated_item_id
|
|
? false : $translated_parent_menu_item_id;
|
|
|
|
update_post_meta(
|
|
$translated_item_id,
|
|
'_menu_item_menu_item_parent',
|
|
$translated_parent_menu_item_id
|
|
);
|
|
|
|
}
|
|
|
|
private function get_or_set_trid( $item_id, $language_code ) {
|
|
$trid = $this->post_translations->get_element_trid( $item_id );
|
|
if ( ! $trid ) {
|
|
$this->sitepress->set_element_language_details(
|
|
$item_id,
|
|
'post_nav_menu_item',
|
|
false,
|
|
$language_code
|
|
);
|
|
$trid = $this->post_translations->get_element_trid( $item_id );
|
|
}
|
|
|
|
return $trid;
|
|
}
|
|
}
|