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

wp-graphql / wp-graphql / 18790791685

24 Oct 2025 08:03PM UTC coverage: 83.207% (-1.4%) from 84.575%
18790791685

push

github

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

2 of 4 new or added lines in 2 files covered. (50.0%)

189 existing lines in 10 files now uncovered.

16143 of 19401 relevant lines covered (83.21%)

257.79 hits per line

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

69.05
/src/Data/Connection/PluginConnectionResolver.php
1
<?php
2
namespace WPGraphQL\Data\Connection;
3

4
/**
5
 * Class PluginConnectionResolver - Connects plugins to other objects
6
 *
7
 * @package WPGraphQL\Data\Connection
8
 * @since 0.0.5
9
 * @extends \WPGraphQL\Data\Connection\AbstractConnectionResolver<array<string,array<string,mixed>>>
10
 */
11
class PluginConnectionResolver extends AbstractConnectionResolver {
12

13
        /**
14
         * A list of all the installed plugins, keyed by their type.
15
         *
16
         * @var ?array{site:array<string,mixed>,mustuse:array<string,mixed>,dropins:array<string,mixed>}
17
         */
18
        protected $all_plugins;
19

20
        /**
21
         * {@inheritDoc}
22
         */
23
        public function get_ids_from_query() {
5✔
24
                $ids     = [];
5✔
25
                $queried = ! empty( $this->query ) ? $this->query : [];
5✔
26

27
                if ( empty( $queried ) ) {
5✔
28
                        return $ids;
×
29
                }
30

31
                foreach ( $queried as $key => $item ) {
5✔
32
                        $ids[ $key ] = $key;
5✔
33
                }
34

35
                return $ids;
5✔
36
        }
37

38
        /**
39
         * {@inheritDoc}
40
         */
41
        protected function prepare_query_args( array $args ): array {
7✔
42
                if ( ! empty( $args['where']['status'] ) ) {
7✔
43
                        $args['where']['stati'] = [ $args['where']['status'] ];
1✔
44
                } elseif ( ! empty( $args['where']['stati'] ) && is_string( $args['where']['stati'] ) ) {
7✔
45
                        $args['where']['stati'] = [ $args['where']['stati'] ];
×
46
                }
47

48
                return $args;
7✔
49
        }
50

51
        /**
52
         * {@inheritDoc}
53
         *
54
         * @return array<string,array<string,mixed>>
55
         */
56
        protected function query( array $query_args ) {
5✔
57
                // Get all plugins.
58
                $plugins = $this->get_all_plugins();
5✔
59

60
                $all_plugins = array_merge( $plugins['site'], $plugins['mustuse'], $plugins['dropins'] );
5✔
61

62
                // Bail early if no plugins.
63
                if ( empty( $all_plugins ) ) {
5✔
64
                        return [];
×
65
                }
66

67
                // Holds the plugin names sorted by status. The other ` status =>  [ plugin_names ] ` will be added later.
68
                $plugins_by_status = [
5✔
69
                        'mustuse' => array_flip( array_keys( $plugins['mustuse'] ) ),
5✔
70
                        'dropins' => array_flip( array_keys( $plugins['mustuse'] ) ),
5✔
71
                ];
5✔
72

73
                // Permissions.
74
                $can_update           = current_user_can( 'update_plugins' );
5✔
75
                $can_view_autoupdates = $can_update && function_exists( 'wp_is_auto_update_enabled_for_type' ) && wp_is_auto_update_enabled_for_type( 'plugin' );
5✔
76
                $show_network_plugins = apply_filters( 'show_network_active_plugins', current_user_can( 'manage_network_plugins' ) );
5✔
77

78
                // Store the plugin stati as array keys for performance.
79
                $active_stati = ! empty( $query_args['where']['stati'] ) ? array_flip( $query_args['where']['stati'] ) : [];
5✔
80

81
                // Get additional plugin info.
82
                $upgradable_list         = $can_update && isset( $active_stati['upgrade'] ) ? get_site_transient( 'update_plugins' ) : [];
5✔
83
                $recently_activated_list = isset( $active_stati['recently_activated'] ) ? get_site_option( 'recently_activated', [] ) : [];
5✔
84

85
                // Loop through the plugins, add additional data, and store them in $plugins_by_status.
86
                foreach ( $all_plugins as $plugin_file => $plugin_data ) {
5✔
87
                        if ( ! file_exists( WP_PLUGIN_DIR . '/' . $plugin_file ) ) {
5✔
88
                                unset( $all_plugins[ $plugin_file ] );
×
89
                                continue;
×
90
                        }
91

92
                        // Handle multisite plugins.
93
                        if ( is_multisite() && is_network_only_plugin( $plugin_file ) && ! is_plugin_active( $plugin_file ) ) {
5✔
94

95
                                // Check for inactive network plugins.
96
                                if ( $show_network_plugins ) {
×
97

98
                                        // add the plugin to the network_inactive and network_inactive list since "network_inactive" are considered inactive
99
                                        $plugins_by_status['inactive'][ $plugin_file ]         = $plugin_file;
×
100
                                        $plugins_by_status['network_inactive'][ $plugin_file ] = $plugin_file;
×
101
                                } else {
102
                                        // Unset and skip to next plugin.
103
                                        unset( $all_plugins[ $plugin_file ] );
×
104
                                        continue;
×
105
                                }
106
                        } elseif ( is_plugin_active_for_network( $plugin_file ) ) {
5✔
107
                                // Check for active network plugins.
108
                                if ( $show_network_plugins ) {
5✔
109
                                        // add the plugin to the network_activated and active list, since "network_activated" are active
110
                                        $plugins_by_status['active'][ $plugin_file ]            = $plugin_file;
5✔
111
                                        $plugins_by_status['network_activated'][ $plugin_file ] = $plugin_file;
5✔
112
                                } else {
113
                                        // Unset and skip to next plugin.
114
                                        unset( $all_plugins[ $plugin_file ] );
×
115
                                        continue;
×
116
                                }
117
                        }
118

119
                        // Populate active/inactive lists.
120
                        // @todo should this include MU/Dropins?
121
                        if ( is_plugin_active( $plugin_file ) ) {
5✔
122
                                $plugins_by_status['active'][ $plugin_file ] = $plugin_file;
5✔
123
                        } else {
124
                                $plugins_by_status['inactive'][ $plugin_file ] = $plugin_file;
5✔
125
                        }
126

127
                        // Populate recently activated list.
128
                        if ( isset( $recently_activated_list[ $plugin_file ] ) ) {
5✔
129
                                $plugins_by_status['recently_activated'][ $plugin_file ] = $plugin_file;
×
130
                        }
131

132
                        // Populate paused list.
133
                        if ( is_plugin_paused( $plugin_file ) ) {
5✔
134
                                $plugins_by_status['paused'][ $plugin_file ] = $plugin_file;
×
135
                        }
136

137
                        // Get update information.
138
                        if ( $can_update && isset( $upgradable_list->response[ $plugin_file ] ) ) {
5✔
139
                                // An update is available.
140
                                $plugin_data['update'] = true;
×
141
                                // Extra info if known.
142
                                $plugin_data = array_merge( (array) $upgradable_list->response[ $plugin_file ], [ 'update-supported' => true ], $plugin_data );
×
143

144
                                // Populate upgradable list.
145
                                $plugins_by_status['upgrade'][ $plugin_file ] = $plugin_file;
×
146
                        } elseif ( isset( $upgradable_list->no_update[ $plugin_file ] ) ) {
5✔
147
                                $plugin_data = array_merge( (array) $upgradable_list->no_update[ $plugin_file ], [ 'update-supported' => true ], $plugin_data );
×
148
                        } elseif ( empty( $plugin_data['update-supported'] ) ) {
5✔
149
                                $plugin_data['update-supported'] = false;
5✔
150
                        }
151

152
                        // Get autoupdate information.
153
                        if ( $can_view_autoupdates ) {
5✔
154
                                /*
155
                                * Create the payload that's used for the auto_update_plugin filter.
156
                                * This is the same data contained within $upgradable_list->(response|no_update) however
157
                                * not all plugins will be contained in those keys, this avoids unexpected warnings.
158
                                */
159
                                $filter_payload = [
×
160
                                        'id'            => $plugin_file,
×
161
                                        'slug'          => '',
×
162
                                        'plugin'        => $plugin_file,
×
163
                                        'new_version'   => '',
×
164
                                        'url'           => '',
×
165
                                        'package'       => '',
×
166
                                        'icons'         => [],
×
167
                                        'banners'       => [],
×
168
                                        'banners_rtl'   => [],
×
169
                                        'tested'        => '',
×
170
                                        'requires_php'  => '',
×
171
                                        'compatibility' => new \stdClass(),
×
172
                                ];
×
173
                                $filter_payload = (object) wp_parse_args( $plugin_data, $filter_payload );
×
174

175
                                if ( function_exists( 'wp_is_auto_update_forced_for_item' ) ) {
×
176
                                        $auto_update_forced                = wp_is_auto_update_forced_for_item( 'plugin', null, $filter_payload );
×
177
                                        $plugin_data['auto-update-forced'] = $auto_update_forced;
×
178
                                }
179
                        }
180

181
                        // Save any changes to the plugin data.
182
                        $all_plugins[ $plugin_file ] = $plugin_data;
5✔
183
                }
184

185
                $plugins_by_status['all'] = array_flip( array_keys( $all_plugins ) );
5✔
186

187
                /**
188
                 * Filters the plugins by status.
189
                 * */
190
                $filtered_plugins = ! empty( $active_stati ) ? array_values( array_intersect_key( $plugins_by_status, $active_stati ) ) : [];
5✔
191
                // If plugins exist for the filter, flatten and return them. Otherwise, return the full list.
192
                $filtered_plugins = ! empty( $filtered_plugins ) ? array_merge( [], ...$filtered_plugins ) : $plugins_by_status['all'];
5✔
193

194
                if ( ! empty( $query_args['where']['search'] ) ) {
5✔
195
                        // Filter by search args.
196
                        $s       = sanitize_text_field( $query_args['where']['search'] );
1✔
197
                        $matches = array_keys(
1✔
198
                                array_filter(
1✔
199
                                        $all_plugins,
1✔
200
                                        static function ( $plugin ) use ( $s ) {
1✔
201
                                                foreach ( $plugin as $value ) {
1✔
202
                                                        if ( is_string( $value ) && false !== stripos( wp_strip_all_tags( $value ), $s ) ) {
1✔
203
                                                                return true;
1✔
204
                                                        }
205
                                                }
206

207
                                                return false;
1✔
208
                                        }
1✔
209
                                )
1✔
210
                        );
1✔
211
                        if ( ! empty( $matches ) ) {
1✔
212
                                $filtered_plugins = array_intersect_key( $filtered_plugins, array_flip( $matches ) );
1✔
213
                        }
214
                }
215

216
                // Return plugin data filtered by args.
217
                return ! empty( $filtered_plugins ) ? array_intersect_key( $all_plugins, $filtered_plugins ) : [];
5✔
218
        }
219

220
        /**
221
         * {@inheritDoc}
222
         */
223
        protected function loader_name(): string {
7✔
224
                return 'plugin';
7✔
225
        }
226

227
        /**
228
         * {@inheritDoc}
229
         */
230
        public function is_valid_offset( $offset ) {
3✔
231
                $plugins = $this->get_all_plugins();
3✔
232

233
                $all_plugins = array_merge( $plugins['site'], $plugins['mustuse'], $plugins['dropins'] );
3✔
234

235
                return array_key_exists( $offset, $all_plugins );
3✔
236
        }
237

238
        /**
239
         * {@inheritDoc}
240
         */
241
        public function should_execute() {
7✔
242
                if ( is_multisite() ) {
7✔
243
                        // update_, install_, and delete_ are handled above with is_super_admin().
244
                        $menu_perms = get_site_option( 'menu_items', [] );
7✔
245
                        if ( empty( $menu_perms['plugins'] ) && ! current_user_can( 'manage_network_plugins' ) ) {
7✔
246
                                return false;
3✔
247
                        }
248
                } elseif ( ! current_user_can( 'activate_plugins' ) ) {
×
249
                        return false;
×
250
                }
251

252
                return true;
5✔
253
        }
254

255
        /**
256
         * Gets all the installed plugins, including must use and drop in plugins.
257
         *
258
         * The result is cached in the ConnectionResolver instance.
259
         *
260
         * @return array{site:array<string,mixed>,mustuse:array<string,mixed>,dropins:array<string,mixed>}
261
         */
262
        protected function get_all_plugins(): array {
5✔
263
                if ( ! isset( $this->all_plugins ) ) {
5✔
264
                        if ( ! function_exists( 'get_plugins' ) ) {
5✔
UNCOV
265
                                require_once ABSPATH . 'wp-admin/includes/plugin.php';
×
266
                        }
267

268
                        // This is missing must use and drop in plugins, so we need to fetch and merge them separately.
269
                        $site_plugins   = apply_filters( 'all_plugins', get_plugins() );
5✔
270
                        $mu_plugins     = apply_filters( 'show_advanced_plugins', true, 'mustuse' ) ? get_mu_plugins() : [];
5✔
271
                        $dropin_plugins = apply_filters( 'show_advanced_plugins', true, 'dropins' ) ? get_dropins() : [];
5✔
272

273
                        $this->all_plugins = [
5✔
274
                                'site'    => is_array( $site_plugins ) ? $site_plugins : [],
5✔
275
                                'mustuse' => $mu_plugins,
5✔
276
                                'dropins' => $dropin_plugins,
5✔
277
                        ];
5✔
278
                }
279

280
                return $this->all_plugins;
5✔
281
        }
282
}
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