Files
doitinpoland.com/wp-content/plugins/sitepress-multilingual-cms/inc/wp-nav-menus/menu-item-sync.class.php
2023-09-12 21:41:04 +02:00

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;
}
}