type && $item->object_id ) { if ( ! in_array( (string) $item->object, $post_types, true ) ) { continue; } $this->translate_post_item( $item, $current ); } } return $items; } /** * Swap a page/post item for its linked translation. */ private function translate_post_item( $item, $current ) { $object_id = (int) $item->object_id; // Already in the visitor's language (e.g. the item was added from the // right language, or a per-language menu was served). if ( duolangue_get_post_lang( $object_id ) === $current ) { return; } $translation = duolangue_get_post_translation( $object_id ); if ( ! $translation || 'publish' !== get_post_status( $translation ) || duolangue_get_post_lang( $translation ) !== $current ) { // No usable translation: keep the item as-is rather than hiding // it — a visible link to the other language beats a hole in the // navigation. return; } // Replace the label only when it was the object's own title; a custom // navigation label is the author's deliberate wording and is kept. if ( (string) $item->title === (string) get_the_title( $object_id ) ) { $item->title = get_the_title( $translation ); } if ( (string) $item->attr_title === (string) get_the_title( $object_id ) ) { $item->attr_title = get_the_title( $translation ); } $item->url = get_permalink( $translation ); $item->object_id = (string) $translation; } /** * Append a language link to the menus chosen in the settings. * * @param string $items HTML list items. * @param stdClass $args wp_nav_menu() arguments. * @return string */ public function append_language( $items, $args ) { if ( is_admin() ) { return $items; } $settings = duolangue_get_settings(); $locations = (array) $settings['menu_locations']; if ( empty( $locations ) ) { return $items; } // '_all' targets every menu (useful when the theme/builder registers // no locations — Oxygen, Bricks…); otherwise match the location. if ( ! in_array( '_all', $locations, true ) && ! $this->is_menu_in_locations( $args, $locations ) ) { return $items; } $display = $settings['menu_display']; $current = duolangue_current_lang(); if ( 'both' === $settings['menu_show'] ) { foreach ( duolangue_get_languages() as $lang ) { $items .= $this->menu_item( $lang, Duolangue_Router::url_for_lang( $lang['code'] ), $display, $lang['code'] === $current ? ' current-lang' : '' ); } return $items; } // Default: only the other language. return $items . $this->menu_item( duolangue_other_lang(), duolangue_other_lang_url(), $display, '' ); } /** * Is the menu being rendered one of the chosen locations? * * Matches either the location the theme asked for (theme_location), or * the menu itself when it is assigned to a chosen location: page builders * (Oxygen, Bricks…) usually render a menu by its ID, not by location. * * @param stdClass $args wp_nav_menu() arguments. * @param string[] $locations Locations chosen in the settings. * @return bool */ private function is_menu_in_locations( $args, $locations ) { $location = isset( $args->theme_location ) ? (string) $args->theme_location : ''; if ( '' !== $location && in_array( $location, $locations, true ) ) { return true; } $menu = isset( $args->menu ) ? wp_get_nav_menu_object( $args->menu ) : false; if ( ! $menu ) { return false; } $assigned = get_nav_menu_locations(); foreach ( $locations as $chosen ) { if ( isset( $assigned[ $chosen ] ) && (int) $assigned[ $chosen ] === (int) $menu->term_id ) { return true; } } return false; } private function menu_item( $lang, $url, $display, $extra_class ) { return sprintf( '