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

wp-graphql / wp-graphql-woocommerce / 13569823583

27 Feb 2025 03:22PM UTC coverage: 83.617% (-0.07%) from 83.69%
13569823583

push

github

web-flow
fix: Better support for private and password protected products implemented (#925)

25 of 67 new or added lines in 5 files covered. (37.31%)

1 existing line in 1 file now uncovered.

12428 of 14863 relevant lines covered (83.62%)

72.2 hits per line

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

24.32
/includes/model/class-wc-post.php
1
<?php
2
/**
3
 * Abstract Model - WC_Post
4
 *
5
 * Defines shared functionality for WooCommerce CPT models.
6
 *
7
 * @package WPGraphQL\WooCommerce\Model
8
 * @since 0.0.1
9
 */
10

11
namespace WPGraphQL\WooCommerce\Model;
12

13
use GraphQL\Error\UserError;
14
use WPGraphQL\Model\Post;
15

16
/**
17
 * Class WC_Post
18
 *
19
 * @property \WC_Data $wc_data
20
 * @property \WP_Post $data
21
 *
22
 * @package WPGraphQL\WooCommerce\Model
23
 */
24
abstract class WC_Post extends Post {
25
        /**
26
         * Stores the WC_Data object connected to the model.
27
         *
28
         * @var \WC_Data
29
         */
30
        protected $wc_data;
31

32
        /**
33
         * WC_Post constructor
34
         *
35
         * @param \WC_Data $data  Data object to be used by the model.
36
         *
37
         * @throws \Exception  Failed to retrieve data source post object.
38
         */
39
        public function __construct( $data ) {
40
                // Store CRUD object.
41
                $this->wc_data = $data;
75✔
42

43
                // Get WP_Post object.
44
                $post = get_post( $data->get_id() );
75✔
45

46
                // Check if product is valid.
47
                if ( ! is_object( $post ) ) {
75✔
48
                        throw new \Exception( __( 'Failed to retrieve data source post object', 'wp-graphql-woocommerce' ) );
×
49
                }
50

51
                // Add $allowed_restricted_fields.
52
                if ( ! has_filter( 'graphql_allowed_fields_on_restricted_type', [ static::class, 'add_allowed_restricted_fields' ] ) ) {
75✔
53
                        add_filter( 'graphql_allowed_fields_on_restricted_type', [ static::class, 'add_allowed_restricted_fields' ], 10, 2 );
75✔
54
                }
55

56
                // Execute Post Model constructor.
57
                parent::__construct( $post );
75✔
58
        }
59

60
        /**
61
         * Injects CRUD object fields into $allowed_restricted_fields
62
         *
63
         * @param array  $allowed_restricted_fields  The fields to allow when the data is designated as restricted to the current user.
64
         * @param string $model_name                 Name of the model the filter is currently being executed in.
65
         *
66
         * @return string[]
67
         */
68
        public static function add_allowed_restricted_fields( $allowed_restricted_fields, $model_name ) {
69
                $class_name = static::class;
1✔
70
                if ( "{$class_name}Object" === $model_name ) {
1✔
71
                        return static::get_allowed_restricted_fields( $allowed_restricted_fields );
×
72
                }
73

74
                return $allowed_restricted_fields;
1✔
75
        }
76

77
        /**
78
         * Return the fields allowed to be displayed even if this entry is restricted.
79
         *
80
         * @param array $allowed_restricted_fields  The fields to allow when the data is designated as restricted to the current user.
81
         *
82
         * @return array
83
         */
84
        protected static function get_allowed_restricted_fields( $allowed_restricted_fields = [] ) {
85
                return [
×
86
                        'isRestricted',
×
87
                        'isPrivate',
×
88
                        'isPublic',
×
89
                        'id',
×
90
                        'databaseId',
×
NEW
91
                        'slug',
×
NEW
92
                        'uri',
×
NEW
93
                        'link',
×
NEW
94
                        'name',
×
NEW
95
                        'isPostsPage',
×
NEW
96
                        'isFrontPage',
×
NEW
97
                        'hasPassword',
×
NEW
98
                        'status',
×
UNCOV
99
                ];
×
100
        }
101

102
        /**
103
         * Forwards function calls to WC_Data sub-class instance.
104
         *
105
         * @param string $method - function name.
106
         * @param array  $args  - function call arguments.
107
         *
108
         * @return mixed
109
         *
110
         * @throws \BadMethodCallException Method not found on WC data object.
111
         */
112
        public function __call( $method, $args ) {
113
                if ( \is_callable( [ $this->wc_data, $method ] ) ) {
3✔
114
                        return $this->wc_data->$method( ...$args );
3✔
115
                }
116

117
                $class = self::class;
×
118
                throw new \BadMethodCallException( "Call to undefined method {$method} on the {$class}" );
×
119
        }
120

121
        /**
122
         * Wrapper function for deleting
123
         *
124
         * @throws \GraphQL\Error\UserError Not authorized.
125
         *
126
         * @param boolean $force_delete Should the data be deleted permanently.
127
         * @return boolean
128
         */
129
        public function delete( $force_delete = false ) {
130
                $post_type_object = $this->post_type_object;
1✔
131
                if ( empty( $post_type_object ) ) {
1✔
132
                        throw new UserError(
×
133
                                __(
×
134
                                        'Post type object not found.',
×
135
                                        'wp-graphql-woocommerce'
×
136
                                )
×
137
                        );
×
138
                }
139

140
                if ( ! current_user_can( $post_type_object->cap->edit_posts ) ) {
1✔
141
                        throw new UserError(
×
142
                                __(
×
143
                                        'User does not have the capabilities necessary to delete this object.',
×
144
                                        'wp-graphql-woocommerce'
×
145
                                )
×
146
                        );
×
147
                }
148

149
                return $this->wc_data->delete( $force_delete );
1✔
150
        }
151

152
        /**
153
         * {@inheritDoc}
154
         */
155
        public function is_private() {
156
                /**
157
                 * Published content is public, not private
158
                 */
159
                if ( 'publish' === $this->data->post_status && $this->post_type_object && empty( $this->data->post_password ) && ( true === $this->post_type_object->public || true === $this->post_type_object->publicly_queryable ) ) {
75✔
160
                        return false;
75✔
161
                }
162

NEW
163
                return parent::is_post_private( $this->data );
×
164
        }
165

166
        /**
167
         * Method for determining if the data should be considered private or not
168
         *
169
         * @param \WP_Post $post_object The object of the post we need to verify permissions for.
170
         *
171
         * @return bool
172
         */
173
        protected function is_post_private( $post_object = null ) {
174
                /**
175
                 * Stores the incoming post type object for the post being modeled
176
                 *
177
                 * @var null|\WP_Post_Type $post_type_object
178
                 */
179
                $post_type_object = $this->post_type_object;
×
180

181
                if ( empty( $post_object ) ) {
×
182
                        $post_object = $this->data;
×
183
                        return true;
×
184
                }
185

186
                /**
187
                 * If the status is NOT publish and the user does NOT have capabilities to edit posts,
188
                 * consider the post private.
189
                 */
190
                if ( ! isset( $post_type_object->cap->edit_posts ) || ! current_user_can( $post_type_object->cap->edit_posts ) ) {
×
191
                        return true;
×
192
                }
193

194
                /**
195
                 * If the owner of the content is the current user
196
                 */
197
                if ( ( true === $this->owner_matches_current_user() ) && 'revision' !== $post_object->post_type ) {
×
198
                        return false;
×
199
                }
200

201
                if ( 'private' === $this->data->post_status && ( ! isset( $post_type_object->cap->read_private_posts ) || ! current_user_can( $post_type_object->cap->read_private_posts ) ) ) {
×
202
                        return true;
×
203
                }
204

NEW
205
                if ( ! empty( $post_object->post_password ) ) {
×
NEW
206
                        return true;
×
207
                }
208

209
                if ( 'auto-draft' === $this->data->post_status ) {
×
210
                        $parent = get_post( (int) $this->data->post_parent );
×
211

212
                        if ( empty( $parent ) ) {
×
213
                                return true;
×
214
                        }
215

216
                        $parent_post_type_obj = $post_type_object;
×
217
                        if ( 'private' === $parent->post_status ) {
×
218
                                $cap = isset( $parent_post_type_obj->cap->read_private_posts ) ? $parent_post_type_obj->cap->read_private_posts : 'read_private_posts';
×
219
                        } else {
220
                                $cap = isset( $parent_post_type_obj->cap->edit_post ) ? $parent_post_type_obj->cap->edit_post : 'edit_post';
×
221
                        }
222

223
                        if ( ! current_user_can( $cap, $parent->ID ) ) {
×
224
                                return true;
×
225
                        }
226
                }//end if
227

228
                return false;
×
229
        }
230

231
        /**
232
         * Returns the source WP_Post instance.
233
         *
234
         * @return \WP_Post
235
         */
236
        public function as_WP_Post() {
237
                return $this->data;
×
238
        }
239

240
        /**
241
         * Returns the source WC_Data instance
242
         *
243
         * @return \WC_Data
244
         */
245
        public function as_WC_Data() {
246
                return $this->wc_data;
3✔
247
        }
248
}
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