PluginProbe ʕ •ᴥ•ʔ
WP Job Manager / 2.4.6
WP Job Manager v2.4.6
2.4.6 2.4.5 2.4.4 2.4.3 2.4.2 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.1.0 1.1.1 1.1.2 1.1.3 1.10.0 1.11.0 1.11.1 1.12.0 1.12.1 1.13.0 1.14.0 1.15.0 1.16.0 1.16.1 1.17.0 1.18.0 1.19.0 1.2.0 1.20.0 1.20.1 1.21.0 1.21.1 1.21.2 1.21.3 1.21.4 1.22.0 1.22.1 1.22.2 1.22.3 1.23.0 1.23.1 1.23.10 1.23.11 1.23.12 1.23.13 1.23.2 1.23.3 1.23.4 1.23.5 1.23.6 1.23.7 1.23.8 1.23.9 1.24.0 1.24.0.1 1.25.0 1.25.0.1 1.25.1 1.25.1.1 1.25.2 1.25.2.1 1.25.3 1.25.3.1 1.26.0 1.26.0.1 1.26.1 1.26.1.1 1.26.2 1.26.2.1 1.27.0 1.27.0.1 1.28.0 1.28.0.1 1.29.0 1.29.0.1 1.29.1 1.29.1.1 1.29.2 1.29.2.1 1.29.3 1.29.3.1 1.3.0 1.3.1 1.30.0 1.30.0.1 1.30.1 1.30.1.1 1.30.2 1.30.2.1 1.31.0 1.31.0.1 1.31.1 1.31.1.1 1.31.2 1.31.3 1.32.0 1.32.1 1.32.2 1.32.3 1.33.0 1.33.1 1.33.2 1.33.3 1.33.4 1.33.5 1.34.0 1.34.1 1.34.2 1.34.3 1.34.4 1.34.5 1.35.0 1.35.1 1.35.2 1.35.3 1.36.0 1.36.1 1.36.2 1.37.0 1.38.0 1.38.1 1.39.0 1.4.0 1.40.0 1.40.1 1.40.2 1.41.0 1.42.0 1.5.0 1.5.1 1.5.2 1.6.0 1.7.0 1.7.1 1.7.3 1.8.0 1.8.1 1.8.2 1.9.0 1.9.1 1.9.2 1.9.3 2.0.0 2.1.0 2.1.1 2.2.0 2.2.1 2.2.2 2.3.0 2.4.0 2.4.1
wp-job-manager / includes / class-stats.php
wp-job-manager / includes Last commit date
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