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 / PostObjectDelete.php

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

177 lines 6.1 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 GraphQLRelay\Relay;
7 use WPGraphQL\Data\PostObjectMutation;
8 use WPGraphQL\Model\Post;
9 use WPGraphQL\Utils\Utils;
10 use WP_Post_Type;
11
12 class PostObjectDelete {
13 /**
14 * Registers the PostObjectDelete mutation.
15 *
16 * @param \WP_Post_Type $post_type_object The post type of the mutation.
17 *
18 * @return void
19 * @throws \Exception
20 */
21 public static function register_mutation( WP_Post_Type $post_type_object ) {
22 $mutation_name = 'delete' . ucwords( $post_type_object->graphql_single_name );
23
24 register_graphql_mutation(
25 $mutation_name,
26 [
27 'inputFields' => self::get_input_fields( $post_type_object ),
28 'outputFields' => self::get_output_fields( $post_type_object ),
29 'mutateAndGetPayload' => self::mutate_and_get_payload( $post_type_object, $mutation_name ),
30 ]
31 );
32 }
33
34 /**
35 * Defines the mutation input field configuration.
36 *
37 * @param \WP_Post_Type $post_type_object The post type of the mutation.
38 *
39 * @return array<string,array<string,mixed>>
40 */
41 public static function get_input_fields( $post_type_object ) {
42 return [
43 'id' => [
44 'type' => [
45 'non_null' => 'ID',
46 ],
47 'description' => static function () use ( $post_type_object ) {
48 // translators: The placeholder is the name of the post's post_type being deleted
49 return sprintf( __( 'The ID of the %1$s to delete', 'wp-graphql' ), $post_type_object->graphql_single_name );
50 },
51 ],
52 'forceDelete' => [
53 'type' => 'Boolean',
54 'description' => static function () {
55 return __( 'Whether the object should be force deleted instead of being moved to the trash', 'wp-graphql' );
56 },
57 ],
58 'ignoreEditLock' => [
59 'type' => 'Boolean',
60 'description' => static function () {
61 return __( 'Override the edit lock when another user is editing the post', 'wp-graphql' );
62 },
63 ],
64 ];
65 }
66
67 /**
68 * Defines the mutation output field configuration.
69 *
70 * @param \WP_Post_Type $post_type_object The post type of the mutation.
71 *
72 * @return array<string,array<string,mixed>>
73 */
74 public static function get_output_fields( WP_Post_Type $post_type_object ) {
75 return [
76 'deletedId' => [
77 'type' => 'ID',
78 'description' => static function () {
79 return __( 'The ID of the deleted object', 'wp-graphql' );
80 },
81 'resolve' => static function ( $payload ) {
82 /** @var \WPGraphQL\Model\Post $deleted */
83 $deleted = $payload['postObject'];
84
85 return ! empty( $deleted->ID ) ? Relay::toGlobalId( 'post', (string) $deleted->ID ) : null;
86 },
87 ],
88 $post_type_object->graphql_single_name => [
89 'type' => $post_type_object->graphql_single_name,
90 'description' => static function () {
91 return __( 'The object before it was deleted', 'wp-graphql' );
92 },
93 'resolve' => static function ( $payload ) {
94 /** @var \WPGraphQL\Model\Post $deleted */
95 $deleted = $payload['postObject'];
96
97 return ! empty( $deleted->ID ) ? $deleted : null;
98 },
99 ],
100 ];
101 }
102
103 /**
104 * Defines the mutation data modification closure.
105 *
106 * @param \WP_Post_Type $post_type_object The post type of the mutation.
107 * @param string $mutation_name The mutation name.
108 *
109 * @return callable(array<string,mixed>$input,\WPGraphQL\AppContext $context,\GraphQL\Type\Definition\ResolveInfo $info):array<string,mixed>
110 */
111 public static function mutate_and_get_payload( WP_Post_Type $post_type_object, string $mutation_name ) {
112 return static function ( $input ) use ( $post_type_object ) {
113 // Get the database ID for the post.
114 $post_id = Utils::get_database_id_from_id( $input['id'] );
115
116 /**
117 * Stop now if a user isn't allowed to delete a post
118 */
119 if ( ! isset( $post_type_object->cap->delete_post ) || ! current_user_can( $post_type_object->cap->delete_post, $post_id ) ) {
120 // translators: the $post_type_object->graphql_plural_name placeholder is the name of the object being mutated
121 throw new UserError( esc_html( sprintf( __( 'Sorry, you are not allowed to delete %1$s', 'wp-graphql' ), $post_type_object->graphql_plural_name ) ) );
122 }
123
124 /**
125 * Check if we should force delete or not
126 */
127 $force_delete = ! empty( $input['forceDelete'] ) && true === $input['forceDelete'];
128
129 /**
130 * Get the post object before deleting it
131 */
132 $post_before_delete = ! empty( $post_id ) ? get_post( $post_id ) : null;
133
134 if ( empty( $post_before_delete ) ) {
135 throw new UserError( esc_html__( 'The post could not be deleted', 'wp-graphql' ) );
136 }
137
138 $post_before_delete = new Post( $post_before_delete );
139
140 /**
141 * If the post is already in the trash, and the forceDelete input was not passed,
142 * don't remove from the trash
143 */
144 if ( 'trash' === $post_before_delete->status && true !== $force_delete ) {
145 // Translators: the first placeholder is the post_type of the object being deleted and the second placeholder is the unique ID of that object
146 throw new UserError( esc_html( sprintf( __( 'The %1$s with id %2$s is already in the trash. To remove from the trash, use the forceDelete input', 'wp-graphql' ), $post_type_object->graphql_single_name, $post_id ) ) );
147 }
148
149 // If post is locked and the override is not specified, do not allow the edit
150 $locked_user_id = PostObjectMutation::check_edit_lock( $post_id, $input );
151 if ( false !== $locked_user_id ) {
152 $user = get_userdata( (int) $locked_user_id );
153 $display_name = isset( $user->display_name ) ? $user->display_name : 'unknown';
154 /* translators: %s: User's display name. */
155 throw new UserError( esc_html( sprintf( __( 'You cannot delete this item. %s is currently editing.', 'wp-graphql' ), $display_name ) ) );
156 }
157
158 /**
159 * Delete the post
160 */
161 $deleted = wp_delete_post( (int) $post_id, $force_delete );
162
163 /**
164 * If the post was moved to the trash, spoof the object's status before returning it
165 */
166 $post_before_delete->status = ( false !== $deleted && true !== $force_delete ) ? 'trash' : $post_before_delete->status;
167
168 /**
169 * Return the deletedId and the object before it was deleted
170 */
171 return [
172 'postObject' => $post_before_delete,
173 ];
174 };
175 }
176 }
177