3rd-party
2 months ago
abstracts
3 months ago
admin
2 weeks ago
emails
2 weeks ago
forms
2 weeks ago
helper
3 months ago
promoted-jobs
2 weeks ago
ui
2 weeks ago
widgets
2 weeks ago
class-access-token.php
2 years ago
class-dev-tools.php
2 years ago
class-guest-session.php
2 years ago
class-guest-user.php
2 years ago
class-job-dashboard-shortcode.php
6 months ago
class-job-listing-stats.php
2 years ago
class-job-overlay.php
2 years ago
class-stats-dashboard.php
2 years ago
class-stats-script.php
3 months ago
class-stats.php
3 months ago
class-wp-job-manager-ajax.php
2 months ago
class-wp-job-manager-api.php
6 years ago
class-wp-job-manager-blocks.php
2 weeks ago
class-wp-job-manager-cache-helper.php
3 months ago
class-wp-job-manager-category-walker.php
6 years ago
class-wp-job-manager-com-api.php
2 years ago
class-wp-job-manager-data-cleaner.php
2 years ago
class-wp-job-manager-data-exporter.php
3 months ago
class-wp-job-manager-dependency-checker.php
2 years ago
class-wp-job-manager-email-notifications.php
2 years ago
class-wp-job-manager-forms.php
5 years ago
class-wp-job-manager-geocode.php
2 weeks ago
class-wp-job-manager-install.php
2 years ago
class-wp-job-manager-post-types.php
2 weeks ago
class-wp-job-manager-recaptcha.php
6 months ago
class-wp-job-manager-rest-api.php
2 months ago
class-wp-job-manager-shortcodes.php
2 weeks ago
class-wp-job-manager-usage-tracking-data.php
2 years ago
class-wp-job-manager-usage-tracking.php
2 years ago
class-wp-job-manager-widget.php
2 weeks ago
class-wp-job-manager.php
3 months ago
trait-singleton.php
2 years ago
class-stats.php
291 lines
| 1 | <?php |
| 2 | /** |
| 3 | * File containing the class WP_Job_Manager\Stats |
| 4 | * |
| 5 | * @package wp-job-manager |
| 6 | */ |
| 7 | |
| 8 | namespace WP_Job_Manager; |
| 9 | |
| 10 | if ( ! defined( 'ABSPATH' ) ) { |
| 11 | exit; |
| 12 | } |
| 13 | |
| 14 | /** |
| 15 | * Collect and retrieve job statistics. |
| 16 | * |
| 17 | * @since 2.3.0 |
| 18 | */ |
| 19 | class Stats { |
| 20 | use Singleton; |
| 21 | |
| 22 | /** |
| 23 | * Cache group for stat queries. |
| 24 | */ |
| 25 | const CACHE_GROUP = 'wpjm_stats'; |
| 26 | |
| 27 | /** |
| 28 | * Setting key for enabling stats. |
| 29 | */ |
| 30 | const OPTION_ENABLE_STATS = 'job_manager_stats_enable'; |
| 31 | |
| 32 | private const TABLE = 'wpjm_stats'; |
| 33 | |
| 34 | /** |
| 35 | * Constructor. |
| 36 | */ |
| 37 | private function __construct() { |
| 38 | $this->init(); |
| 39 | } |
| 40 | |
| 41 | /** |
| 42 | * Do initialization of all the things needed for stats. |
| 43 | */ |
| 44 | public function init() { |
| 45 | |
| 46 | $this->init_wpdb_alias(); |
| 47 | |
| 48 | if ( ! self::is_enabled() ) { |
| 49 | return; |
| 50 | } |
| 51 | |
| 52 | Stats_Dashboard::instance(); |
| 53 | Stats_Script::instance(); |
| 54 | } |
| 55 | |
| 56 | /** |
| 57 | * Initialize the alias for the stats table on the wpdb object. |
| 58 | * |
| 59 | * @return void |
| 60 | */ |
| 61 | private function init_wpdb_alias() { |
| 62 | global $wpdb; |
| 63 | if ( isset( $wpdb->wpjm_stats ) ) { |
| 64 | return; |
| 65 | } |
| 66 | $wpdb->wpjm_stats = $wpdb->prefix . self::TABLE; |
| 67 | $wpdb->tables[] = self::TABLE; |
| 68 | } |
| 69 | |
| 70 | /** |
| 71 | * Migrate the stats table to the latest version. |
| 72 | * |
| 73 | * @return void |
| 74 | */ |
| 75 | public function migrate_db() { |
| 76 | global $wpdb; |
| 77 | $collate = $wpdb->get_charset_collate(); |
| 78 | require_once ABSPATH . 'wp-admin/includes/upgrade.php'; |
| 79 | \dbDelta( |
| 80 | [ |
| 81 | "CREATE TABLE {$wpdb->wpjm_stats} ( |
| 82 | `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, |
| 83 | `date` date NOT NULL, |
| 84 | `post_id` bigint(20) DEFAULT NULL, |
| 85 | `name` varchar(50) NOT NULL, |
| 86 | `group` varchar(50) DEFAULT '', |
| 87 | `count` bigint(20) unsigned not null default 1, |
| 88 | PRIMARY KEY (`id`), |
| 89 | UNIQUE INDEX `idx_wpjm_stats_name_date_group_post_id` (`name`, `date`, `group`, `post_id`) |
| 90 | ) {$collate}", |
| 91 | ] |
| 92 | ); |
| 93 | } |
| 94 | |
| 95 | /** |
| 96 | * Check if collecting and showing statistics are enabled. |
| 97 | * |
| 98 | * @return bool |
| 99 | */ |
| 100 | public static function is_enabled() { |
| 101 | return (bool) get_option( self::OPTION_ENABLE_STATS, false ); |
| 102 | } |
| 103 | |
| 104 | /** |
| 105 | * Log a stat into the db. |
| 106 | * |
| 107 | * @param string $name The stat name. |
| 108 | * @param array $args { |
| 109 | * Optional args for this stat. |
| 110 | * |
| 111 | * @type string $group The group this stat belongs to. |
| 112 | * @type int $post_id The post_id this stat belongs to. |
| 113 | * @type int $count The amount to increment the stat by. |
| 114 | * @type string $date Date in YYYY-MM-DD format. |
| 115 | * } |
| 116 | * |
| 117 | * @return bool |
| 118 | */ |
| 119 | public function log_stat( string $name, array $args = [] ) { |
| 120 | |
| 121 | if ( ! self::is_enabled() ) { |
| 122 | return false; |
| 123 | } |
| 124 | |
| 125 | return $this->batch_log_stats( |
| 126 | [ |
| 127 | array_merge( |
| 128 | [ 'name' => $name ], |
| 129 | $args |
| 130 | ), |
| 131 | ] |
| 132 | ); |
| 133 | } |
| 134 | |
| 135 | /** |
| 136 | * Log a stat for multiple posts in one query. |
| 137 | * |
| 138 | * @param array[] $stats { |
| 139 | * Array of stats to log, with the following fields. |
| 140 | * |
| 141 | * @type string $name The stat name. |
| 142 | * @type int $post_id Post ids to log the stat for. |
| 143 | * @type string $group Additional data (eg keyword) for the stat. |
| 144 | * @type int $count The amount to increment the stat by. |
| 145 | * @type string $date Date in YYYY-MM-DD format. |
| 146 | * } |
| 147 | * |
| 148 | * @return bool |
| 149 | */ |
| 150 | public function batch_log_stats( array $stats ) { |
| 151 | |
| 152 | if ( ! self::is_enabled() ) { |
| 153 | return false; |
| 154 | } |
| 155 | $stats = array_map( [ $this, 'parse_stats' ], $stats ); |
| 156 | $stats = array_filter( $stats ); |
| 157 | |
| 158 | if ( empty( $stats ) ) { |
| 159 | return false; |
| 160 | } |
| 161 | |
| 162 | global $wpdb; |
| 163 | |
| 164 | $values = []; |
| 165 | |
| 166 | foreach ( $stats as $stat ) { |
| 167 | $values[] = $wpdb->prepare( '(%s, %s, %s, %d, %d)', $stat['name'], $stat['date'], $stat['group'], $stat['post_id'], $stat['count'] ); |
| 168 | } |
| 169 | |
| 170 | // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, |
| 171 | $result = $wpdb->query( |
| 172 | "INSERT INTO {$wpdb->wpjm_stats} " . |
| 173 | '(`name`, `date`, `group`, `post_id`, `count` )' . |
| 174 | // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared |
| 175 | 'VALUES ' . implode( ', ', $values ) . |
| 176 | 'ON DUPLICATE KEY UPDATE `count` = `count` + VALUES(`count`)', |
| 177 | ); |
| 178 | |
| 179 | if ( false === $result ) { |
| 180 | return false; |
| 181 | } |
| 182 | |
| 183 | return true; |
| 184 | } |
| 185 | |
| 186 | /** |
| 187 | * Process and validate stat details. |
| 188 | * |
| 189 | * @param array $args { |
| 190 | * Stat data. |
| 191 | * |
| 192 | * @type string $name The stat name. |
| 193 | * @type string $group Additional data (eg keyword) for the stat. |
| 194 | * @type int $post_id The post_id this stat belongs to. |
| 195 | * @type int $count The amount to increment the stat by. |
| 196 | * @type string $date Date in YYYY-MM-DD format. |
| 197 | * } |
| 198 | * |
| 199 | * @return array|false |
| 200 | */ |
| 201 | private function parse_stats( $args ) { |
| 202 | $args = wp_parse_args( |
| 203 | $args, |
| 204 | [ |
| 205 | 'name' => '', |
| 206 | 'group' => '', |
| 207 | 'post_id' => 0, |
| 208 | 'count' => 1, |
| 209 | 'date' => gmdate( 'Y-m-d' ), |
| 210 | ] |
| 211 | ); |
| 212 | |
| 213 | $args['post_id'] = absint( $args['post_id'] ); |
| 214 | |
| 215 | if ( |
| 216 | ! is_string( $args['name'] ) || |
| 217 | ! is_string( $args['group'] ) || |
| 218 | empty( $args['name'] ) || |
| 219 | strlen( $args['name'] ) > 50 || |
| 220 | strlen( $args['group'] ) > 50 || |
| 221 | empty( $args['post_id'] ) || |
| 222 | ! is_integer( $args['count'] ) ) { |
| 223 | return false; |
| 224 | } |
| 225 | |
| 226 | if ( ! is_string( $args['date'] ) || 1 !== preg_match( '/^(\d{4})-(\d{2})-(\d{2})$/', $args['date'], $date_parts ) ) { |
| 227 | return false; |
| 228 | } |
| 229 | if ( ! wp_checkdate( (int) $date_parts[2], (int) $date_parts[3], (int) $date_parts[1], $args['date'] ) ) { |
| 230 | return false; |
| 231 | } |
| 232 | |
| 233 | $post_status = get_post_status( $args['post_id'] ); |
| 234 | if ( ! $post_status || 'trash' === $post_status ) { |
| 235 | return false; |
| 236 | } |
| 237 | |
| 238 | return $args; |
| 239 | } |
| 240 | |
| 241 | /** |
| 242 | * Delete all stats for a given job. |
| 243 | * |
| 244 | * @param int $post_id |
| 245 | */ |
| 246 | public function delete_stats( $post_id ) { |
| 247 | global $wpdb; |
| 248 | //phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching |
| 249 | $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->wpjm_stats} WHERE post_id = %d", $post_id ) ); |
| 250 | } |
| 251 | |
| 252 | /** |
| 253 | * Delete all stats for a given job. |
| 254 | * |
| 255 | * @param string $stat_name |
| 256 | * @param int $post_id |
| 257 | * @param null $date |
| 258 | * |
| 259 | * @return array |
| 260 | */ |
| 261 | public function get_stats( $stat_name = '', $post_id = null, $date = null ) { |
| 262 | global $wpdb; |
| 263 | |
| 264 | $query = "SELECT * FROM {$wpdb->wpjm_stats} WHERE 1=1 "; |
| 265 | $params = []; |
| 266 | |
| 267 | if ( ! empty( $stat_name ) ) { |
| 268 | $query .= ' AND name = %s'; |
| 269 | $params[] = $stat_name; |
| 270 | } |
| 271 | |
| 272 | if ( ! empty( $post_id ) ) { |
| 273 | $query .= ' AND post_id = %d'; |
| 274 | $params[] = $post_id; |
| 275 | } |
| 276 | |
| 277 | if ( ! empty( $date ) ) { |
| 278 | $query .= ' AND date = %s'; |
| 279 | $params[] = $date; |
| 280 | } |
| 281 | |
| 282 | if ( ! empty( $params ) ) { |
| 283 | // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- Dynamic query. |
| 284 | $query = $wpdb->prepare( $query, $params ); |
| 285 | } |
| 286 | |
| 287 | // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- Prepared above. |
| 288 | return $wpdb->get_results( $query ); |
| 289 | } |
| 290 | } |
| 291 |