Skip to content

Commit a459f3e

Browse files
committed
Refactor get_job_listings() to a class
1 parent 908e0b5 commit a459f3e

5 files changed

+748
-205
lines changed
Lines changed: 370 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,370 @@
1+
<?php
2+
/**
3+
* File containing the class WP_Job_Manager_Listing_Query_Generator.
4+
*
5+
* @package wp-job-manager
6+
* @since 1.35.0
7+
*/
8+
9+
if ( ! defined( 'ABSPATH' ) ) {
10+
exit; // Exit if accessed directly.
11+
}
12+
13+
/**
14+
* Generates the query used to fetch posts for Job Manager and extensions.
15+
*/
16+
abstract class WP_Job_Manager_Listing_Query_Generator {
17+
/**
18+
* Arguments used to generate the query. Set on instantiation.
19+
*
20+
* @var array
21+
*/
22+
private $args;
23+
24+
/**
25+
* Whether we should check the cache and then save the results. Set on instantiation.
26+
*
27+
* @var bool
28+
*/
29+
private $use_cache;
30+
31+
/**
32+
* Stores if we actually used the cache.
33+
*
34+
* @var bool
35+
*/
36+
private $did_use_cache;
37+
38+
/**
39+
* Query generated.
40+
*
41+
* @var WP_Query
42+
*/
43+
private $query;
44+
45+
/**
46+
* WP_Job_Manager_Listing_Query_Generator constructor.
47+
*
48+
* @param array $args Arguments used to generate teh query.
49+
* @param bool $use_cache True if we should use the cache.
50+
*/
51+
public function __construct( $args = [], $use_cache = true ) {
52+
$this->args = self::parse_args( $args );
53+
$this->use_cache = $use_cache;
54+
55+
$this->init();
56+
}
57+
58+
/**
59+
* Salt used for the cache key.
60+
*
61+
* @return string
62+
*/
63+
abstract protected function get_cache_key_salt();
64+
65+
/**
66+
* Get the query arguments used for `WP_Query`.
67+
*
68+
* @return array
69+
*/
70+
abstract protected function get_query_args();
71+
72+
/**
73+
* Get the default arguments used to generate the query.
74+
*
75+
* @return array
76+
*/
77+
abstract protected static function get_default_args();
78+
79+
/**
80+
* Run any tasks that need to be done right away.
81+
*/
82+
protected function init() {
83+
}
84+
85+
/**
86+
* Get the arguments used to generate the query.
87+
*
88+
* @return array
89+
*/
90+
public function get_args() {
91+
return $this->args;
92+
}
93+
94+
/**
95+
* Fires before the query is generated. Can prevent normal generation of `WP_Query` by returning one of its own.
96+
*
97+
* @return void|WP_Query
98+
*/
99+
protected function before_query() {
100+
}
101+
102+
/**
103+
* Fires after the query is generated.
104+
*/
105+
protected function after_query() {
106+
}
107+
108+
/**
109+
* Helper function to generate the `orderby` query argument.
110+
*
111+
* @return array|string
112+
*/
113+
protected function parse_orderby() {
114+
$args = $this->get_args();
115+
116+
if ( ! empty( $args['orderby'] ) ) {
117+
if ( 'featured' === $args['orderby'] ) {
118+
return [
119+
'menu_order' => 'ASC',
120+
'date' => 'DESC',
121+
'ID' => 'DESC',
122+
];
123+
}
124+
125+
if ( 'rand_featured' === $args['orderby'] ) {
126+
return [
127+
'menu_order' => 'ASC',
128+
'rand' => 'ASC',
129+
];
130+
}
131+
132+
return $args['orderby'];
133+
}
134+
135+
// By default, order by date and then ID.
136+
return [
137+
'date' => 'DESC',
138+
'ID' => 'DESC',
139+
];
140+
}
141+
142+
/**
143+
* Returns the default order direction. By default, this will be ignored
144+
*
145+
* @return string
146+
*/
147+
protected function parse_order() {
148+
$args = $this->get_args();
149+
150+
if ( isset( $args['order'] ) ) {
151+
return $args['order'];
152+
}
153+
154+
return 'DESC';
155+
}
156+
157+
/**
158+
* Parses the `offset` argument used in the query.
159+
*
160+
* @return int
161+
*/
162+
protected function parse_offset() {
163+
$args = $this->get_args();
164+
165+
if ( isset( $args['offset'] ) ) {
166+
return absint( $args['offset'] );
167+
}
168+
169+
return 0;
170+
}
171+
172+
/**
173+
* Parses the `posts_per_page` argument used in the query.
174+
*
175+
* @return int
176+
*/
177+
protected function parse_posts_per_page() {
178+
$args = $this->get_args();
179+
180+
if ( isset( $args['posts_per_page'] ) ) {
181+
return intval( $args['posts_per_page'] );
182+
}
183+
184+
return 20;
185+
}
186+
187+
/**
188+
* Parses the `no_found_rows` argument used in the query.
189+
*
190+
* @return bool|null
191+
*/
192+
protected function parse_no_found_rows() {
193+
$args = $this->get_args();
194+
195+
if ( $args['posts_per_page'] < 0 ) {
196+
return true;
197+
}
198+
199+
return null;
200+
}
201+
202+
/**
203+
* Parses the `fields` argument used in the query.
204+
*
205+
* @return string
206+
*/
207+
protected function parse_fields() {
208+
$args = $this->get_args();
209+
210+
if ( ! empty( $args['fields'] ) ) {
211+
return $args['fields'];
212+
}
213+
214+
return 'all';
215+
}
216+
217+
/**
218+
* Returns the query object with the result of the query.
219+
*
220+
* @return WP_Query
221+
*/
222+
public function get_query() {
223+
$this->query = false;
224+
$query = $this->before_query();
225+
$this->did_use_cache = false;
226+
227+
if ( $query instanceof WP_Query ) {
228+
$this->query = $query;
229+
}elseif ( $this->use_cache ) {
230+
$this->query = $this->get_cached_query();
231+
$this->did_use_cache = true;
232+
}
233+
234+
if ( false === $this->query ) {
235+
$this->query = new WP_Query( $this->get_query_args() );
236+
$this->save_cache();
237+
}
238+
239+
$this->after_query();
240+
241+
return $this->query;
242+
}
243+
244+
/**
245+
* True if we actually used the cache when fetching the listing results.
246+
*
247+
* @return bool
248+
*/
249+
public function did_use_cache() {
250+
return $this->did_use_cache;
251+
}
252+
253+
/**
254+
* Perform tasks on cached query result. Can be extended by child classes.
255+
*
256+
* @param WP_Query $query Query that was just re-hydrated from a cached result.
257+
* @return WP_Query
258+
*/
259+
protected function after_cache_hydration( WP_Query $query ) {
260+
$args = $this->get_args();
261+
262+
// Random order is cached so shuffle them. Note: This doesn't really work with pagination.
263+
if ( 'rand_featured' === $args['orderby'] ) {
264+
usort(
265+
$query->posts,
266+
/**
267+
* Helper function to maintain featured status when shuffling results.
268+
*
269+
* @param WP_Post $a
270+
* @param WP_Post $b
271+
*
272+
* @return bool
273+
*/
274+
function ( $a, $b ) {
275+
if ( -1 === $a->menu_order || -1 === $b->menu_order ) {
276+
// Left is featured.
277+
if ( 0 === $b->menu_order ) {
278+
return -1;
279+
}
280+
// Right is featured.
281+
if ( 0 === $a->menu_order ) {
282+
return 1;
283+
}
284+
}
285+
return wp_rand( -1, 1 );
286+
}
287+
);
288+
} elseif ( 'rand' === $args['orderby'] ) {
289+
shuffle( $query->posts );
290+
}
291+
292+
return $query;
293+
}
294+
295+
/**
296+
* Check for results in cache.
297+
*
298+
* @return bool|WP_Query
299+
*/
300+
private function get_cached_query() {
301+
$cache_key = $this->get_cache_key();
302+
$query_args = $this->get_query_args();
303+
$cached_query_posts = get_transient( $cache_key );
304+
305+
if (
306+
$cached_query_posts
307+
&& is_object( $cached_query_posts )
308+
&& isset( $cached_query_posts->max_num_pages )
309+
&& isset( $cached_query_posts->found_posts )
310+
&& isset( $cached_query_posts->posts )
311+
&& is_array( $cached_query_posts->posts )
312+
) {
313+
if ( in_array( $query_args['fields'], [ 'ids', 'id=>parent' ], true ) ) {
314+
// For these special requests, just return the array of results as set.
315+
$posts = $cached_query_posts->posts;
316+
} else {
317+
$posts = array_map( 'get_post', $cached_query_posts->posts );
318+
}
319+
320+
$result = new WP_Query();
321+
$result->parse_query( $query_args );
322+
$result->posts = $posts;
323+
$result->found_posts = intval( $cached_query_posts->found_posts );
324+
$result->max_num_pages = intval( $cached_query_posts->max_num_pages );
325+
$result->post_count = count( $posts );
326+
327+
$result = $this->after_cache_hydration( $result );
328+
329+
return $result;
330+
}
331+
332+
return false;
333+
}
334+
335+
/**
336+
* Save the query result to cache.
337+
*/
338+
private function save_cache() {
339+
if ( ! ( $this->query instanceof WP_Query ) || ! $this->use_cache ) {
340+
return;
341+
}
342+
343+
$cacheable_result = [];
344+
$cacheable_result['posts'] = array_values( $this->query->posts );
345+
$cacheable_result['found_posts'] = $this->query->found_posts;
346+
$cacheable_result['max_num_pages'] = $this->query->max_num_pages;
347+
348+
set_transient( $this->get_cache_key(), wp_json_encode( $cacheable_result ), DAY_IN_SECONDS );
349+
}
350+
351+
/**
352+
* Get the key to use for caching results.
353+
*
354+
* @return string
355+
*/
356+
private function get_cache_key() {
357+
return WP_Job_Manager_Cache_Helper::CACHE_PREFIX . md5( wp_json_encode( $this->get_query_args() ) . $this->get_cache_key_salt() );
358+
}
359+
360+
/**
361+
* Parses the arguments used to generated the query.
362+
*
363+
* @param array $args Arguments used to generate the query.
364+
* @return array
365+
*/
366+
private static function parse_args( $args ) {
367+
return wp_parse_args( $args, static::get_default_args() );
368+
}
369+
370+
}

includes/class-wp-job-manager-cache-helper.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
* @since 1.0.0
1717
*/
1818
class WP_Job_Manager_Cache_Helper {
19+
const CACHE_PREFIX = 'jm_ ';
1920

2021
/**
2122
* Initializes cache hooks.

0 commit comments

Comments
 (0)