Skip to content

Commit

Permalink
Stats snapshots for patterns (#294)
Browse files Browse the repository at this point in the history
Adds functions for gathering stats about patterns and saving them to snapshot posts, similar to what is done on the 5ftf site. A cron job is set up to run at 00:00 UTC daily to save a snapshot. Also adds a simple, work-in-progress page in WP Admin to view the current stats and some basic info about the number of snapshots that have been created.

Fixes #292
  • Loading branch information
coreymckrill authored Jul 16, 2021
1 parent 05c024f commit 8993803
Show file tree
Hide file tree
Showing 6 changed files with 671 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,6 @@
require_once __DIR__ . '/includes/pattern-flag-post-type.php';
require_once __DIR__ . '/includes/pattern-validation.php';
require_once __DIR__ . '/includes/search.php';
require_once __DIR__ . '/includes/admin.php';
require_once __DIR__ . '/includes/favorite.php';
require_once __DIR__ . '/includes/stats.php';
require_once __DIR__ . '/includes/admin.php';
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use WP_Post, WP_Query;
use function WordPressdotorg\Locales\get_locales_with_english_names;
use function WordPressdotorg\Pattern_Directory\Pattern_Flag_Post_Type\get_pattern_ids_with_pending_flags;
use const WordPressdotorg\Pattern_Directory\Pattern_Post_Type\POST_TYPE as PATTERN;
use const WordPressdotorg\Pattern_Directory\Pattern_Flag_Post_Type\POST_TYPE as FLAG;
use const WordPressdotorg\Pattern_Directory\Pattern_Flag_Post_Type\TAX_TYPE as FLAG_REASON;
Expand Down Expand Up @@ -192,34 +193,15 @@ function handle_pattern_list_table_views( WP_Query $query ) {
return;
}

global $wpdb;

$current_screen = get_current_screen();

if ( 'edit-' . PATTERN === $current_screen->id ) {
$orderby = $query->get( 'orderby', 'date' );
$order = $query->get( 'order', 'desc' );

// For string interpolation.
$pattern = PATTERN;
$flag = FLAG;

// phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
// phpcs:ignore WordPress.DB.DirectDatabaseQuery
$valid_ids = $wpdb->get_col(
$wpdb->prepare(
"
SELECT DISTINCT patterns.ID
FROM {$wpdb->posts} patterns
JOIN {$wpdb->posts} flags ON patterns.ID = flags.post_parent AND flags.post_type = '{$flag}' AND flags.post_status = 'pending'
WHERE patterns.post_type = '{$pattern}'
ORDER BY %s %s
",
$orderby,
$order
)
$args = array(
'orderby' => $query->get( 'orderby', 'date' ),
'order' => $query->get( 'order', 'desc' ),
);
// phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared

$valid_ids = get_pattern_ids_with_pending_flags( $args );

if ( empty( $valid_ids ) ) {
$valid_ids = false;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
<?php

namespace WordPressdotorg\Pattern_Directory\Admin\Stats;

use function WordPressdotorg\Pattern_Directory\Stats\{ get_meta_field_schema, get_snapshot_data, get_snapshots };
use const WordPressdotorg\Pattern_Directory\Pattern_Post_Type\POST_TYPE as PATTERN_POST_TYPE;

defined( 'WPINC' ) || die();

/**
* Actions and filters.
*/
add_action( 'admin_menu', __NAMESPACE__ . '\add_subpage' );

/**
* Register an admin page under Block Patterns for viewing stats.
*
* @return void
*/
function add_subpage() {
$parent_slug = add_query_arg( 'post_type', PATTERN_POST_TYPE, 'edit.php' );

$post_type_object = get_post_type_object( PATTERN_POST_TYPE );

add_submenu_page(
$parent_slug,
__( 'Pattern Stats', 'wporg-patterns' ),
__( 'Stats', 'wporg-patterns' ),
$post_type_object->cap->edit_posts,
PATTERN_POST_TYPE . '-stats',
__NAMESPACE__ . '\render_subpage'
);
}

/**
* Render the stats subpage.
*
* @return void
*/
function render_subpage() {
$schema = get_meta_field_schema();
$data = get_snapshot_data();
$snapshot_query = get_snapshots( array(), true );
$snapshots = $snapshot_query->get_posts();
$next_snapshot = wp_get_scheduled_event( PATTERN_POST_TYPE . '_record_snapshot' );

?>
<style>
.number {
font-weight: 700;
text-align: right;
}

.widefat.but-not-too-wide {
width: auto;
}
</style>
<div class="wrap">
<h1 class="wp-heading-inline">
<?php esc_html_e( 'Pattern Stats', 'wporg-patterns' ); ?>
</h1>

<p>
This page is a work in progress. Someday there might be charts!
</p>

<h2>
Right now
</h2>

<table class="widefat but-not-too-wide striped">
<thead>
<tr>
<th>
Meta Key
</th>
<td>
Description
</td>
<td>
Value
</td>
</tr>
</thead>
<tbody>
<?php foreach ( $schema['properties'] as $field_name => $field_schema ) : ?>
<tr>
<th>
<code><?php echo esc_html( $field_name ); ?></code>
</th>
<td>
<?php echo esc_html( $field_schema['description'] ); ?>
</td>
<td class="<?php echo ( is_numeric( $data[ $field_name ] ) ) ? 'number' : ''; ?>">
<?php if ( isset( $data[ $field_name ] ) ) : ?>
<?php if ( is_numeric( $data[ $field_name ] ) ) : ?>
<?php echo esc_html( number_format_i18n( $data[ $field_name ] ) ); ?>
<?php else : ?>
<?php echo esc_html( $data[ $field_name ] ); ?>
<?php endif; ?>
<?php else : ?>
Data missing.
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>

<h2>
Snapshots
</h2>

<p>
Snapshot frequency should be daily at around 00:00 UTC.
<strong>
<?php if ( $next_snapshot ) : ?>
<?php
printf(
'The next snapshot will be captured on %s.',
esc_html( wp_date( 'r', $next_snapshot->timestamp ) )
);
?>
<?php else : ?>
No snapshot is currently scheduled.
<?php endif; ?>
</strong>
</p>

<table class="widefat but-not-too-wide striped">
<tbody>
<tr>
<td>
Number of snapshots
</td>
<td class="number">
<?php echo esc_html( number_format_i18n( $snapshot_query->found_posts ) ); ?>
</td>
</tr>
<tr>
<td>
Earliest snapshot
</td>
<td>
<?php if ( $snapshot_query->found_posts > 0 ) : ?>
<?php echo esc_html( reset( $snapshots )->post_title ); ?>
<?php else : ?>
No data.
<?php endif; ?>
</td>
</tr>
<tr>
<td>
Latest snapshot
</td>
<td>
<?php if ( $snapshot_query->found_posts > 0 ) : ?>
<?php echo esc_html( end( $snapshots )->post_title ); ?>
<?php else : ?>
No data.
<?php endif; ?>
</td>
</tr>
</tbody>
</table>

<h2>
Export
</h2>
<p>
Coming soon! 🎉
</p>
</div>
<?php
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@

require_once __DIR__ . '/admin-flags.php';
require_once __DIR__ . '/admin-patterns.php';
require_once __DIR__ . '/admin-stats.php';
Original file line number Diff line number Diff line change
Expand Up @@ -145,3 +145,49 @@ function check_flag_threshold( $post_ID, $post, $update ) {
) );
}
}

/**
* Get a list of post IDs for patterns that have pending flags.
*
* TODO this isn't used anywhere on the front end, but maybe it should be cached?
*
* @param array $args Optional. Query args. 'orderby' and/or 'order'.
*
* @return int[]
*/
function get_pattern_ids_with_pending_flags( $args = array() ) {
global $wpdb;

$args = wp_parse_args(
$args,
array(
'orderby' => 'date',
'order' => 'desc',
)
);

// For string interpolation.
$pattern = PATTERN;
$flag = POST_TYPE;

// phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
// phpcs:ignore WordPress.DB.DirectDatabaseQuery
$pattern_ids = $wpdb->get_col(
$wpdb->prepare(
"
SELECT DISTINCT patterns.ID
FROM {$wpdb->posts} patterns
JOIN {$wpdb->posts} flags ON patterns.ID = flags.post_parent
AND flags.post_type = '{$flag}'
AND flags.post_status = 'pending'
WHERE patterns.post_type = '{$pattern}'
ORDER BY %s %s
",
$args['orderby'],
$args['order']
)
);
// phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared

return $pattern_ids;
}
Loading

0 comments on commit 8993803

Please sign in to comment.