get_content_relations_table(); if ( '' === $table ) { return 0; } list( $src_blog, $src_elem ) = self::source_columns( $mlp2, $table ); if ( '' === $src_blog ) { return 0; } $type_safe = ( 'term' === $type ) ? 'term' : 'post'; // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared return (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(DISTINCT {$src_blog}, {$src_elem}) FROM `{$table}` WHERE ml_type = %s", $type_safe ) ); // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared } /** * Return a batch of distinct source groups, with all their translation members. * * Each returned element is: * [ * 'type' => string, // 'post' or 'term' * 'members' => [ * ['site_id' => int, 'element_id' => int], * ... * ] * ] * * The source element itself is always included as a member. * * @param string $type 'post' or 'term'. * @param int $offset Offset into the distinct source list. * @param int $limit Number of groups to return. * @return array[] */ public static function get_groups_batch( string $type, int $offset, int $limit ): array { global $wpdb; $mlp2 = new Robotstxt_Mlp2_Mlp5_Detector_Mlp2(); $table = $mlp2->get_content_relations_table(); if ( '' === $table ) { return array(); } list( $src_blog, $src_elem ) = self::source_columns( $mlp2, $table ); if ( '' === $src_blog ) { return array(); } $type_safe = ( 'term' === $type ) ? 'term' : 'post'; // Fetch a page of distinct sources. // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared $sources = $wpdb->get_results( $wpdb->prepare( "SELECT DISTINCT {$src_blog} AS source_blog, {$src_elem} AS source_elem FROM `{$table}` WHERE ml_type = %s ORDER BY {$src_blog}, {$src_elem} LIMIT %d OFFSET %d", $type_safe, $limit, $offset ), ARRAY_A ); // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared if ( empty( $sources ) ) { return array(); } $groups = array(); foreach ( $sources as $source ) { $src_blog_id = (int) $source['source_blog']; $src_elem_id = (int) $source['source_elem']; // Fetch all translations for this source. // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared $translations = $wpdb->get_results( $wpdb->prepare( "SELECT ml_blogid, ml_elementid FROM `{$table}` WHERE ml_type = %s AND {$src_blog} = %d AND {$src_elem} = %d", $type_safe, $src_blog_id, $src_elem_id ), ARRAY_A ); // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared // Build members: source + all translations (deduplicated). $seen = array(); $members = array(); $source_key = $src_blog_id . ':' . $src_elem_id; $seen[ $source_key ] = true; $members[] = array( 'site_id' => $src_blog_id, 'element_id' => $src_elem_id, ); foreach ( (array) $translations as $t ) { $key = ( (int) $t['ml_blogid'] ) . ':' . ( (int) $t['ml_elementid'] ); if ( isset( $seen[ $key ] ) ) { continue; } $seen[ $key ] = true; $members[] = array( 'site_id' => (int) $t['ml_blogid'], 'element_id' => (int) $t['ml_elementid'], ); } if ( count( $members ) >= 2 ) { $groups[] = array( 'type' => $type_safe, 'members' => $members, ); } } return $groups; } /** * Detect the source-blog and source-element column names. * * Returns ['', ''] when columns cannot be determined. * * @param Robotstxt_Mlp2_Mlp5_Detector_Mlp2 $mlp2 MLP2 detector. * @param string $table Content relations table name. * @return string[] [ $source_blog_col, $source_element_col ] */ private static function source_columns( Robotstxt_Mlp2_Mlp5_Detector_Mlp2 $mlp2, string $table ): array { $cols = $mlp2->describe_table( $table ); $blog_col = ''; foreach ( array( 'ml_source_blogid', 'ml_blogid' ) as $c ) { if ( isset( $cols[ $c ] ) ) { $blog_col = $c; break; } } $elem_col = ''; foreach ( array( 'ml_source_elementid', 'ml_elementid' ) as $c ) { if ( isset( $cols[ $c ] ) ) { $elem_col = $c; break; } } return array( $blog_col, $elem_col ); } }