Making WordPress.org

Changeset 2864


Ignore:
Timestamp:
03/31/2016 08:25:15 PM (10 years ago)
Author:
ocean90
Message:

Translate: Display stats, contributors and language packs on theme project pages.

See #1388.

Location:
sites/trunk
Files:
5 edited
5 copied

Legend:

Unmodified
Added
Removed
  • sites/trunk/translate.wordpress.org/public_html/gp-templates-new/projects-wp-plugins.php

    r2765 r2864  
    5656                <thead>
    5757                        <tr>
    58                                 <?php foreach ( $table_headings as $heading ) : ?>
    59                                 <th class="title"><?php echo $heading; ?></th>
     58                                <?php foreach ( $table_headings as $key => $heading ) : ?>
     59                                <th class="col-<?php echo $key; ?>"><?php echo $heading; ?></th>
    6060                                <?php endforeach; ?>
    6161                        </tr>
  • sites/trunk/translate.wordpress.org/public_html/gp-templates-new/projects-wp-themes-contributors.php

    r2858 r2864  
    4949
    5050        <h3>Teams</h3>
    51         <p>For each locale a plugin can have translation editors and contributors. If a locale has no editor yet then you should probably <a href="https://make.wordpress.org/polyglots/handbook/rosetta/theme-plugin-directories/#translating-themes-plugins">make a request</a>.</p>
     51        <p>For each locale a theme can have translation editors and contributors. If a locale has no editor yet then you should probably <a href="https://make.wordpress.org/polyglots/handbook/rosetta/theme-plugin-directories/#translating-themes-plugins">make a request</a>.</p>
    5252        <?php
    5353        if ( $contributors_by_locale ) {
  • sites/trunk/translate.wordpress.org/public_html/gp-templates-new/projects-wp-themes-language-packs.php

    r2858 r2864  
    4343        <h3>Language Packs</h3>
    4444
    45         <p>Language packs are installed automatically if they are available. Once a locale has reached the threshold for a package build it will be listed here. It also means that you don&#8217;t have to include this language in your plugin anymore.</p>
     45        <p>Language packs are installed automatically if they are available. Once a locale has reached the threshold for a package build it will be listed here. It also means that you don&#8217;t have to include this language in your theme anymore.</p>
    4646
    4747        <?php
  • sites/trunk/translate.wordpress.org/public_html/gp-templates-new/projects-wp-themes.php

    r2858 r2864  
    33$table_headings = array(
    44        'locale'        => __( 'Locale' ),
    5         'dev'           => __( 'Development' ),
    6         'dev-readme'    => __( 'Development Readme' ),
    75        'stable'        => __( 'Stable' ),
    8         'stable-readme' => __( 'Stable Readme' ),
    96        'waiting'       => __( 'Waiting' ),
    107);
     
    4643</div>
    4744
    48 <?php if ( $has_error ) : ?>
    49 <div class="wporg-notice wporg-notice-warning">
    50         <p>This plugin is not <a href="https://developer.wordpress.org/plugins/internationalization/how-to-internationalize-your-plugin/">properly prepared for localization</a>. If you would like to translate this plugin, <a href="<?php echo esc_url( 'https://wordpress.org/support/plugin/' . $project->slug ); ?>">please contact the author</a>.</p>
    51 </div>
    52 <?php endif; ?>
    53 
    5445<div class="stats-table">
    5546        <table id="stats-table" class="table">
    5647                <thead>
    5748                        <tr>
    58                                 <?php foreach ( $table_headings as $heading ) : ?>
    59                                 <th class="title"><?php echo $heading; ?></th>
     49                                <?php foreach ( $table_headings as $key => $heading ) : ?>
     50                                <th class="col-<?php echo $key; ?>"><?php echo $heading; ?></th>
    6051                                <?php endforeach; ?>
    6152                        </tr>
     
    8879                                        <?php
    8980                                                if ( $translation_locale_statuses[ $locale_slug ] ) :
    90                                                         foreach ( array( 'dev', 'dev-readme', 'stable', 'stable-readme', 'waiting' ) as $subproject_slug ) :
     81                                                        foreach ( array( 'stable', 'waiting' ) as $subproject_slug ) :
    9182                                                                if ( isset( $translation_locale_statuses[ $locale_slug ][ $subproject_slug ] ) ) :
    9283                                                                        $percent = $translation_locale_statuses[ $locale_slug ][ $subproject_slug ];
     
    10596                                                                        else :
    10697                                                                                $percent_class = (int) ( $percent / 10 ) * 10;
    107                                                                                 $link_url  = gp_url_project( $project->path, gp_url_join( $subproject_slug, $gp_locale->slug, $set_slug ) );
     98                                                                                $link_url  = gp_url_project( $project->path, gp_url_join( $gp_locale->slug, $set_slug ) );
    10899                                                                                $link_text = "$percent%";
    109100
  • sites/trunk/translate.wordpress.org/public_html/gp-templates-new/stats-overview.php

    r2740 r2864  
    1414                <thead>
    1515                        <tr>
    16                                 <th class="title"><?php _e( 'Locale' ); ?></th>
     16                                <th class="col-locale-code"><?php _e( 'Locale' ); ?></th>
    1717                                <?php foreach ( $projects as $slug => $project ) : ?>
    1818                                        <th><?php
  • sites/trunk/translate.wordpress.org/public_html/gp-templates-new/style.css

    r2667 r2864  
    949949        text-align: center;
    950950        border-collapse: collapse;
     951        table-layout: fixed;
    951952}
    952953
     
    962963        text-align: center;
    963964        vertical-align: bottom;
    964         width: 79px;
    965965        padding: 10px 3px;
    966966        font-size: .8em;
     
    974974}
    975975
    976 .stats-table table th.title {
    977         width: 140px!important;
     976.stats-table table th {
     977        word-break: break-word;
     978}
     979
     980.stats-table table th.col-locale-code {
     981        width: 110px;
     982}
     983
     984.stats-table table th.col-locale {
     985        width: 180px;
    978986}
    979987
  • sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-routes/routes/wp-directory.php

    r2858 r2864  
    11<?php
    22
    3 class WPorg_GP_Route_WP_Plugins extends GP_Route {
    4 
    5         /**
    6          * Prints stats about sub-project of a specific project.
    7          *
    8          * @param string $project_slug Slug of a project.
    9          */
    10         public function get_plugin_projects( $project_slug ) {
     3class WPorg_GP_Route_WP_Directory extends GP_Route {
     4
     5        /**
     6         * Prints stats about contributors of a specific project.
     7         *
     8         * @param GP_Project $project The project.
     9         * @return array|false False if project not found, otherwise array with contributors.
     10         */
     11        public function get_contributors( $project ) {
    1112                global $wpdb;
    12 
    13                 $project_path = 'wp-plugins/' . $project_slug;
    14                 $project = GP::$project->by_path( $project_path );
    15                 if ( ! $project ) {
    16                         return $this->die_with_404();
    17                 }
    18 
    19                 $rows = $wpdb->get_results( "
    20                         SELECT
    21                                 path, locale, locale_slug,
    22                                 (100 * stats.current/stats.all) as percent_complete,
    23                                 stats.waiting+stats.fuzzy as waiting_strings,
    24                                 stats.untranslated as untranslated
    25                         FROM {$wpdb->project_translation_status} stats
    26                                 LEFT JOIN {$wpdb->gp_projects} p ON stats.project_id = p.id
    27                         WHERE
    28                                 p.parent_project_id = '{$project->id}'
    29                 " );
    30 
    31                 // Split out into $[Locale][Project] = %
    32                 $translation_locale_statuses = array();
    33                 $sub_projects = array();
    34                 foreach ( $rows as $set ) {
    35 
    36                         // Find unique locale key.
    37                         $locale_key = $set->locale;
    38                         if ( 'default' != $set->locale_slug ) {
    39                                 $locale_key = $set->locale . '/' . $set->locale_slug;
    40                         }
    41                         $sub_project = str_replace( "$project_path/", '', $set->path );
    42                         $sub_projects[ $sub_project ] = true;
    43 
    44                         /*
    45                          * > 50% round down, so that a project with all strings except 1 translated shows 99%, instead of 100%.
    46                          * < 50% round up, so that a project with just a few strings shows 1%, instead of 0%.
    47                          */
    48                         $percent_complete = (float) $set->percent_complete;
    49                         $translation_locale_statuses[ $locale_key ][ $sub_project ] = ( $percent_complete > 50 ) ? floor( $percent_complete ) : ceil( $percent_complete );
    50 
    51                         // Increment the amount of waiting and untranslated strings.
    52                         if ( ! isset( $translation_locale_statuses[ $locale_key ]['waiting'] ) ) {
    53                                 $translation_locale_statuses[ $locale_key ]['waiting'] = 0;
    54                         }
    55                         if ( ! isset( $translation_locale_statuses[ $locale_key ]['untranslated'] ) ) {
    56                                 $translation_locale_statuses[ $locale_key ]['untranslated'] = 0;
    57                         }
    58                         $translation_locale_statuses[ $locale_key ]['waiting'] += (int) $set->waiting_strings;
    59                         $translation_locale_statuses[ $locale_key ]['untranslated'] += (int) $set->untranslated;
    60 
    61 
    62                         ksort( $translation_locale_statuses[ $locale_key ], SORT_NATURAL );
    63                 }
    64 
    65                 // Check if the plugin has at least one code project. These won't be created if a plugin
    66                 // has no text domain defined.
    67                 $sub_projects = array_keys( $sub_projects );
    68                 $has_error = ( ! in_array( 'dev', $sub_projects ) && ! in_array( 'stable', $sub_projects ) );
    69 
    70                 unset( $project_path, $locale_key, $rows, $set, $sub_project, $sub_projects );
    71 
    72                 // Calculate a list of [Locale] = % subtotals
    73                 $translation_locale_complete = array();
    74                 foreach ( $translation_locale_statuses as $locale => $sets ) {
    75                         unset( $sets['waiting'], $sets['untranslated'] );
    76                         $translation_locale_complete[ $locale ] = round( array_sum( $sets ) / count( $sets ), 3 );
    77                 }
    78                 unset( $locale, $sets );
    79 
    80 
    81                 // Sort by translation completeness, least number of waiting strings, and locale slug.
    82                 uksort( $translation_locale_complete, function ( $a, $b ) use ( $translation_locale_complete, $translation_locale_statuses ) {
    83                         if ( $translation_locale_complete[ $a ] < $translation_locale_complete[ $b ] ) {
    84                                 return 1;
    85                         } elseif ( $translation_locale_complete[ $a ] == $translation_locale_complete[ $b ] ) {
    86                                 if ( $translation_locale_statuses[ $a ]['waiting'] != $translation_locale_statuses[ $b ]['waiting'] ) {
    87                                         return strnatcmp( $translation_locale_statuses[ $a ]['waiting'], $translation_locale_statuses[ $b ]['waiting'] );
    88                                 } else {
    89                                         return strnatcmp( $a, $b );
    90                                 }
    91                         } else {
    92                                 return -1;
    93                         }
    94                 } );
    95 
    96                 if ( function_exists( 'wporg_get_plugin_icon' ) ) {
    97                         $project->icon = wporg_get_plugin_icon( $project->slug, 64 );
    98                 } else {
    99                         $project->icon = '<div class="default-icon"><span class="dashicons dashicons-admin-plugins"></span></div>';
    100                 }
    101 
    102                 $this->tmpl( 'projects-wp-plugins', get_defined_vars() );
    103         }
    104 
    105         /**
    106          * Prints stats about contributors of a specific project.
    107          *
    108          * @param string $project_slug Slug of a project.
    109          */
    110         public function get_plugin_contributors( $project_slug ) {
    111                 global $wpdb;
    112 
    113                 $project_path = 'wp-plugins/' . $project_slug;
    114                 $project = GP::$project->by_path( $project_path );
    115                 if ( ! $project ) {
    116                         return $this->die_with_404();
    117                 }
    118 
    119                 if ( function_exists( 'wporg_get_plugin_icon' ) ) {
    120                         $project->icon = wporg_get_plugin_icon( $project->slug, 64 );
    121                 } else {
    122                         $project->icon = '<div class="default-icon"><span class="dashicons dashicons-admin-plugins"></span></div>';
    123                 }
    12413
    12514                $contributors_by_locale = array();
     
    15746                unset( $translation_editors );
    15847
     48                foreach( $this->get_translation_contributors_by_locale( $project->id ) as $row ) {
     49                        if ( ! isset( $contributors_by_locale[ $row->locale ] ) ) {
     50                                $contributors_by_locale[ $row->locale ] = $default_value;
     51                        }
     52
     53                        if ( isset( $contributors_by_locale[ $row->locale ]['editors'][ $row->user_id ] ) ) {
     54                                continue;
     55                        }
     56
     57                        if ( isset( $contributors_by_locale[ $row->locale ]['contributors'][ $row->user_id ] ) ) {
     58                                continue;
     59                        }
     60
     61                        $user = get_user_by( 'id', $row->user_id );
     62                        if ( ! $user ) {
     63                                continue;
     64                        }
     65
     66                        $contributors_by_locale[ $row->locale ]['contributors'][ $row->user_id ] = (object) array(
     67                                'nicename'     => $user->user_nicename,
     68                                'display_name' => $this->_encode( $user->display_name ),
     69                        );
     70
     71                        $contributors_by_locale[ $row->locale ]['count']++;
     72                }
     73
    15974                $sub_projects = $wpdb->get_col( $wpdb->prepare( "
    16075                        SELECT id
     
    191106                }
    192107
    193                 $chart_data = $this->get_plugin_contributors_chart_data( $project->id, $sub_projects );
    194 
    195                 $this->tmpl( 'projects-wp-plugins-contributors', get_defined_vars() );
     108                return $contributors_by_locale;
    196109        }
    197110
     
    199112         * Generates the chart data for contributors activity.
    200113         *
    201          * @param  int    $project_id   The ID of a project. Used to store data as meta.
    202          * @param  array $sub_projects Optional. IDs of sub-projects.
     114         * @param GP_Project $project_id The project.
    203115         * @return array The data to build a chart via Chartist.js.
    204116         */
    205         private function get_plugin_contributors_chart_data( $project_id, $sub_projects = null ) {
    206                 $chart_data = gp_get_meta( 'wp-plugins', $project_id, 'contributors-chart-data' );
    207                 if ( $chart_data ) {
    208                         if ( $chart_data['last_updated'] + DAY_IN_SECONDS > time() ) {
    209                                 return $chart_data;
    210                         }
    211                 }
    212 
     117        protected function get_contributors_chart_data( $project ) {
    213118                global $wpdb;
    214119
    215                 if ( ! $sub_projects ) {
    216                         $sub_projects = $wpdb->get_col( $wpdb->prepare( "
    217                                 SELECT id
    218                                 FROM {$wpdb->gp_projects}
    219                                 WHERE parent_project_id = %d
    220                         ", $$project_id ) );
    221                 }
    222 
     120                $sub_projects = $wpdb->get_col( $wpdb->prepare( "
     121                        SELECT id
     122                        FROM {$wpdb->gp_projects}
     123                        WHERE parent_project_id = %d
     124                ", $project->id ) );
     125
     126                $project_ids = array_merge( array( $project->id ), $sub_projects );
    223127                $translation_set_ids = $wpdb->get_col( "
    224                         SELECT `id` FROM {$wpdb->gp_translation_sets} WHERE `project_id` IN (" . implode( ',', $sub_projects ) . ")
     128                        SELECT `id` FROM {$wpdb->gp_translation_sets} WHERE `project_id` IN (" . implode( ',', $project_ids ) . ")
    225129                " );
    226130
     
    277181                }
    278182
    279                 $last_updated = time();
    280                 $chart_data = compact( 'labels', 'series', 'last_updated' );
    281 
    282                 gp_update_meta( $project_id, 'contributors-chart-data', $chart_data, 'wp-plugins' );
     183                $chart_data = compact( 'labels', 'series' );
    283184
    284185                return $chart_data;
     
    288189         * Prints stats about language packs of a specific project.
    289190         *
    290          * @param string $project_slug Slug of a project.
    291          */
    292         public function get_plugin_language_packs( $project_slug ) {
    293                 $project_path = 'wp-plugins/' . $project_slug;
    294                 $project = GP::$project->by_path( $project_path );
    295                 if ( ! $project ) {
    296                         return $this->die_with_404();
    297                 }
    298 
    299                 if ( function_exists( 'wporg_get_plugin_icon' ) ) {
    300                         $project->icon = wporg_get_plugin_icon( $project->slug, 64 );
    301                 } else {
    302                         $project->icon = '<div class="default-icon"><span class="dashicons dashicons-admin-plugins"></span></div>';
    303                 }
    304 
     191         * @param string $type Type of the language pack, plugin or theme.
     192         * @param string $slug Slug of a project.
     193         */
     194        public function get_language_packs( $type, $slug ) {
    305195                $http_context = stream_context_create( array(
    306196                        'http' => array(
     
    308198                        ),
    309199                ) );
    310                 $json = file_get_contents( "https://api.wordpress.org/translations/plugins/1.0/?slug={$project_slug}", null, $http_context );
     200                if ( 'plugin' === $type ) {
     201                        $type = 'plugins';
     202                } else {
     203                        $type = 'themes';
     204                }
     205                $json = file_get_contents( "https://api.wordpress.org/translations/$type/1.0/?slug={$slug}", null, $http_context );
    311206                $language_packs = $json && '{' == $json[0] ? json_decode( $json ) : null;
    312207
    313                 $this->tmpl( 'projects-wp-plugins-language-packs', get_defined_vars() );
     208                return $language_packs;
    314209        }
    315210
  • sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-routes/routes/wp-plugins.php

    r2663 r2864  
    11<?php
    22
    3 class WPorg_GP_Route_WP_Plugins extends GP_Route {
     3class WPorg_GP_Route_WP_Plugins extends WPorg_GP_Route_WP_Directory {
    44
    55        /**
     
    9494                } );
    9595
    96                 if ( function_exists( 'wporg_get_plugin_icon' ) ) {
    97                         $project->icon = wporg_get_plugin_icon( $project->slug, 64 );
    98                 } else {
    99                         $project->icon = '<div class="default-icon"><span class="dashicons dashicons-admin-plugins"></span></div>';
    100                 }
     96                $project->icon = $this->get_plugin_icon( $project, 64 );
    10197
    10298                $this->tmpl( 'projects-wp-plugins', get_defined_vars() );
     
    117113                }
    118114
    119                 if ( function_exists( 'wporg_get_plugin_icon' ) ) {
    120                         $project->icon = wporg_get_plugin_icon( $project->slug, 64 );
    121                 } else {
    122                         $project->icon = '<div class="default-icon"><span class="dashicons dashicons-admin-plugins"></span></div>';
     115                $project->icon = $this->get_plugin_icon( $project, 64 );
     116
     117                $contributors_by_locale = gp_get_meta( 'wp-plugins', $project->id, 'contributors-by-locale' );
     118                if ( ! $contributors_by_locale || $contributors_by_locale['last_updated'] + HOUR_IN_SECONDS < time() ) {
     119                        $contributors_by_locale = $this->get_contributors( $project );
     120                        $contributors_by_locale['last_updated'] = time();
     121                        gp_update_meta( $project->id, 'contributors-by-locale', $contributors_by_locale, 'wp-plugins' );
    123122                }
    124123
    125                 $contributors_by_locale = array();
    126                 $default_value = array(
    127                         'count' => 0,
    128                         'editors' => array(),
    129                         'contributors' => array(),
    130                 );
    131 
    132                 $translation_editors = $wpdb->get_results( $wpdb->prepare( "
    133                         SELECT
    134                                 `user_id`, `locale`
    135                         FROM {$wpdb->wporg_translation_editors}
    136                         WHERE `project_id` = %d
    137                 ", $project->id ), OBJECT );
    138 
    139                 foreach ( $translation_editors as $translation_editor ) {
    140                         if ( ! isset( $contributors_by_locale[ $translation_editor->locale ] ) ) {
    141                                 $contributors_by_locale[ $translation_editor->locale ] = $default_value;
    142                         }
    143 
    144                         $user = get_user_by( 'id', $translation_editor->user_id );
    145                         if ( ! $user ) {
    146                                 continue;
    147                         }
    148 
    149                         $contributors_by_locale[ $translation_editor->locale ]['editors'][ $translation_editor->user_id ] = (object) array(
    150                                 'nicename'     => $user->user_nicename,
    151                                 'display_name' => $this->_encode( $user->display_name ),
    152                         );
    153 
    154                         $contributors_by_locale[ $translation_editor->locale ]['count']++;
     124                $chart_data = gp_get_meta( 'wp-plugins', $project->id, 'contributors-chart-data' );
     125                if ( ! $chart_data || $chart_data['last_updated'] + DAY_IN_SECONDS < time() ) {
     126                        $chart_data = $this->get_contributors_chart_data( $project );
     127                        $chart_data['last_updated'] = time();
     128                        gp_update_meta( $project->id, 'contributors-chart-data', $chart_data, 'wp-plugins' );
    155129                }
    156130
    157                 unset( $translation_editors );
    158 
    159                 $sub_projects = $wpdb->get_col( $wpdb->prepare( "
    160                         SELECT id
    161                         FROM {$wpdb->gp_projects}
    162                         WHERE parent_project_id = %d
    163                 ", $project->id ) );
    164 
    165                 foreach ( $sub_projects as $sub_project ) {
    166                         foreach( $this->get_translation_contributors_by_locale( $sub_project ) as $row ) {
    167                                 if ( ! isset( $contributors_by_locale[ $row->locale ] ) ) {
    168                                         $contributors_by_locale[ $row->locale ] = $default_value;
    169                                 }
    170 
    171                                 if ( isset( $contributors_by_locale[ $row->locale ]['editors'][ $row->user_id ] ) ) {
    172                                         continue;
    173                                 }
    174 
    175                                 if ( isset( $contributors_by_locale[ $row->locale ]['contributors'][ $row->user_id ] ) ) {
    176                                         continue;
    177                                 }
    178 
    179                                 $user = get_user_by( 'id', $row->user_id );
    180                                 if ( ! $user ) {
    181                                         continue;
    182                                 }
    183 
    184                                 $contributors_by_locale[ $row->locale ]['contributors'][ $row->user_id ] = (object) array(
    185                                         'nicename'     => $user->user_nicename,
    186                                         'display_name' => $this->_encode( $user->display_name ),
    187                                 );
    188 
    189                                 $contributors_by_locale[ $row->locale ]['count']++;
    190                         }
    191                 }
    192 
    193                 $chart_data = $this->get_plugin_contributors_chart_data( $project->id, $sub_projects );
     131                unset( $contributors_by_locale['last_updated'], $chart_data['last_updated'] );
    194132
    195133                $this->tmpl( 'projects-wp-plugins-contributors', get_defined_vars() );
    196         }
    197 
    198         /**
    199          * Generates the chart data for contributors activity.
    200          *
    201          * @param  int    $project_id   The ID of a project. Used to store data as meta.
    202          * @param  array $sub_projects Optional. IDs of sub-projects.
    203          * @return array The data to build a chart via Chartist.js.
    204          */
    205         private function get_plugin_contributors_chart_data( $project_id, $sub_projects = null ) {
    206                 $chart_data = gp_get_meta( 'wp-plugins', $project_id, 'contributors-chart-data' );
    207                 if ( $chart_data ) {
    208                         if ( $chart_data['last_updated'] + DAY_IN_SECONDS > time() ) {
    209                                 return $chart_data;
    210                         }
    211                 }
    212 
    213                 global $wpdb;
    214 
    215                 if ( ! $sub_projects ) {
    216                         $sub_projects = $wpdb->get_col( $wpdb->prepare( "
    217                                 SELECT id
    218                                 FROM {$wpdb->gp_projects}
    219                                 WHERE parent_project_id = %d
    220                         ", $$project_id ) );
    221                 }
    222 
    223                 $translation_set_ids = $wpdb->get_col( "
    224                         SELECT `id` FROM {$wpdb->gp_translation_sets} WHERE `project_id` IN (" . implode( ',', $sub_projects ) . ")
    225                 " );
    226 
    227                 if ( ! $translation_set_ids ) {
    228                         return array();
    229                 }
    230 
    231                 $date_begin = new DateTime( '-6 day' );
    232                 $date_end = new DateTime( 'NOW' );
    233                 $date_interval = new DateInterval( 'P1D' );
    234                 $date_range = new DatePeriod( $date_begin, $date_interval, $date_end );
    235 
    236                 $days = array();
    237                 foreach( $date_range as $date ) {
    238                         $days[] = $date->format( 'Y-m-d' );
    239                 }
    240                 $days[] = $date_end->format( 'Y-m-d' );
    241 
    242                 $counts = $wpdb->get_results( "
    243                         SELECT
    244                                 DATE(date_modified) AS `day`, COUNT(*) AS `count`, `status`
    245                         FROM {$wpdb->gp_translations}
    246                         WHERE
    247                                 `translation_set_id` IN (" . implode( ',', $translation_set_ids ) . ")
    248                                 AND date_modified >= ( CURDATE() - INTERVAL 7 DAY )
    249                         GROUP BY `status`, `day`
    250                         ORDER BY `day` DESC
    251                 " );
    252 
    253                 $status = array( 'current', 'waiting', 'rejected' );
    254                 $data = [];
    255                 foreach ( $days as $day ) {
    256                         $data[ $day ] = array_fill_keys( $status, 0 );
    257                         foreach ( $counts as $count ) {
    258                                 if ( $count->day !== $day || ! in_array( $count->status, $status ) ) {
    259                                         continue;
    260                                 }
    261 
    262                                 $data[ $day ][ $count->status ] = (int) $count->count;
    263                         }
    264                 }
    265 
    266                 $labels = array_keys( $data );
    267                 array_pop( $labels );
    268                 $labels[] = ''; // Don't show a label for today
    269 
    270                 $series = array();
    271                 $series_data = array_values( $data );
    272                 foreach ( $status as $stati ) {
    273                         $series[] = (object) array(
    274                                 'name' => $stati,
    275                                 'data' => wp_list_pluck( $series_data, $stati ),
    276                         );
    277                 }
    278 
    279                 $last_updated = time();
    280                 $chart_data = compact( 'labels', 'series', 'last_updated' );
    281 
    282                 gp_update_meta( $project_id, 'contributors-chart-data', $chart_data, 'wp-plugins' );
    283 
    284                 return $chart_data;
    285134        }
    286135
     
    297146                }
    298147
    299                 if ( function_exists( 'wporg_get_plugin_icon' ) ) {
    300                         $project->icon = wporg_get_plugin_icon( $project->slug, 64 );
    301                 } else {
    302                         $project->icon = '<div class="default-icon"><span class="dashicons dashicons-admin-plugins"></span></div>';
    303                 }
     148                $project->icon = $this->get_plugin_icon( $project, 64 );
    304149
    305150                $http_context = stream_context_create( array(
     
    315160
    316161        /**
    317          * Retrieves translators of a specific project.
     162         * Retrieves the icon of a plugin.
    318163         *
    319          * @param int $project_id Project ID.
    320          * @return object Translators of the project.
     164         * @param GP_Project $project The plugin project.
     165         * @param int        $size    Optional. The size of the icon. Default 64.
     166         * @return string HTML markup for the icon.
    321167         */
    322         private function get_translation_contributors_by_locale( $project_id ) {
    323                 global $wpdb;
     168        private function get_plugin_icon( $project, $size = 64 ) {
     169                $default = '<div class="default-icon"><span class="dashicons dashicons-admin-plugins"></span></div>';
    324170
    325                 $sql = $wpdb->prepare( "
    326                         SELECT ts.`locale`, ts.`slug` AS `locale_slug`, t.`user_id`
    327                         FROM `{$wpdb->gp_translations}` t, `{$wpdb->gp_translation_sets}` ts
    328                         WHERE t.`translation_set_id` = ts.`id`
    329                             AND t.`user_id` IS NOT NULL AND t.`user_id` != 0
    330                             AND t.`date_modified` > %s
    331                             AND ts.`project_id` = %d
    332                             AND t.`status` <> 'rejected'
    333                         GROUP BY ts.`locale`, ts.`slug`, t.`user_id`
    334                 ", date( 'Y-m-d', time() - YEAR_IN_SECONDS ), $project_id );
     171                if ( function_exists( 'wporg_get_plugin_icon' ) ) {
     172                        $icon = wporg_get_plugin_icon( $project->slug, $size );
     173                }
    335174
    336                 return $wpdb->get_results( $sql );
    337         }
     175                if ( $icon ) {
     176                        return $icon;
     177                }
    338178
    339         private function _encode( $raw ) {
    340                 $raw = mb_convert_encoding( $raw, 'UTF-8', 'ASCII, JIS, UTF-8, Windows-1252, ISO-8859-1' );
    341                 return ent2ncr( htmlspecialchars_decode( htmlentities( $raw, ENT_NOQUOTES, 'UTF-8' ), ENT_NOQUOTES ) );
     179                return $default;
    342180        }
    343181}
  • sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-routes/routes/wp-themes.php

    r2858 r2864  
    11<?php
    22
    3 class WPorg_GP_Route_WP_Plugins extends GP_Route {
     3class WPorg_GP_Route_WP_Themes extends WPorg_GP_Route_WP_Directory {
    44
    55        /**
     
    88         * @param string $project_slug Slug of a project.
    99         */
    10         public function get_plugin_projects( $project_slug ) {
     10        public function get_theme_projects( $project_slug ) {
    1111                global $wpdb;
    1212
    13                 $project_path = 'wp-plugins/' . $project_slug;
     13                $project_path = 'wp-themes/' . $project_slug;
    1414                $project = GP::$project->by_path( $project_path );
    1515                if ( ! $project ) {
     
    2626                                LEFT JOIN {$wpdb->gp_projects} p ON stats.project_id = p.id
    2727                        WHERE
    28                                 p.parent_project_id = '{$project->id}'
     28                                p.id = '{$project->id}'
    2929                " );
    3030
     
    3939                                $locale_key = $set->locale . '/' . $set->locale_slug;
    4040                        }
    41                         $sub_project = str_replace( "$project_path/", '', $set->path );
    42                         $sub_projects[ $sub_project ] = true;
    4341
    4442                        /*
     
    4745                         */
    4846                        $percent_complete = (float) $set->percent_complete;
    49                         $translation_locale_statuses[ $locale_key ][ $sub_project ] = ( $percent_complete > 50 ) ? floor( $percent_complete ) : ceil( $percent_complete );
     47                        $translation_locale_statuses[ $locale_key ]['stable'] = ( $percent_complete > 50 ) ? floor( $percent_complete ) : ceil( $percent_complete );
    5048
    5149                        // Increment the amount of waiting and untranslated strings.
     
    6260                        ksort( $translation_locale_statuses[ $locale_key ], SORT_NATURAL );
    6361                }
    64 
    65                 // Check if the plugin has at least one code project. These won't be created if a plugin
    66                 // has no text domain defined.
    67                 $sub_projects = array_keys( $sub_projects );
    68                 $has_error = ( ! in_array( 'dev', $sub_projects ) && ! in_array( 'stable', $sub_projects ) );
    6962
    7063                unset( $project_path, $locale_key, $rows, $set, $sub_project, $sub_projects );
     
    9487                } );
    9588
    96                 if ( function_exists( 'wporg_get_plugin_icon' ) ) {
    97                         $project->icon = wporg_get_plugin_icon( $project->slug, 64 );
    98                 } else {
    99                         $project->icon = '<div class="default-icon"><span class="dashicons dashicons-admin-plugins"></span></div>';
    100                 }
     89                $project->icon = $this->get_theme_icon( $project, 64 );
    10190
    102                 $this->tmpl( 'projects-wp-plugins', get_defined_vars() );
     91                $this->tmpl( 'projects-wp-themes', get_defined_vars() );
    10392        }
    10493
     
    10897         * @param string $project_slug Slug of a project.
    10998         */
    110         public function get_plugin_contributors( $project_slug ) {
     99        public function get_theme_contributors( $project_slug ) {
    111100                global $wpdb;
    112101
    113                 $project_path = 'wp-plugins/' . $project_slug;
     102                $project_path = 'wp-themes/' . $project_slug;
    114103                $project = GP::$project->by_path( $project_path );
    115104                if ( ! $project ) {
     
    117106                }
    118107
    119                 if ( function_exists( 'wporg_get_plugin_icon' ) ) {
    120                         $project->icon = wporg_get_plugin_icon( $project->slug, 64 );
    121                 } else {
    122                         $project->icon = '<div class="default-icon"><span class="dashicons dashicons-admin-plugins"></span></div>';
     108                $project->icon = $this->get_theme_icon( $project, 64 );
     109
     110                $contributors_by_locale = gp_get_meta( 'wp-themes', $project->id, 'contributors-by-locale' );
     111                if ( ! $contributors_by_locale || $contributors_by_locale['last_updated'] + HOUR_IN_SECONDS < time() ) {
     112                        $contributors_by_locale = $this->get_contributors( $project );
     113                        $contributors_by_locale['last_updated'] = time();
     114                        gp_update_meta( $project->id, 'contributors-by-locale', $contributors_by_locale, 'wp-themes' );
    123115                }
    124116
    125                 $contributors_by_locale = array();
    126                 $default_value = array(
    127                         'count' => 0,
    128                         'editors' => array(),
    129                         'contributors' => array(),
    130                 );
    131 
    132                 $translation_editors = $wpdb->get_results( $wpdb->prepare( "
    133                         SELECT
    134                                 `user_id`, `locale`
    135                         FROM {$wpdb->wporg_translation_editors}
    136                         WHERE `project_id` = %d
    137                 ", $project->id ), OBJECT );
    138 
    139                 foreach ( $translation_editors as $translation_editor ) {
    140                         if ( ! isset( $contributors_by_locale[ $translation_editor->locale ] ) ) {
    141                                 $contributors_by_locale[ $translation_editor->locale ] = $default_value;
    142                         }
    143 
    144                         $user = get_user_by( 'id', $translation_editor->user_id );
    145                         if ( ! $user ) {
    146                                 continue;
    147                         }
    148 
    149                         $contributors_by_locale[ $translation_editor->locale ]['editors'][ $translation_editor->user_id ] = (object) array(
    150                                 'nicename'     => $user->user_nicename,
    151                                 'display_name' => $this->_encode( $user->display_name ),
    152                         );
    153 
    154                         $contributors_by_locale[ $translation_editor->locale ]['count']++;
     117                $chart_data = gp_get_meta( 'wp-themes', $project->id, 'contributors-chart-data' );
     118                if ( ! $chart_data || $chart_data['last_updated'] + DAY_IN_SECONDS < time() ) {
     119                        $chart_data = $this->get_contributors_chart_data( $project );
     120                        $chart_data['last_updated'] = time();
     121                        gp_update_meta( $project->id, 'contributors-chart-data', $chart_data, 'wp-themes' );
    155122                }
    156123
    157                 unset( $translation_editors );
    158 
    159                 $sub_projects = $wpdb->get_col( $wpdb->prepare( "
    160                         SELECT id
    161                         FROM {$wpdb->gp_projects}
    162                         WHERE parent_project_id = %d
    163                 ", $project->id ) );
    164 
    165                 foreach ( $sub_projects as $sub_project ) {
    166                         foreach( $this->get_translation_contributors_by_locale( $sub_project ) as $row ) {
    167                                 if ( ! isset( $contributors_by_locale[ $row->locale ] ) ) {
    168                                         $contributors_by_locale[ $row->locale ] = $default_value;
    169                                 }
    170 
    171                                 if ( isset( $contributors_by_locale[ $row->locale ]['editors'][ $row->user_id ] ) ) {
    172                                         continue;
    173                                 }
    174 
    175                                 if ( isset( $contributors_by_locale[ $row->locale ]['contributors'][ $row->user_id ] ) ) {
    176                                         continue;
    177                                 }
    178 
    179                                 $user = get_user_by( 'id', $row->user_id );
    180                                 if ( ! $user ) {
    181                                         continue;
    182                                 }
    183 
    184                                 $contributors_by_locale[ $row->locale ]['contributors'][ $row->user_id ] = (object) array(
    185                                         'nicename'     => $user->user_nicename,
    186                                         'display_name' => $this->_encode( $user->display_name ),
    187                                 );
    188 
    189                                 $contributors_by_locale[ $row->locale ]['count']++;
    190                         }
    191                 }
    192 
    193                 $chart_data = $this->get_plugin_contributors_chart_data( $project->id, $sub_projects );
     124                unset( $contributors_by_locale['last_updated'], $chart_data['last_updated'] );
    194125
    195126                $this->tmpl( 'projects-wp-plugins-contributors', get_defined_vars() );
    196         }
    197 
    198         /**
    199          * Generates the chart data for contributors activity.
    200          *
    201          * @param  int    $project_id   The ID of a project. Used to store data as meta.
    202          * @param  array $sub_projects Optional. IDs of sub-projects.
    203          * @return array The data to build a chart via Chartist.js.
    204          */
    205         private function get_plugin_contributors_chart_data( $project_id, $sub_projects = null ) {
    206                 $chart_data = gp_get_meta( 'wp-plugins', $project_id, 'contributors-chart-data' );
    207                 if ( $chart_data ) {
    208                         if ( $chart_data['last_updated'] + DAY_IN_SECONDS > time() ) {
    209                                 return $chart_data;
    210                         }
    211                 }
    212 
    213                 global $wpdb;
    214 
    215                 if ( ! $sub_projects ) {
    216                         $sub_projects = $wpdb->get_col( $wpdb->prepare( "
    217                                 SELECT id
    218                                 FROM {$wpdb->gp_projects}
    219                                 WHERE parent_project_id = %d
    220                         ", $$project_id ) );
    221                 }
    222 
    223                 $translation_set_ids = $wpdb->get_col( "
    224                         SELECT `id` FROM {$wpdb->gp_translation_sets} WHERE `project_id` IN (" . implode( ',', $sub_projects ) . ")
    225                 " );
    226 
    227                 if ( ! $translation_set_ids ) {
    228                         return array();
    229                 }
    230 
    231                 $date_begin = new DateTime( '-6 day' );
    232                 $date_end = new DateTime( 'NOW' );
    233                 $date_interval = new DateInterval( 'P1D' );
    234                 $date_range = new DatePeriod( $date_begin, $date_interval, $date_end );
    235 
    236                 $days = array();
    237                 foreach( $date_range as $date ) {
    238                         $days[] = $date->format( 'Y-m-d' );
    239                 }
    240                 $days[] = $date_end->format( 'Y-m-d' );
    241 
    242                 $counts = $wpdb->get_results( "
    243                         SELECT
    244                                 DATE(date_modified) AS `day`, COUNT(*) AS `count`, `status`
    245                         FROM {$wpdb->gp_translations}
    246                         WHERE
    247                                 `translation_set_id` IN (" . implode( ',', $translation_set_ids ) . ")
    248                                 AND date_modified >= ( CURDATE() - INTERVAL 7 DAY )
    249                         GROUP BY `status`, `day`
    250                         ORDER BY `day` DESC
    251                 " );
    252 
    253                 $status = array( 'current', 'waiting', 'rejected' );
    254                 $data = [];
    255                 foreach ( $days as $day ) {
    256                         $data[ $day ] = array_fill_keys( $status, 0 );
    257                         foreach ( $counts as $count ) {
    258                                 if ( $count->day !== $day || ! in_array( $count->status, $status ) ) {
    259                                         continue;
    260                                 }
    261 
    262                                 $data[ $day ][ $count->status ] = (int) $count->count;
    263                         }
    264                 }
    265 
    266                 $labels = array_keys( $data );
    267                 array_pop( $labels );
    268                 $labels[] = ''; // Don't show a label for today
    269 
    270                 $series = array();
    271                 $series_data = array_values( $data );
    272                 foreach ( $status as $stati ) {
    273                         $series[] = (object) array(
    274                                 'name' => $stati,
    275                                 'data' => wp_list_pluck( $series_data, $stati ),
    276                         );
    277                 }
    278 
    279                 $last_updated = time();
    280                 $chart_data = compact( 'labels', 'series', 'last_updated' );
    281 
    282                 gp_update_meta( $project_id, 'contributors-chart-data', $chart_data, 'wp-plugins' );
    283 
    284                 return $chart_data;
    285127        }
    286128
     
    290132         * @param string $project_slug Slug of a project.
    291133         */
    292         public function get_plugin_language_packs( $project_slug ) {
    293                 $project_path = 'wp-plugins/' . $project_slug;
     134        public function get_theme_language_packs( $project_slug ) {
     135                $project_path = 'wp-themes/' . $project_slug;
    294136                $project = GP::$project->by_path( $project_path );
    295137                if ( ! $project ) {
     
    297139                }
    298140
    299                 if ( function_exists( 'wporg_get_plugin_icon' ) ) {
    300                         $project->icon = wporg_get_plugin_icon( $project->slug, 64 );
    301                 } else {
    302                         $project->icon = '<div class="default-icon"><span class="dashicons dashicons-admin-plugins"></span></div>';
    303                 }
     141                $project->icon = $this->get_theme_icon( $project, 64 );
    304142
    305                 $http_context = stream_context_create( array(
    306                         'http' => array(
    307                                 'user_agent' => 'WordPress.org Translate',
    308                         ),
    309                 ) );
    310                 $json = file_get_contents( "https://api.wordpress.org/translations/plugins/1.0/?slug={$project_slug}", null, $http_context );
    311                 $language_packs = $json && '{' == $json[0] ? json_decode( $json ) : null;
     143                $language_packs = $this->get_language_packs( 'theme', $project_slug );
    312144
    313145                $this->tmpl( 'projects-wp-plugins-language-packs', get_defined_vars() );
     
    315147
    316148        /**
    317          * Retrieves translators of a specific project.
     149         * Retrieves the icon of a theme.
    318150         *
    319          * @param int $project_id Project ID.
    320          * @return object Translators of the project.
     151         * @param GP_Project $project The theme project.
     152         * @param int        $size    Optional. The size of the icon. Default 64.
     153         * @return string HTML markup for the icon.
    321154         */
    322         private function get_translation_contributors_by_locale( $project_id ) {
    323                 global $wpdb;
     155        private function get_theme_icon( $project, $size = 64 ) {
     156                $default = '<div class="default-icon"><span class="dashicons dashicons-admin-themes"></span></div>';
    324157
    325                 $sql = $wpdb->prepare( "
    326                         SELECT ts.`locale`, ts.`slug` AS `locale_slug`, t.`user_id`
    327                         FROM `{$wpdb->gp_translations}` t, `{$wpdb->gp_translation_sets}` ts
    328                         WHERE t.`translation_set_id` = ts.`id`
    329                             AND t.`user_id` IS NOT NULL AND t.`user_id` != 0
    330                             AND t.`date_modified` > %s
    331                             AND ts.`project_id` = %d
    332                             AND t.`status` <> 'rejected'
    333                         GROUP BY ts.`locale`, ts.`slug`, t.`user_id`
    334                 ", date( 'Y-m-d', time() - YEAR_IN_SECONDS ), $project_id );
     158                $screenshot = gp_get_meta( 'wp-themes', $project->id, 'screenshot' );
     159                if ( $screenshot ) {
     160                        return sprintf(
     161                                '<div class="icon"><img src="%s" alt="" width="%d" height="%d"></div>',
     162                                esc_url( 'https://i0.wp.com/' . $screenshot . '?w=' . $size * 2 . '&strip=all' ),
     163                                $size,
     164                                $size
     165                        );
     166                }
    335167
    336                 return $wpdb->get_results( $sql );
    337         }
    338 
    339         private function _encode( $raw ) {
    340                 $raw = mb_convert_encoding( $raw, 'UTF-8', 'ASCII, JIS, UTF-8, Windows-1252, ISO-8859-1' );
    341                 return ent2ncr( htmlspecialchars_decode( htmlentities( $raw, ENT_NOQUOTES, 'UTF-8' ), ENT_NOQUOTES ) );
     168                return $default;
    342169        }
    343170}
  • sites/trunk/wordpress.org/public_html/wp-content/plugins/wporg-gp-routes/wporg-gp-routes.php

    r2531 r2864  
    1313require_once __DIR__ . '/routes/locale.php';
    1414require_once __DIR__ . '/routes/stats-overview.php';
     15require_once __DIR__ . '/routes/wp-directory.php';
    1516require_once __DIR__ . '/routes/wp-plugins.php';
     17require_once __DIR__ . '/routes/wp-themes.php';
    1618
    1719class WPorg_GP_Routes {
     
    3436         *  - /languages/$locale/$path
    3537         *  - /profile/$path
     38         *  - /projects/wp-plugins/?
     39         *  - /projects/wp-themes/?
    3640         *
    3741         * Adds:
     
    4549         *  - /projects/wp-plugins/$project/contributors
    4650         *  - /projects/wp-plugins/$project/language-packs
     51         *  - /projects/wp-themes/$project
     52         *  - /projects/wp-themes/$project/contributors
     53         *  - /projects/wp-themes/$project/language-packs
    4754         */
    4855        public function register_routes() {
     
    7784                        GP::$router->prepend( "/projects/wp-plugins/$project/contributors", array( 'WPorg_GP_Route_WP_Plugins', 'get_plugin_contributors' ) );
    7885                        GP::$router->prepend( "/projects/wp-plugins/$project/language-packs", array( 'WPorg_GP_Route_WP_Plugins', 'get_plugin_language_packs' ) );
     86                        GP::$router->prepend( "/projects/wp-themes/$project", array( 'WPorg_GP_Route_WP_Themes', 'get_theme_projects' ) );
     87                        GP::$router->prepend( "/projects/wp-themes/$project/contributors", array( 'WPorg_GP_Route_WP_Themes', 'get_theme_contributors' ) );
     88                        GP::$router->prepend( "/projects/wp-themes/$project/language-packs", array( 'WPorg_GP_Route_WP_Themes', 'get_theme_language_packs' ) );
    7989                }
    8090        }
Note: See TracChangeset for help on using the changeset viewer.