fields->language_specific_keys(), true ) ) { return ''; } return (bool) apply_filters( 'blocklingo_sync_meta_key', true, $meta_key ) ? 'custom_fields' : ''; } /** Added, updated or deleted meta: copy the key's values to the other translations. */ public function on_meta( mixed $meta_id, mixed $post_id, mixed $meta_key ): void { $post_id = (int) $post_id; $meta_key = (string) $meta_key; if ( $this->guard->is_paused() ) { return; } $option = $this->option_for_meta( $meta_key ); if ( ! $option || ! $this->settings->get()->syncs( $option ) ) { return; } $others = $this->others( $post_id ); if ( ! $others ) { return; } $values = get_post_meta( $post_id, $meta_key, false ); $this->guard->paused( static function () use ( $others, $meta_key, $values ): void { foreach ( $others as $other ) { delete_post_meta( $other, $meta_key ); foreach ( (array) $values as $value ) { add_post_meta( $other, $meta_key, wp_slash( $value ) ); } } } ); } /** Terms changed: same terms on the other translations. */ public function on_terms( mixed $post_id, mixed $terms, mixed $tt_ids, mixed $taxonomy ): void { $post_id = (int) $post_id; $taxonomy = (string) $taxonomy; if ( $this->guard->is_paused() || ! $this->settings->get()->syncs( 'taxonomies' ) ) { return; } if ( ! (bool) apply_filters( 'blocklingo_sync_taxonomy', true, $taxonomy ) ) { return; } $others = $this->others( $post_id ); if ( ! $others ) { return; } $ids = wp_get_object_terms( $post_id, $taxonomy, array( 'fields' => 'ids' ) ); if ( is_wp_error( $ids ) ) { return; } $ids = array_map( 'intval', (array) $ids ); $translated = $this->terms->is_translatable( $taxonomy ); $this->guard->paused( function () use ( $others, $ids, $taxonomy, $translated ): void { foreach ( $others as $lang => $other ) { // Translated taxonomies: each language gets its own version of the terms, when there is one. wp_set_object_terms( $other, $translated ? $this->terms->map( $ids, (string) $lang ) : $ids, $taxonomy ); } } ); } /** Post saved: order, comment status, date and parent follow. */ public function on_post_saved( mixed $post_id, mixed $post ): void { if ( ! $post instanceof WP_Post || $this->guard->is_paused() || 'auto-draft' === $post->post_status ) { return; } $others = $this->others( (int) $post_id ); $settings = $this->settings->get(); foreach ( $others as $lang => $other_id ) { $other = get_post( $other_id ); if ( ! $other ) { continue; } $data = array(); if ( $settings->syncs( 'menu_order' ) && (int) $other->menu_order !== (int) $post->menu_order ) { $data['menu_order'] = (int) $post->menu_order; } if ( $settings->syncs( 'comment_status' ) ) { if ( $other->comment_status !== $post->comment_status ) { $data['comment_status'] = $post->comment_status; } if ( $other->ping_status !== $post->ping_status ) { $data['ping_status'] = $post->ping_status; } } if ( $settings->syncs( 'post_date' ) && $other->post_date !== $post->post_date ) { $data['post_date'] = $post->post_date; $data['post_date_gmt'] = $post->post_date_gmt; } if ( $settings->syncs( 'page_parent' ) && is_post_type_hierarchical( $post->post_type ) ) { $parent = $post->post_parent ? $this->posts->in_language( (int) $post->post_parent, (string) $lang ) : 0; // Parent without a translation in this language: leave the other post where it is. if ( ( $parent || ! $post->post_parent ) && (int) $other->post_parent !== $parent ) { $data['post_parent'] = $parent; } } if ( $data ) { // Direct update: no hooks, no recursion, no new revision. $this->db->update( $this->db->posts, $data, array( 'ID' => $other_id ) ); clean_post_cache( $other_id ); } } } /** @return array Other members of the post's group: lang => ID. */ private function others( int $post_id ): array { $post = get_post( $post_id ); if ( ! $post || ! $this->settings->get()->is_translatable_type( $post->post_type ) || wp_is_post_revision( $post ) ) { return array(); } return array_filter( $this->posts->group( $post_id ), static fn( int $id ): bool => $id !== $post_id ); } }