first commit
This commit is contained in:
@@ -0,0 +1,440 @@
|
||||
<?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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user