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 / Mutation / UpdateSettings.php

UpdateSettings.php in WPGraphQL trunk, at src/Mutation/UpdateSettings.php

246 lines 7.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace WPGraphQL\Mutation;
4
5 use GraphQL\Error\UserError;
6 use WPGraphQL\AppContext;
7 use WPGraphQL\Data\DataSource;
8 use WPGraphQL\Registry\TypeRegistry;
9 use WPGraphQL\Utils\Utils;
10
11 /**
12 * Class UpdateSettings
13 *
14 * @package WPGraphQL\Mutation
15 */
16 class UpdateSettings {
17
18 /**
19 * Registers the CommentCreate mutation.
20 *
21 * @param \WPGraphQL\Registry\TypeRegistry $type_registry The WPGraphQL TypeRegistry
22 *
23 * @return void
24 */
25 public static function register_mutation( TypeRegistry $type_registry ) {
26 $output_fields = self::get_output_fields( $type_registry );
27 $input_fields = self::get_input_fields( $type_registry );
28
29 if ( empty( $output_fields ) || empty( $input_fields ) ) {
30 return;
31 }
32
33 register_graphql_mutation(
34 'updateSettings',
35 [
36 'inputFields' => $input_fields,
37 'outputFields' => $output_fields,
38 'mutateAndGetPayload' => static function ( $input, AppContext $context ) use ( $type_registry ) {
39 $payload = self::mutate_and_get_payload( $input, $type_registry );
40
41 // Options were just written; drop any setting-group models loaded
42 // earlier in this request so payload fields resolve fresh values.
43 $context->get_loader( 'setting_group' )->clear_all();
44
45 return $payload;
46 },
47 ]
48 );
49 }
50
51 /**
52 * Defines the mutation input field configuration.
53 *
54 * @param \WPGraphQL\Registry\TypeRegistry $type_registry The WPGraphQL TypeRegistry
55 *
56 * @return array<string,array<string,mixed>>
57 */
58 public static function get_input_fields( TypeRegistry $type_registry ) {
59 $allowed_settings = DataSource::get_allowed_settings( $type_registry );
60
61 $input_fields = [];
62
63 if ( ! empty( $allowed_settings ) ) {
64
65 /**
66 * Loop through the $allowed_settings and build fields
67 * for the individual settings
68 */
69 foreach ( $allowed_settings as $setting ) {
70 if ( ! isset( $setting['type'] ) || ! $type_registry->get_type( $setting['type'] ) ) {
71 continue;
72 }
73
74 /**
75 * Readonly settings are not writable, so they are not added to the
76 * mutation input, UNLESS they carry a `graphql_deprecated_input` reason.
77 * In that case the input field is kept (marked deprecated) so existing
78 * schemas that already exposed it don't break; it still rejects the write
79 * at runtime in mutate_and_get_payload().
80 */
81 $deprecation_reason = ! empty( $setting['graphql_deprecated_input'] ) ? (string) $setting['graphql_deprecated_input'] : null;
82
83 if ( ! empty( $setting['graphql_readonly'] ) && null === $deprecation_reason ) {
84 continue;
85 }
86
87 /**
88 * The flat (group-prefixed) input field name is derived once in the
89 * normalized settings map so the input and payload surfaces agree.
90 */
91 $individual_setting_key = isset( $setting['graphql_settings_field_name'] ) ? (string) $setting['graphql_settings_field_name'] : '';
92
93 if ( empty( $individual_setting_key ) ) {
94 continue;
95 }
96
97 /**
98 * Dynamically build the individual setting,
99 * then add it to the $input_fields
100 */
101 $input_fields[ $individual_setting_key ] = [
102 'type' => $setting['type'],
103 'description' => $setting['description'] ?? null,
104 ];
105
106 if ( null !== $deprecation_reason ) {
107 $input_fields[ $individual_setting_key ]['deprecationReason'] = $deprecation_reason;
108 }
109 }
110 }
111
112 return $input_fields;
113 }
114
115 /**
116 * Defines the mutation output field configuration.
117 *
118 * @param \WPGraphQL\Registry\TypeRegistry $type_registry The WPGraphQL TypeRegistry
119 *
120 * @return array<string,array<string,mixed>>
121 */
122 public static function get_output_fields( TypeRegistry $type_registry ) {
123
124 /**
125 * Get the allowed setting groups and their fields
126 */
127 $allowed_setting_groups = DataSource::get_allowed_settings_by_group( $type_registry );
128
129 $output_fields = [];
130
131 /**
132 * Get all of the settings, regardless of group
133 */
134 $output_fields['allSettings'] = [
135 'type' => 'Settings',
136 'description' => static function () {
137 return __( 'Update all settings.', 'wp-graphql' );
138 },
139 'resolve' => static function () {
140 return true;
141 },
142 ];
143
144 if ( ! empty( $allowed_setting_groups ) && is_array( $allowed_setting_groups ) ) {
145 foreach ( $allowed_setting_groups as $group => $setting_type ) {
146 $group_key = DataSource::format_group_name( $group );
147 $setting_type_name = Utils::format_type_name( $group_key . 'Settings' );
148
149 $output_fields[ Utils::format_field_name( $setting_type_name ) ] = [
150 'type' => $setting_type_name,
151 // translators: %s is the setting type name
152 'description' => static function () use ( $setting_type_name ) {
153 // translators: %s is the setting type name
154 return sprintf( __( 'Update the %s setting.', 'wp-graphql' ), $setting_type_name );
155 },
156 'resolve' => static function ( $root, array $args, AppContext $context ) use ( $group_key ) {
157 return $context->get_loader( 'setting_group' )->load_deferred( $group_key );
158 },
159 ];
160 }
161 }
162 return $output_fields;
163 }
164
165 /**
166 * Defines the mutation data modification closure.
167 *
168 * @param array<string,mixed> $input The mutation input
169 * @param \WPGraphQL\Registry\TypeRegistry $type_registry The WPGraphQL TypeRegistry
170 *
171 * @return array<string,array<string,mixed>>
172 *
173 * @throws \GraphQL\Error\UserError
174 */
175 public static function mutate_and_get_payload( array $input, TypeRegistry $type_registry ): array {
176 /**
177 * Check that the user can manage setting options
178 */
179 if ( ! current_user_can( 'manage_options' ) ) {
180 throw new UserError( esc_html__( 'Sorry, you are not allowed to edit settings as this user.', 'wp-graphql' ) );
181 }
182
183 /**
184 * The $updatable_settings_options will store all of the allowed
185 * settings in a WP ready format
186 */
187 $updatable_settings_options = [];
188
189 $allowed_settings = DataSource::get_allowed_settings( $type_registry );
190
191 /**
192 * Loop through the $allowed_settings and build the insert options array
193 */
194 foreach ( $allowed_settings as $key => $setting ) {
195
196 /**
197 * The flat input field name is derived once in the normalized settings
198 * map, so this matches the name registered on the input type.
199 */
200 $individual_setting_key = isset( $setting['graphql_settings_field_name'] ) ? (string) $setting['graphql_settings_field_name'] : '';
201
202 if ( empty( $individual_setting_key ) ) {
203 continue;
204 }
205
206 /**
207 * Dynamically build the individual setting,
208 * then add it to $updatable_settings_options
209 */
210 $updatable_settings_options[ Utils::format_field_name( $individual_setting_key ) ] = [
211 'option' => $key,
212 'group' => $setting['group'],
213 'readonly' => ! empty( $setting['graphql_readonly'] ),
214 ];
215 }
216
217 foreach ( $input as $key => $value ) {
218 /**
219 * Check to see that the input field exists in settings, if so grab the option
220 * name and update the option
221 */
222 if ( ! array_key_exists( $key, $updatable_settings_options ) ) {
223 continue;
224 }
225
226 /**
227 * Throw an error if the setting is readonly, e.g. the site url,
228 * as we do not want users changing it and breaking all the things
229 */
230 if ( ! empty( $updatable_settings_options[ $key ]['readonly'] ) ) {
231 throw new UserError(
232 sprintf(
233 /* translators: %s is the name of the readonly settings input field. */
234 esc_html__( 'Sorry, the %s setting cannot be changed with this mutation, speak with your site administrator to change it.', 'wp-graphql' ),
235 esc_html( $key )
236 )
237 );
238 }
239
240 update_option( $updatable_settings_options[ $key ]['option'], $value );
241 }
242
243 return $updatable_settings_options;
244 }
245 }
246