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

wp-graphql / wp-graphql / 14716683875

28 Apr 2025 07:58PM UTC coverage: 84.287% (+1.6%) from 82.648%
14716683875

push

github

actions-user
release: merge develop into master for v2.3.0

15905 of 18870 relevant lines covered (84.29%)

257.23 hits per line

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

92.0
/src/Model/MenuItem.php
1
<?php
2

3
namespace WPGraphQL\Model;
4

5
use Exception;
6
use GraphQL\Error\UserError;
7
use GraphQLRelay\Relay;
8
use WP_Post;
9

10
/**
11
 * Class MenuItem - Models the data for the MenuItem object type
12
 *
13
 * @property string[]      $cssClasses
14
 * @property int           $databaseId
15
 * @property ?string       $description
16
 * @property ?string       $id
17
 * @property ?string       $label
18
 * @property ?string       $linkRelationship
19
 * @property string[]|null $locations
20
 * @property ?int          $menuDatabaseId
21
 * @property ?string       $menuId
22
 * @property int           $objectId
23
 * @property ?int          $parentDatabaseId
24
 * @property ?string       $parentId
25
 * @property ?string       $target
26
 * @property ?string       $title
27
 * @property ?string       $uri
28
 * @property ?string       $url
29
 *
30
 * @package WPGraphQL\Model
31
 */
32
class MenuItem extends Model {
33

34
        /**
35
         * Stores the incoming post data
36
         *
37
         * @var mixed|object $data
38
         */
39
        protected $data;
40

41
        /**
42
         * MenuItem constructor.
43
         *
44
         * @param \WP_Post $post The incoming WP_Post object that needs modeling
45
         *
46
         * @return void
47
         */
48
        public function __construct( WP_Post $post ) {
21✔
49
                $this->data = wp_setup_nav_menu_item( $post );
21✔
50
                parent::__construct();
21✔
51
        }
52

53
        /**
54
         * {@inheritDoc}
55
         *
56
         * If a MenuItem is not connected to a menu that's assigned to a location
57
         * it's not considered a public node.
58
         *
59
         * @throws \Exception
60
         */
61
        public function is_private() {
21✔
62

63
                // If the current user can edit theme options, consider the menu item public
64
                if ( current_user_can( 'edit_theme_options' ) ) {
21✔
65
                        return false;
3✔
66
                }
67

68
                // Get menu locations for the active theme
69
                $locations = get_theme_mod( 'nav_menu_locations' );
20✔
70

71
                // If there are no menu locations, consider the MenuItem private
72
                if ( empty( $locations ) ) {
20✔
73
                        return true;
×
74
                }
75

76
                // Get the values of the locations
77
                $location_ids = array_values( $locations );
20✔
78
                $menus        = wp_get_object_terms( $this->data->ID, 'nav_menu', [ 'fields' => 'ids' ] );
20✔
79

80
                // If there are no menus
81
                if ( empty( $menus ) ) {
20✔
82
                        return true;
×
83
                }
84

85
                if ( is_wp_error( $menus ) ) {
20✔
86
                        // translators: %s is the menu item ID.
87
                        throw new Exception( esc_html( sprintf( __( 'No menus could be found for menu item %s', 'wp-graphql' ), $this->data->ID ) ) );
×
88
                }
89

90
                $menu_id = $menus[0];
20✔
91
                if ( empty( $location_ids ) || ! in_array( $menu_id, $location_ids, true ) ) {
20✔
92
                        return true;
×
93
                }
94

95
                return false;
20✔
96
        }
97

98
        /**
99
         * {@inheritDoc}
100
         */
101
        protected function init() {
21✔
102
                if ( empty( $this->fields ) ) {
21✔
103
                        $this->fields = [
21✔
104
                                'cssClasses'       => function () {
21✔
105
                                        // If all we have is a non-array or an array with one empty
106
                                        // string, return an empty array.
107
                                        if ( ! isset( $this->data->classes ) || ! is_array( $this->data->classes ) || empty( $this->data->classes ) || empty( $this->data->classes[0] ) ) {
4✔
108
                                                return [];
1✔
109
                                        }
110

111
                                        return $this->data->classes;
3✔
112
                                },
21✔
113
                                'databaseId'       => function () {
21✔
114
                                        return absint( $this->data->ID );
21✔
115
                                },
21✔
116
                                'description'      => function () {
21✔
117
                                        return ! empty( $this->data->description ) ? $this->data->description : null;
4✔
118
                                },
21✔
119
                                'id'               => function () {
21✔
120
                                        return ! empty( $this->databaseId ) ? Relay::toGlobalId( 'post', (string) $this->databaseId ) : null;
21✔
121
                                },
21✔
122
                                'label'            => function () {
21✔
123
                                        return ! empty( $this->data->title ) ? $this->html_entity_decode( $this->data->title, 'label', true ) : null;
4✔
124
                                },
21✔
125
                                'linkRelationship' => function () {
21✔
126
                                        return ! empty( $this->data->xfn ) ? $this->data->xfn : null;
4✔
127
                                },
21✔
128
                                'locations'        => function () {
21✔
129
                                        if ( empty( $this->menuDatabaseId ) ) {
18✔
130
                                                return null;
×
131
                                        }
132

133
                                        $menu_locations = get_theme_mod( 'nav_menu_locations' );
18✔
134

135
                                        if ( empty( $menu_locations ) || ! is_array( $menu_locations ) ) {
18✔
136
                                                return null;
×
137
                                        }
138

139
                                        $locations = null;
18✔
140
                                        foreach ( $menu_locations as $location => $id ) {
18✔
141
                                                if ( absint( $id ) === ( $this->menuDatabaseId ) ) {
18✔
142
                                                        $locations[] = $location;
18✔
143
                                                }
144
                                        }
145

146
                                        return $locations;
18✔
147
                                },
21✔
148
                                'menuDatabaseId'   => function () {
21✔
149
                                        $menus = wp_get_object_terms( $this->data->ID, 'nav_menu' );
18✔
150
                                        if ( is_wp_error( $menus ) ) {
18✔
151
                                                throw new UserError( esc_html( $menus->get_error_message() ) );
×
152
                                        }
153

154
                                        return ! empty( $menus[0]->term_id ) ? $menus[0]->term_id : null;
18✔
155
                                },
21✔
156
                                'menuId'           => function () {
21✔
157
                                        return ! empty( $this->menuDatabaseId ) ? Relay::toGlobalId( 'term', (string) $this->menuDatabaseId ) : null;
18✔
158
                                },
21✔
159
                                'objectId'         => function () {
21✔
160
                                        return absint( $this->data->object_id );
×
161
                                },
21✔
162
                                'order'            => function () {
21✔
163
                                        return $this->data->menu_order;
18✔
164
                                },
21✔
165
                                'parentDatabaseId' => function () {
21✔
166
                                        return $this->data->menu_item_parent;
18✔
167
                                },
21✔
168
                                'parentId'         => function () {
21✔
169
                                        return ! empty( $this->parentDatabaseId ) ? Relay::toGlobalId( 'post', (string) $this->parentDatabaseId ) : null;
18✔
170
                                },
21✔
171
                                'path'             => function () {
21✔
172
                                        $url = $this->url;
4✔
173

174
                                        if ( ! empty( $url ) ) {
4✔
175
                                                /** @var array<string,mixed> $parsed */
176
                                                $parsed = wp_parse_url( $url );
4✔
177
                                                if ( isset( $parsed['host'] ) && strpos( home_url(), $parsed['host'] ) ) {
4✔
178
                                                        return $parsed['path'];
3✔
179
                                                }
180
                                        }
181

182
                                        return $url;
1✔
183
                                },
21✔
184
                                'target'           => function () {
21✔
185
                                        return ! empty( $this->data->target ) ? $this->data->target : null;
4✔
186
                                },
21✔
187
                                'title'            => function () {
21✔
188
                                        return ( ! empty( $this->data->attr_title ) ) ? $this->data->attr_title : null;
4✔
189
                                },
21✔
190
                                'uri'              => function () {
21✔
191
                                        $url = $this->url;
4✔
192

193
                                        return ! empty( $url ) ? str_ireplace( home_url(), '', $url ) : null;
4✔
194
                                },
21✔
195
                                'url'              => function () {
21✔
196
                                        return ! empty( $this->data->url ) ? $this->data->url : null;
4✔
197
                                },
21✔
198

199
                                // Deprecated.
200
                                'menuItemId'       => function () {
21✔
201
                                        return $this->databaseId;
14✔
202
                                },
21✔
203
                        ];
21✔
204
                }
205
        }
206
}
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

© 2025 Coveralls, Inc