PluginProbe
WPGraphQL / trunk
WPGraphQL vtrunk
2.22.3 2.22.2 2.22.1 2.22.0 2.21.1 2.21.0 2.20.0 2.19.0 2.18.0 2.17.0 2.16.0 2.15.1 2.15.0 2.14.1 2.14.0 2.13.0 2.2.0 2.3.0 2.3.3 2.3.6 2.3.8 2.5.0 2.5.1 2.5.2 2.5.3 All 177 releases
wp-graphql / src / Data / Cursor / TermObjectCursor.php

TermObjectCursor.php in WPGraphQL trunk, at src/Data/Cursor/TermObjectCursor.php

245 lines 5.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace WPGraphQL\Data\Cursor;
3
4 use WP_Term;
5
6 class TermObjectCursor extends AbstractCursor {
7
8 /**
9 * @var ?\WP_Term ;
10 */
11 public $cursor_node;
12
13 /**
14 * Counter for meta value joins
15 *
16 * @var int
17 */
18 public $meta_join_alias = 0;
19
20 /**
21 * {@inheritDoc}
22 *
23 * @var string
24 */
25 protected $id_key = 't.term_id';
26
27
28 /**
29 * {@inheritDoc}
30 *
31 * @return ?\WP_Term ;
32 */
33 public function get_cursor_node() {
34 // Bail if no offset.
35 if ( ! $this->cursor_offset ) {
36 return null;
37 }
38
39 /**
40 * If pre-hooked, return filtered node.
41 *
42 * @param \WP_Term|null $pre_term The pre-filtered term node.
43 * @param int $offset The cursor offset.
44 * @param \WPGraphQL\Data\Cursor\TermObjectCursor $node The cursor instance.
45 *
46 * @hookGroup connections
47 * @since 0.0.5
48 *
49 * @return \WP_Term|null
50 */
51 $pre_term = apply_filters( 'graphql_pre_term_cursor_node', null, $this->cursor_offset, $this );
52 if ( null !== $pre_term ) {
53 return $pre_term;
54 }
55
56 // Get cursor node.
57 $term = WP_Term::get_instance( $this->cursor_offset );
58
59 return $term instanceof WP_Term ? $term : null;
60 }
61
62 /**
63 * {@inheritDoc}
64 *
65 * @param array<array<string,mixed>>[]|null $fields The fields from the CursorBuilder to convert to SQL.
66 */
67 public function to_sql( $fields = null ) {
68 $sql = $this->builder->to_sql( $fields );
69 if ( empty( $sql ) ) {
70 return '';
71 }
72 return ' AND ' . $sql;
73 }
74
75 /**
76 * {@inheritDoc}
77 */
78 public function get_where() {
79 // If we have a bad cursor, just skip.
80 if ( ! $this->is_valid_offset_and_node() ) {
81 return '';
82 }
83
84 $orderby = $this->get_query_var( 'orderby' );
85 $order = $this->get_query_var( 'order' );
86
87 if ( 'name' === $orderby ) {
88 if ( '>' === $this->compare ) {
89 $order = 'DESC';
90 $this->compare = '<';
91 } elseif ( '<' === $this->compare ) {
92 $this->compare = '>';
93 $order = 'ASC';
94 }
95 }
96
97 /**
98 * If $orderby is just a string just compare with it directly as DESC
99 */
100 if ( ! empty( $orderby ) && is_string( $orderby ) ) {
101 $this->compare_with( $orderby, $order );
102 }
103
104 /**
105 * If there's no orderby specified yet, compare with the following fields.
106 */
107 if ( ! $this->builder->has_fields() ) {
108 $this->compare_with_cursor_fields();
109 }
110
111 /**
112 * Stabilize cursor by consistently comparing with the ID.
113 */
114 $this->compare_with_id_field();
115
116 return $this->to_sql();
117 }
118
119 /**
120 * Get AND operator for given order by key
121 *
122 * @param string $by The order by key
123 * @param string $order The order direction ASC or DESC
124 */
125 private function compare_with( string $by, string $order ): void {
126
127 // Bail early, if "key" and "value" provided in query_vars.
128 $key = $this->get_query_var( "graphql_cursor_compare_by_{$by}_key" );
129 $value = $this->get_query_var( "graphql_cursor_compare_by_{$by}_value" );
130 if ( ! empty( $key ) && ! empty( $value ) ) {
131 $this->builder->add_field( $key, $value, null, $order );
132 return;
133 }
134
135 // Set "key" as term table column and get "value" from cursor node.
136 $key = "t.{$by}";
137 $value = $this->cursor_node->{$by};
138
139 /**
140 * If key or value are null, check whether this is a meta key based ordering before bailing.
141 */
142 if ( null === $value ) {
143 $meta_key = $this->get_meta_key( $by );
144 if ( $meta_key ) {
145 $this->compare_with_meta_field( $meta_key, $order );
146 }
147 return;
148 }
149
150 $this->builder->add_field( $key, $value, null, $order );
151 }
152
153 /**
154 * Compare with meta key field
155 *
156 * @param string $meta_key meta key
157 * @param string $order The comparison string
158 */
159 private function compare_with_meta_field( string $meta_key, string $order ): void {
160 $meta_type = $this->get_query_var( 'meta_type' );
161 $meta_value = get_term_meta( $this->cursor_offset, $meta_key, true );
162
163 $key = "{$this->wpdb->termmeta}.meta_value";
164
165 /**
166 * WP uses mt1, mt2 etc. style aliases for additional meta value joins.
167 */
168 if ( 0 !== $this->meta_join_alias ) {
169 $key = "mt{$this->meta_join_alias}.meta_value";
170 }
171
172 ++$this->meta_join_alias;
173
174 $this->builder->add_field( $key, $meta_value, $meta_type, $order, $this );
175 }
176
177 /**
178 * Get the actual meta key if any
179 *
180 * @param string $by The order by key
181 *
182 * @return string|null
183 */
184 private function get_meta_key( string $by ) {
185 if ( 'meta_value' === $by || 'meta_value_num' === $by ) {
186 return $this->get_query_var( 'meta_key' );
187 }
188
189 /**
190 * Check for the WP 4.2+ style meta clauses
191 * https://make.wordpress.org/core/2015/03/30/query-improvements-in-wp-4-2-orderby-and-meta_query/
192 */
193 if ( ! isset( $this->query_vars['meta_query'][ $by ] ) ) {
194 return null;
195 }
196
197 $clause = $this->query_vars['meta_query'][ $by ];
198
199 return empty( $clause['key'] ) ? null : $clause['key'];
200 }
201
202 /**
203 * @todo remove in 3.0.0
204 * @deprecated 1.9.0
205 * @codeCoverageIgnore
206 *
207 * @param string $name The name of the query var to get
208 * @return mixed|null
209 */
210 public function get_query_arg( string $name ) {
211 _doing_it_wrong(
212 __METHOD__,
213 sprintf(
214 // translators: %s is the method name
215 esc_html__( 'This method will be removed in the next major release. Use %s instead.', 'wp-graphql' ),
216 self::class . '::get_query_var()'
217 ),
218 '1.9.0'
219 );
220
221 return $this->get_query_var( $name );
222 }
223
224 /**
225 * @todo remove in 3.0.0
226 * @deprecated 1.9.0
227 * @codeCoverageIgnore
228 *
229 * @return ?\WP_Term
230 */
231 public function get_cursor_term() {
232 _doing_it_wrong(
233 __METHOD__,
234 sprintf(
235 // translators: %s is the method name
236 esc_html__( 'This method will be removed in the next major release. Use %s instead.', 'wp-graphql' ),
237 self::class . '::get_cursor_node()'
238 ),
239 '1.9.0'
240 );
241
242 return $this->cursor_node;
243 }
244 }
245