• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

AxeWP / wp-graphql-rank-math / 5176687204

pending completion
5176687204

push

github

web-flow
chore: Implement WPGraphQL Code Standards (PHPCS) (#51)

* chore: lint for WPGraphQL-Minimum

* chore: lint for WPGraphQL-Strict

* chore: lint for WPGraphQL-Extra

* chore: lint for WPGraphQL (full)

* chore: update PHPCS ruleset

* chore: update changelog

* fix: restore `rank_math/head` hook

* chore: update composer deps (wpcli fix)

* chore: fix missed files

* chore: update composer deps

* test: bump boilerplate

* chore: update deps to final versions

93 of 93 new or added lines in 32 files covered. (100.0%)

1963 of 2274 relevant lines covered (86.32%)

5.42 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

71.96
/src/Model/Seo.php
1
<?php
2
/**
3
 * The abstract SEO model.
4
 *
5
 * @package \WPGraphQL\RankMath\Model
6
 */
7

8
namespace WPGraphQL\RankMath\Model;
9

10
use RankMath\Helper as RMHelper;
11
use RankMath\Paper\Paper;
12
use WPGraphQL\Model\Model;
13

14
/**
15
 * Class - Seo
16
 *
17
 * @property string $type The type of object.
18
 */
19
abstract class Seo extends Model {
20
        /**
21
         * Stores the incoming post data
22
         *
23
         * @var \WP_Post|\WP_Term|\WP_User|\WP_Post_Type $data
24
         */
25
        protected $data;
26

27
        /**
28
         * The database id for the current object.
29
         *
30
         * @var integer
31
         */
32
        protected int $database_id;
33

34
        /**
35
         * The current RankMath paper helper.
36
         *
37
         * @var \RankMath\Paper\Paper;
38
         */
39
        protected $helper;
40

41
        /**
42
         * The settings prefix
43
         *
44
         * @var string
45
         */
46
        protected string $prefix;
47

48
        /**
49
         * The head markup.
50
         *
51
         * It's stored here to avoid having to query it multiple times.
52
         *
53
         * A `false` value is used to determine whether an attempt has already been made to fetch it. 
54
         * 
55
         * @var string|false|null
56
         */
57
        protected $full_head;
58

59
        /**
60
         * The Global Post at time of Model generation
61
         *
62
         * @var \WP_Post
63
         */
64
        protected $global_post;
65

66
        /**
67
         * The global authordata at time of Model generation
68
         *
69
         * @var \WP_User
70
         */
71
        protected $global_authordata;
72

73
        /**
74
         * Constructor.
75
         *
76
         * @param \WP_User|\WP_Term|\WP_Post|\WP_Post_Type $object .
77
         * @param string                                   $capability .
78
         * @param string[]                                 $allowed_fields .
79
         */
80
        public function __construct( $object, $capability = '', $allowed_fields = [] ) {
81
                $this->full_head = false;
5✔
82
                $this->data      = $object;
5✔
83

84
                $allowed_fields = array_merge(
5✔
85
                        [
5✔
86
                                'title',
5✔
87
                                'description',
5✔
88
                                'robots',
5✔
89
                                'fullHead',
5✔
90
                                'jsonLd',
5✔
91
                                'openGraph',
5✔
92
                                'type',
5✔
93
                        ],
5✔
94
                        $allowed_fields
5✔
95
                );
5✔
96

97
                parent::__construct( $capability, $allowed_fields );
5✔
98

99
                rank_math()->variables->setup();
5✔
100
                // Seat up RM Globals.
101
                $url = $this->get_object_url();
5✔
102

103
                $this->setup_post_head( $url );
5✔
104
        }
105

106
        /**
107
         * {@inheritDoc}
108
         */
109
        public function setup(): void {
110
                Paper::reset();
5✔
111
                /** @var \RankMath\Paper\Paper $paper */
112
                $paper        = Paper::get();
5✔
113
                $this->helper = $paper;
5✔
114
        }
115

116
        /**
117
         * {@inheritDoc}
118
         */
119
        protected function init() {
120
                if ( empty( $this->fields ) ) {
5✔
121
                        $this->fields = [
5✔
122
                                'title'         => function (): ?string {
5✔
123
                                        return $this->helper->get_title() ?: null;
5✔
124
                                },
5✔
125
                                'description'   => function (): ?string {
5✔
126
                                        return $this->helper->get_description() ?: null;
5✔
127
                                },
5✔
128
                                'robots'        => function (): ?array {
5✔
129
                                        return $this->helper->get_robots() ?: null;
5✔
130
                                },
5✔
131
                                'canonicalUrl'  => function (): ?string {
5✔
132
                                        return $this->helper->get_canonical() ?: null; 
4✔
133
                                },
5✔
134
                                'focusKeywords' => function (): ?array {
5✔
135
                                        $keywords = $this->helper->get_keywords();
4✔
136

137
                                        return ! empty( $keywords ) ? explode( ',', $keywords ) : null;
4✔
138
                                },
5✔
139
                                'fullHead'      => function (): ?string {
5✔
140
                                        $head = $this->get_head();
×
141
                                        return $head ?: null;
×
142
                                },
5✔
143
                                'jsonLd'        => static function () {
5✔
144
                                        ob_start();
5✔
145
                                        $json = new \RankMath\Schema\JsonLD();
5✔
146
                                        $json->setup();
5✔
147
                                        $json->json_ld();
5✔
148
                                        $output = ob_get_clean();
5✔
149

150
                                        return [ 'raw' => $output ?: null ];
5✔
151
                                },
5✔
152
                                'openGraph'     => function () {
5✔
153
                                        $head = $this->get_head();
×
154

155
                                        return ! empty( $head ) ? $this->parse_og_tags( $head ) : null;
×
156
                                },
5✔
157
                                'type'          => function (): string {
5✔
158
                                        return $this->get_object_type();
×
159
                                },
5✔
160
                        ];
5✔
161
                }
162
        }
163

164
        /**
165
         * Gets the hydrated meta, falling back to default settings.
166
         *
167
         * @param string $key The local meta key.
168
         * @param string $fallback Optional. The settings meta key.
169
         * @param string $default Optional. The default value.
170
         *
171
         * @return mixed|null
172
         */
173
        protected function get_meta( string $key, string $fallback = '', string $default = '' ) {
174
                $value = null;
4✔
175
                if ( $this->data instanceof \WP_Post ) {
4✔
176
                        $value = RMHelper::get_post_meta( $key, $this->database_id );
2✔
177
                } elseif ( $this->data instanceof \WP_Term ) {
2✔
178
                        $value = RMHelper::get_term_meta( $key, $this->database_id );
1✔
179
                } elseif ( $this->data instanceof \WP_User ) {
1✔
180
                        $value = RMHelper::get_user_meta( $key, $this->database_id );
1✔
181
                }
182

183
                if ( empty( $value ) && ! empty( $fallback ) ) {
4✔
184
                        $value = RMHelper::get_settings( "titles.{$fallback}", $default );
×
185
                        if ( ! empty( $value ) ) {
×
186
                                $value = RMHelper::replace_vars( $value, $this->data );
×
187
                        }
188
                }
189

190
                return ( ! empty( $value ) ? $value : $default ) ?: null;
4✔
191
        }
192

193
        /**
194
         * Gets the object type used to determine how the GraphQL interface should resolve.
195
         */
196
        abstract public function get_object_type(): string;
197

198
        /**
199
         * Gets the object-specific url to use for generating the RankMath <head>.
200
         */
201
        abstract protected function get_object_url(): string;
202

203
        /**
204
         * Gets the object-specific url to use for generating the RankMath <head>.
205
         *
206
         * @deprecated 0.0.8
207
         */
208
        protected function get_rest_url_param(): string {
209
                _deprecated_function( __FUNCTION__, '0.0.8', __NAMESPACE__ . '::get_object_url()' );
×
210
                return $this->get_object_url();
×
211
        }
212

213
        /**
214
         * Gets all the tags that go in the <head>.
215
         *
216
         * Shims the `RankMath\Rest\Headless::get_html_head() private method to avoid a REST Call.
217
         *
218
         * @throws \GraphQL\Error\Error When the REST request is invalid.
219
         * @throws \GraphQL\Error\UserError When REST response fails.
220
         */
221
        protected function get_head(): ?string {
222
                if ( false !== $this->full_head ) {
×
223
                        return $this->full_head;
×
224
                }
225

226
                ob_start();
×
227
                do_action( 'wp' ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals
×
228
                do_action( 'rank_math/head' );
×
229

230
                $head = ob_get_clean();
×
231

232
                $this->full_head = $head ?: null;
×
233

234
                return $this->full_head;
×
235
        }
236

237
        /**
238
         * Parses the Open Graph tags from the head.
239
         *
240
         * @param string $head The head.
241
         *
242
         * @return ?array<string, mixed> The tags.
243
         */
244
        protected function parse_og_tags( string $head ): ?array {
245
                $tags = [];
×
246

247
                if ( preg_match_all( '/<meta (property|name)="([^"]+):([^"]+)" content="([^"]+)" \/>/', $head, $matches ) ) {
×
248
                        $this->save_tags_from_matches( $matches, $tags );
×
249
                }
250

251
                return $tags ?: null;
×
252
        }
253

254
        /**
255
         * Saves the tags from the matches.
256
         *
257
         * @param string[][]           $matches The matches.
258
         * @param array<string, mixed> $tags The tags array reference.
259
         */
260
        private function save_tags_from_matches( array $matches, array &$tags ): void {
261
                // $matches[2] contains the OpenGraph prefix (og, article, twitter, etc ).
262
                foreach ( $matches[2] as $key => $prefix ) {
×
263
                        $property = $matches[3][ $key ];
×
264
                        $value    = $matches[4][ $key ];
×
265

266
                        // If meta tag already exists, save the values as an array.
267
                        if ( isset( $tags[ $prefix ][ $property ] ) ) {
×
268
                                if ( ! is_array( $tags[ $prefix ][ $property ] ) ) {
×
269
                                        $tags[ $prefix ][ $property ] = [ $tags[ $prefix ][ $property ] ];
×
270
                                }
271
                                $tags[ $prefix ][ $property ][] = $value;
×
272
                        } else {
273
                                $tags[ $prefix ][ $property ] = $value;
×
274
                        }
275
                }
276
        }
277

278
        /**
279
         * Prepare head output for a URL.
280
         *
281
         * Shims the RankMath\Rest\Headless::setup_post_head() private method to avoid a REST call.
282
         *
283
         * @param string $url The URL.
284
         */
285
        private function setup_post_head( string $url ): void {
286
                $headless = new \RankMath\Rest\Headless();
5✔
287
                // Setup WordPress.
288
                $_SERVER['REQUEST_URI'] = esc_url_raw( $headless->generate_request_uri( $url ) );
5✔
289
                remove_all_actions( 'wp' );
5✔
290
                remove_all_actions( 'parse_request' );
5✔
291
                remove_all_actions( 'rank_math/head' );
5✔
292
                remove_all_actions( 'rank_math/json_ld' );
5✔
293
                remove_all_actions( 'rank_math/opengraph/facebook' );
5✔
294
                remove_all_actions( 'rank_math/opengraph/twitter' );
5✔
295
                remove_all_actions( 'rank_math/opengraph/slack' );
5✔
296

297
                if ( $headless->is_home ) {
5✔
298
                        $GLOBALS['wp_query']->is_home = true;
1✔
299
                }
300

301
                remove_filter( 'option_rewrite_rules', [ $headless, 'fix_query_notice' ] );
5✔
302

303
                // Setup Rank Math.
304
                rank_math()->variables->setup();
5✔
305
                new \RankMath\Frontend\Frontend();
5✔
306
        }
307
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc