> */ protected array $meta_query = array(); /** * Store or meta query data * * @var array> */ protected array $meta_query_or = array(); /** * Store tax query * * @var array> */ protected array $tax_query = array(); /** * Store all args * * @var array */ protected array $args = array(); /** * Constructor * * @param Object $model The model class name */ public function __construct( $model ) { $this->model = $model; $this->args['post_type'] = $model->get_post_type(); $this->args['post_status'] = Post_Model::$accepted_statuses; } /** * Add a meta query condition (AND) * * @param string|array $key Meta key or array of conditions * @param string $compare Comparison operator * @param mixed $value Meta value * * @return $this */ public function where( $key, $value = null, $compare = '=' ) { if ( is_array( $key ) ) { foreach ( $key as $condition ) { $this->where( ...$condition ); } return $this; } $this->meta_query[] = compact( 'key', 'value', 'compare' ); return $this; } /** * Add an OR meta query condition * * @param string $key * @param string $compare * @param mixed $value * * @return $this */ public function or_where( $key, $value = null, $compare = '=' ) { $this->meta_query_or[] = compact( 'key', 'value', 'compare' ); return $this; } /** * Add a WHERE IN meta query condition * * @param string $key * @param array $values * * @return $this */ public function where_in( $key, array $values ) { $this->meta_query[] = array( 'key' => $key, 'value' => $values, 'compare' => 'IN', ); return $this; } /** * Exclude posts by ID from query results * * @param int|array $ids Post ID or array of post IDs to exclude * * @return $this */ public function where_not_ids( $ids ) { $this->args['post__not_in'] = (array) $ids; return $this; } /** * Add a meta query condition for NULL value * * @param string $key * * @return $this */ public function where_null( $key ) { $this->meta_query[] = array( 'key' => $key, 'compare' => 'NOT EXISTS', ); return $this; } /** * Add a taxonomy query (generic) * * @param string $taxonomy * @param string|array $terms * @param string $field * * @return $this */ public function taxonomy( $taxonomy, $terms, $field = 'slug' ) { $this->tax_query[] = array( 'taxonomy' => $taxonomy, 'field' => $field, 'terms' => (array) $terms, ); return $this; } /** * Add a category query * * @param string|int $slug_or_id * * @return $this */ public function category( $slug_or_id ) { return $this->taxonomy( 'category', $slug_or_id, is_numeric( $slug_or_id ) ? 'term_id' : 'slug' ); } /** * Add a tag query * * @param string|int $slug_or_id * * @return $this */ public function tag( $slug_or_id ) { return $this->taxonomy( 'post_tag', $slug_or_id, is_numeric( $slug_or_id ) ? 'term_id' : 'slug' ); } /** * Set order by custom field * * @param string $field * @param string $direction * * @return $this */ public function orderBy( $field, $direction = 'ASC' ) { $this->args['orderby'] = 'meta_value'; $this->args['meta_key'] = $field; $this->args['order'] = $direction; return $this; } /** * Execute query and return all matched model instances * * @return array */ public function get() { $this->args['numberposts'] = - 1; if ( $meta = $this->build_meta_query() ) { $this->args['meta_query'] = $meta; } if ( $this->tax_query ) { $this->args['tax_query'] = count( $this->tax_query ) > 1 ? array_merge( array( 'relation' => 'AND' ), $this->tax_query ) : $this->tax_query; } $posts = get_posts( $this->args ); return array_map( function ( $post ) { return new $this->model( $post ); }, $posts ); } /** * Paginate the query results * * @param int $per_page * @param int $page * * @return array */ public function paginate( $per_page = 10, $page = 1 ) { $this->args['posts_per_page'] = $per_page; $this->args['paged'] = $page; if ( $meta = $this->build_meta_query() ) { $this->args['meta_query'] = $meta; } if ( $this->tax_query ) { $this->args['tax_query'] = count( $this->tax_query ) > 1 ? array_merge( array( 'relation' => 'AND' ), $this->tax_query ) : $this->tax_query; } $query = new WP_Query( $this->args ); return array( 'items' => array_map( function ( $p ) { return new $this->model( $p ); }, $query->posts ), 'total' => $query->found_posts, 'per_page' => $per_page, 'current_page' => $page, 'last_page' => ceil( $query->found_posts / $per_page ), ); } /** * Return first matched model or null * * @return null|PostModel */ public function first() { $this->args['numberposts'] = 1; if ( $meta = $this->build_meta_query() ) { $this->args['meta_query'] = $meta; } if ( $this->tax_query ) { $this->args['tax_query'] = $this->tax_query; } $posts = get_posts( $this->args ); return $posts ? new $this->model( $posts[0] ) : null; } /** * Count number of matched posts * * @return int */ public function count() { $this->args['posts_per_page'] = 1; $this->args['fields'] = 'ids'; if ( $meta = $this->build_meta_query() ) { $this->args['meta_query'] = $meta; } if ( $this->tax_query ) { $this->args['tax_query'] = $this->tax_query; } $query = new WP_Query( $this->args ); return $query->found_posts; } /** * Check if any record exists * * @return bool */ public function exists() { return $this->count() > 0; } /** * Build meta_query with AND/OR relations * * @return array */ protected function build_meta_query() { $meta = array(); if ( $this->meta_query ) { $meta[] = count( $this->meta_query ) > 0 ? array_merge( array( 'relation' => 'AND' ), $this->meta_query ) : $this->meta_query[0]; } if ( $this->meta_query_or ) { $meta[] = count( $this->meta_query_or ) > 0 ? array_merge( array( 'relation' => 'OR' ), $this->meta_query_or ) : $this->meta_query_or[0]; } if ( count( $meta ) === 1 ) { return $meta[0]; } elseif ( count( $meta ) > 0 ) { return array_merge( array( 'relation' => 'AND' ), $meta ); } return array(); } }