terms. foreach ( $this->terms as $term ) { if ( 'post_translations' == $term['term_taxonomy'] ) { $this->post_translations[] = $term; } if ( 'term_translations' == $term['term_taxonomy'] ) { $term_translations[] = $term; } if ( 'language' === $term['term_taxonomy'] ) { $term_languages[] = $term; } } parent::process_terms(); // First reset the core terms cache as WordPress Importer calls wp_suspend_cache_invalidation( true ); wp_cache_set_terms_last_changed(); // Assign the default language in case the importer created the first language. if ( empty( PLL()->options['default_lang'] ) ) { $languages = get_terms( array( 'taxonomy' => 'language', 'hide_empty' => false, 'orderby' => 'term_id' ) ); $default_lang = reset( $languages ); PLL()->options['default_lang'] = $default_lang->slug; } /* * Merge strings translations for an already existing language. * * Term metas are handled by the importer when creating a term, * but not when updating an existing term. */ foreach ( $term_languages as $term ) { if ( empty( $this->processed_terms[ $term['term_id'] ] ) || empty( $term['termmeta'] ) ) { continue; } foreach ( $term['termmeta'] as $term_meta ) { if ( '_pll_strings_translations' !== $term_meta['key'] ) { continue; } $language = PLL()->model->languages->get( $term['term_id'] ); if ( empty( $language ) ) { continue; } $strings = maybe_unserialize( $term_meta['value'] ); $mo = new PLL_MO(); $mo->import_from_db( $language ); foreach ( $strings as $msg ) { $mo->add_entry_or_merge( $mo->make_entry( $msg[0], $msg[1] ) ); } $mo->export_to_db( $language ); } } // Clean languages cache in case some of them were created during import. PLL()->model->languages->clean_cache(); $this->remap_terms_relations( $term_translations ); $this->remap_translations( $term_translations, $this->processed_terms ); } /** * Overrides WP_Import::process_post to remap posts translations * Also merges strings translations from the WXR file to the existing ones * * @since 1.2 */ public function process_posts() { $menu_items = array(); // Store this for future usage as parent function unset $this->posts foreach ( $this->posts as $post ) { if ( 'nav_menu_item' == $post['post_type'] ) { $menu_items[] = $post; } } parent::process_posts(); PLL()->model->languages->clean_cache(); // To update the posts count in (cached) languages list. $this->remap_translations( $this->post_translations, $this->processed_posts ); unset( $this->post_translations ); // Language switcher menu items foreach ( $menu_items as $item ) { foreach ( $item['postmeta'] as $meta ) { if ( '_pll_menu_item' == $meta['key'] ) { update_post_meta( $this->processed_menu_items[ $item['post_id'] ], '_pll_menu_item', maybe_unserialize( $meta['value'] ) ); } } } } /** * Remaps terms languages. * * @since 1.2 * * @param array $terms array of terms in 'term_translations' taxonomy. */ protected function remap_terms_relations( &$terms ) { global $wpdb; $term_relationships = array(); foreach ( $terms as $term ) { $translations = maybe_unserialize( $term['term_description'] ); foreach ( $translations as $slug => $old_id ) { if ( $old_id && ! empty( $this->processed_terms[ $old_id ] ) && $lang = PLL()->model->get_language( $slug ) ) { // Language relationship. $term_relationships[] = array( $this->processed_terms[ $old_id ], $lang->get_tax_prop( 'term_language', 'term_taxonomy_id' ) ); // Translation relationship. $term_relationships[] = array( $this->processed_terms[ $old_id ], get_term( $this->processed_terms[ $term['term_id'] ], 'term_translations' )->term_taxonomy_id ); } } } // Insert term_relationships. if ( ! empty( $term_relationships ) ) { // Make sure we don't attempt to insert already existing term relationships. $existing_term_relationships = $wpdb->get_results( "SELECT tr.object_id, tr.term_taxonomy_id FROM {$wpdb->term_relationships} AS tr INNER JOIN {$wpdb->term_taxonomy} AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE tt.taxonomy IN ( 'term_language', 'term_translations' )" ); foreach ( $existing_term_relationships as $key => $tr ) { $existing_term_relationships[ $key ] = array( $tr->object_id, $tr->term_taxonomy_id ); } $term_relationships = array_udiff( $term_relationships, $existing_term_relationships, function ( $a, $b ) { return strcmp( implode( ',', $a ), implode( ',', $b ) ); // An easy way to compare arrays (ok if values are int or numeric strings). } ); if ( ! empty( $term_relationships ) ) { $wpdb->query( $wpdb->prepare( // phpcs:ignore WordPress.DB.PreparedSQLPlaceholders.ReplacementsWrongNumber sprintf( "INSERT INTO {$wpdb->term_relationships} ( object_id, term_taxonomy_id ) VALUES %s", implode( ',', array_fill( 0, count( $term_relationships ), '( %d, %d )' ) ) ), array_merge( ...$term_relationships ) ) ); } } } /** * Remaps translations for both posts and terms. * * @since 1.2 * * @param array $terms Array of terms in 'post_translations' or 'term_translations' taxonomies? * @param array $processed_objects Array of posts or terms processed by WordPress Importer. */ protected function remap_translations( &$terms, &$processed_objects ) { global $wpdb; $languages = pll_languages_list(); $to_update = array(); foreach ( $terms as $term ) { $translations = maybe_unserialize( $term['term_description'] ); $new_translations = array(); foreach ( $translations as $slug => $old_id ) { if ( in_array( $slug, $languages, true ) && $old_id && ! empty( $processed_objects[ $old_id ] ) ) { $new_translations[ $slug ] = $processed_objects[ $old_id ]; } else { $new_translations[ $slug ] = $old_id; // Preserve values for all keys which are not our language slugs. } } if ( ! empty( $new_translations ) ) { $to_update['case'][] = array( $this->processed_terms[ $term['term_id'] ], maybe_serialize( $new_translations ) ); $to_update['in'][] = (int) $this->processed_terms[ $term['term_id'] ]; } } if ( ! empty( $to_update ) ) { $wpdb->query( $wpdb->prepare( sprintf( "UPDATE {$wpdb->term_taxonomy} SET description = ( CASE term_id %s END ) WHERE term_id IN (%s)", implode( ' ', array_fill( 0, count( $to_update['case'] ), 'WHEN %d THEN %s' ) ), implode( ',', array_fill( 0, count( $to_update['in'] ), '%d' ) ) ), array_merge( array_merge( ...$to_update['case'] ), $to_update['in'] ) ) ); } } }