Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 34
0.00% covered (danger)
0.00%
0 / 2
CRAP
0.00% covered (danger)
0.00%
0 / 1
WPCom_Themes_Merger
0.00% covered (danger)
0.00%
0 / 34
0.00% covered (danger)
0.00%
0 / 2
72
0.00% covered (danger)
0.00%
0 / 1
 merge_by_wpcom_first
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
20
 merge_by_release_date
0.00% covered (danger)
0.00%
0 / 19
0.00% covered (danger)
0.00%
0 / 1
20
1<?php
2/**
3 * Class WPCom_Themes_Merger.
4 * Responsible for the different merging strategies between WPCom and WPOrg themes.
5 *
6 * @package wpcom-themes
7 */
8
9/**
10 * Merges theme objects between WPCom and WPOrg repositories.
11 */
12class WPCom_Themes_Merger {
13    /**
14     * Merges themes prioritizing WPCom themes.
15     *
16     * @param stdClass $wporg_themes_object The WP.org themes API result.
17     * @param array    $wpcom_themes        The WP.com themes to include.
18     *
19     * @return stdClass The themes API result including wpcom themes.
20     */
21    public function merge_by_wpcom_first( stdClass $wporg_themes_object, array $wpcom_themes ): stdClass {
22        $wporg_themes_excluding_wpcom = array();
23
24        // Create an associative array with theme slugs as keys for quick lookup
25        $wpcom_theme_slugs = array_flip(
26            array_map(
27                fn ( $theme ) => $theme->slug,
28                $wpcom_themes
29            )
30        );
31
32        // Filter themes from $wporg_themes_object that are not in $wpcom_themes
33        foreach ( $wporg_themes_object->themes as $wporg_theme ) {
34            if ( ! isset( $wpcom_theme_slugs[ $wporg_theme->slug ] ) ) {
35                $wporg_themes_excluding_wpcom[] = $wporg_theme;
36            }
37        }
38
39        // Remove the count of wporg themes.
40        $wporg_themes_object->info['results'] -= count( $wporg_themes_object->themes );
41
42        // Merge $wpcom_themes and $wporg_themes_excluding_wpcom if it's the first page
43        if ( $wporg_themes_object->info['page'] === 1 ) {
44            $wporg_themes_object->themes = array_merge( $wpcom_themes, $wporg_themes_excluding_wpcom );
45        }
46
47        // Add the count of themes without duplicates.
48        $wporg_themes_object->info['results'] += count( $wporg_themes_object->themes );
49
50        return $wporg_themes_object;
51    }
52
53    /**
54     * Merge themes by release date with no particular bias.
55     *
56     * @param stdClass $wporg_themes_object The WP.org themes API result.
57     * @param array    $wpcom_themes        The WP.com themes to include.
58     *
59     * @return stdClass The themes API result including wpcom themes.
60     */
61    public function merge_by_release_date( stdClass $wporg_themes_object, array $wpcom_themes ): stdClass {
62        $last_theme_date  = strtotime( end( $wporg_themes_object->themes )?->creation_time ?? '2000-01-01' );
63        $first_theme_date = strtotime( reset( $wporg_themes_object->themes )?->creation_time ?? gmdate( 'Y-m-d' ) );
64
65        $themes = array();
66        foreach ( $wporg_themes_object->themes as $wporg_theme ) {
67            $themes[ $wporg_theme->slug ] = $wporg_theme;
68        }
69
70        // We override WP.org themes with WP.com themes if they have the same slug. We might have fewer results
71        // than expected if there are themes with the same slug in both repositories and the release dates differ.
72        // As a general rule, users will see themes once they're available on the WPCom theme repo which is before they're
73        // available on the WPOrg theme repo.
74        foreach ( $wpcom_themes as $theme ) {
75            $themes[ $theme->slug ] = $theme;
76        }
77
78        $themes = array_filter(
79            $themes,
80            fn( $theme ) => strtotime( $theme->creation_time ) >= $last_theme_date && strtotime( $theme->creation_time ) <= $first_theme_date
81        );
82
83        usort(
84            $themes,
85            fn( $a, $b ) => strtotime( $b->creation_time ) - strtotime( $a->creation_time )
86        );
87
88        // Remove the wporg themes count.
89        $wporg_themes_object->info['results'] -= count( $wporg_themes_object->themes );
90        // Add the filtered unique themes count.
91        $wporg_themes_object->info['results'] += count( $themes );
92
93        $wporg_themes_object->themes = $themes;
94
95        return $wporg_themes_object;
96    }
97}