PluginProbe
Kit (formerly ConvertKit) – Email Newsletter, Email Marketing, Membership, Subscribers and Landing Pages / 3.4.3
Kit (formerly ConvertKit) – Email Newsletter, Email Marketing, Membership, Subscribers and Landing Pages v3.4.3
3.4.3 3.4.2 3.4.1 3.4.0 3.3.9 3.3.8 3.3.7 3.3.6 3.3.5 3.3.4 3.3.3 3.3.2 3.3.1 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.2.6 2.2.7 2.2.8 2.2.9 2.3.0 2.3.1 All 196 releases
← All changes | admin/class-convertkit-admin-restrict-content.php +169 -107 2.2.63.4.3 View file →
@@ -17,8 +17,26 @@
17 17 */
18 18 class ConvertKit_Admin_Restrict_Content {
19 19
20 20 /**
21 + * Holds the ConvertKit Forms resource class.
22 + *
23 + * @since 2.7.3
24 + *
25 + * @var bool|ConvertKit_Resource_Forms
26 + */
27 + public $forms = false;
28 +
29 + /**
30 + * Holds the ConvertKit Tags resource class.
31 + *
32 + * @since 2.3.2
33 + *
34 + * @var bool|ConvertKit_Resource_Tags
35 + */
36 + public $tags = false;
37 +
38 + /**
21 39 * Holds the ConvertKit Products resource class.
22 40 *
23 41 * @since 2.1.0
24 42 *
@@ -45,8 +63,17 @@
45 63 */
46 64 public $restrict_content_filter = 0;
47 65
48 66 /**
67 + * Holds the key for the restrict content enabled flag in the WordPress options table.
68 + *
69 + * @since 3.0.4
70 + *
71 + * @var string
72 + */
73 + public $restrict_content_enabled_key = 'convertkit_restrict_content_enabled';
74 +
75 + /**
49 76 * Registers action and filter hooks.
50 77 *
51 78 * @since 2.1.0
52 79 */
@@ -51,52 +78,81 @@
51 78 * @since 2.1.0
52 79 */
53 80 public function __construct() {
54 81
55 - // Initialize classes that will be used.
56 - $this->restrict_content_settings = new ConvertKit_Settings_Restrict_Content();
82 + // Add New Member Content Wizard button to Pages.
83 + add_filter( 'convertkit_admin_post_register_add_new_buttons', array( $this, 'register_add_new_button' ), 10, 2 );
57 84
58 - // Bail if Restrict Content isn't enabled.
59 - if ( ! $this->restrict_content_settings->enabled() ) {
60 - return;
61 - }
85 + // Filter Page's post state to maybe include a label denoting that Restricted Content is enabled.
86 + // We do this here so we don't run this on Post Types that don't support Restricted Content.
87 + add_filter( 'display_post_states', array( $this, 'maybe_display_restrict_content_post_state' ), 10, 2 );
62 88
63 - // Add New Member Content button.
64 - add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts_and_css' ) );
65 - foreach ( convertkit_get_supported_restrict_content_post_types() as $post_type ) {
66 - add_filter( 'views_edit-' . $post_type, array( $this, 'output_wp_list_table_buttons' ) );
67 - }
68 -
69 89 // Filter WP_List_Table by Restrict Content setting.
70 90 add_action( 'pre_get_posts', array( $this, 'filter_wp_list_table_output' ) );
71 91 add_action( 'restrict_manage_posts', array( $this, 'output_wp_list_table_filters' ) );
72 92
93 + // Update whether any Pages, Posts or CPTs are configured to use Restrict Content when a Page, Post or CPT is created, edited, trashed or deleted.
94 + add_action( 'wp_insert_post', array( $this, 'update_restrict_content_enabled' ) );
95 + add_action( 'trashed_post', array( $this, 'update_restrict_content_enabled' ) );
96 + add_action( 'delete_post', array( $this, 'update_restrict_content_enabled' ) );
97 +
73 98 }
74 99
75 100 /**
76 - * Enqueue JavaScript and CSS when viewing a list of Pages, Posts or Custom Post Types
77 - * in a WP_List_Table that supports Restrict Content functionality.
101 + * Update whether any Pages, Posts or CPTs are configured to use Restrict Content when a
102 + * Page, Post or CPT is created, edited or deleted.
78 103 *
79 - * @since 2.1.0
104 + * @since 3.0.4
80 105 */
81 - public function enqueue_scripts_and_css() {
106 + public function update_restrict_content_enabled() {
82 107
83 - // Bail if we're not on a WP_List_Table screen for a supported Post Type.
84 - if ( ! $this->is_wp_list_table_request_for_supported_post_type() ) {
85 - return;
86 - }
108 + global $wpdb;
87 109
88 - // Enqueue JS and CSS.
89 - wp_enqueue_script( 'convertkit-admin-wp-list-table-buttons', CONVERTKIT_PLUGIN_URL . 'resources/backend/js/wp-list-table-buttons.js', array( 'jquery' ), CONVERTKIT_PLUGIN_VERSION, true );
90 - wp_enqueue_style( 'convertkit-admin-wp-list-table-buttons', CONVERTKIT_PLUGIN_URL . 'resources/backend/css/wp-list-table-buttons.css', array(), CONVERTKIT_PLUGIN_VERSION );
110 + // We don't use WP_Query, as it's expensive on sites with many Pages/Posts/CPTs.
111 + $results = $wpdb->get_results(
112 + $wpdb->prepare(
113 + 'SELECT ' . $wpdb->posts . '.ID
114 + FROM ' . $wpdb->postmeta . '
115 + LEFT JOIN ' . $wpdb->posts . ' ON ' . $wpdb->postmeta . '.post_id = ' . $wpdb->posts . ".ID
116 + WHERE (
117 + (meta_key = '_wp_convertkit_post_meta' AND meta_value LIKE %s)
118 + AND
119 + (meta_key = '_wp_convertkit_post_meta' AND meta_value NOT LIKE %s)
120 + AND
121 + (meta_key = '_wp_convertkit_post_meta' AND meta_value NOT LIKE %s)
122 + )
123 + AND
124 + " . $wpdb->posts . ".post_status = 'publish'
125 + AND
126 + " . $wpdb->posts . ".post_type IN ('" . implode( "', '", convertkit_get_supported_post_types() ) . "') LIMIT 1;", // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQLPlaceholders.QuotedDynamicPlaceholderGeneration
127 + '%' . $wpdb->esc_like( '"restrict_content";' ) . '%',
128 + '%' . $wpdb->esc_like( '"restrict_content";s:0:' ) . '%',
129 + '%' . $wpdb->esc_like( '"restrict_content";s:1:"0"' ) . '%'
130 + )
131 + );
91 132
92 - // Filter Page's post state to maybe include a label denoting that Restricted Content is enabled.
93 - // We do this here so we don't run this on Post Types that don't support Restricted Content.
94 - add_filter( 'display_post_states', array( $this, 'maybe_display_restrict_content_post_state' ), 10, 2 );
133 + // If results are not empty, a Page, Post or CPT is configured to use Restrict Content.
134 + $restrict_content_enabled = ! empty( $results );
95 135
136 + // Update option.
137 + update_option( $this->restrict_content_enabled_key, $restrict_content_enabled );
138 +
96 139 }
97 140
98 141 /**
142 + * Returns whether any Pages, Posts or CPTs are configured to use Restrict Content.
143 + *
144 + * @since 3.0.4
145 + *
146 + * @return bool
147 + */
148 + public function restrict_content_enabled() {
149 +
150 + return (bool) get_option( $this->restrict_content_enabled_key, false );
151 +
152 + }
153 +
154 + /**
99 155 * Query Pages in the WP_List_Table by the Restrict Content filter, if a filter
100 156 * was included in the request.
101 157 *
102 158 * @since 2.1.0
@@ -105,42 +161,58 @@
105 161 */
106 162 public function filter_wp_list_table_output( $query ) {
107 163
108 164 // Bail if no Restrict Content filter specified.
109 - if ( ! array_key_exists( 'convertkit_restrict_content', $_REQUEST ) ) { // phpcs:ignore WordPress.Security.NonceVerification
165 + if ( ! filter_has_var( INPUT_GET, 'convertkit_restrict_content' ) ) {
110 166 return;
111 167 }
112 - if ( ! $_REQUEST['convertkit_restrict_content'] ) { // phpcs:ignore WordPress.Security.NonceVerification
168 +
169 + // Bail if the filter is empty.
170 + if ( empty( filter_input( INPUT_GET, 'convertkit_restrict_content', FILTER_SANITIZE_FULL_SPECIAL_CHARS ) ) ) {
113 171 return;
114 172 }
115 173
116 174 // Don't filter if we're not querying a Post Type that supports Restricted Content.
117 - if ( ! in_array( $query->get( 'post_type' ), convertkit_get_supported_restrict_content_post_types(), true ) ) {
175 + if ( ! in_array( $query->get( 'post_type' ), convertkit_get_supported_post_types(), true ) ) {
118 176 return;
119 177 }
120 178
121 - // Build query.
122 - // Because WordPress stores metadata in a single serialized string for a single key, we have to search
123 - // the string for the Restrict Content setting. However, other settings will also be in this serialized string,
124 - // so to avoid false positives, we define our search value formatted as a serialized string comprising of the
125 - // setting name and value, to be as accurate as possible.
126 - $value = maybe_serialize(
127 - array(
128 - 'restrict_content' => sanitize_text_field( $_REQUEST['convertkit_restrict_content'] ), // phpcs:ignore WordPress.Security.NonceVerification
129 - )
130 - );
179 + // Store Restrict Content filter value.
180 + $this->restrict_content_filter = filter_input( INPUT_GET, 'convertkit_restrict_content', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
131 181
132 - // Strip a:1:{ and final }, as a Post's serialized settings will include other settings.
133 - $value = str_replace( 'a:1:{', '', $value ); // e.g. s:16:"restrict_content";s:13:"product_36377";}.
134 - $value = substr( $value, 0, strlen( $value ) - 1 ); // e.g. s:16:"restrict_content";s:13:"product_36377";.
182 + switch ( $this->restrict_content_filter ) {
183 + case 'all-member-only':
184 + $meta_query = array(
185 + 'key' => '_wp_convertkit_post_meta',
186 + 'value' => '.*?(form|tag|product)_[0-9]+.*?',
187 + 'compare' => 'REGEXP',
188 + );
189 + break;
190 + default:
191 + // Build query.
192 + // Because WordPress stores metadata in a single serialized string for a single key, we have to search
193 + // the string for the Restrict Content setting. However, other settings will also be in this serialized string,
194 + // so to avoid false positives, we define our search value formatted as a serialized string comprising of the
195 + // setting name and value, to be as accurate as possible.
196 + $value = maybe_serialize(
197 + array(
198 + 'restrict_content' => $this->restrict_content_filter,
199 + )
200 + );
135 201
136 - // Add value to query.
137 - $meta_query = array(
138 - 'key' => '_wp_convertkit_post_meta',
139 - 'value' => $value,
140 - 'compare' => 'LIKE',
141 - );
202 + // Strip a:1:{ and final }, as a Post's serialized settings will include other settings.
203 + $value = str_replace( 'a:1:{', '', $value ); // e.g. s:16:"restrict_content";s:13:"product_36377";}.
204 + $value = substr( $value, 0, strlen( $value ) - 1 ); // e.g. s:16:"restrict_content";s:13:"product_36377";.
142 205
206 + // Add value to query.
207 + $meta_query = array(
208 + 'key' => '_wp_convertkit_post_meta',
209 + 'value' => $value,
210 + 'compare' => 'LIKE',
211 + );
212 + break;
213 + }
214 +
143 215 // If the existing meta query is an array, append our query to it, so we honor
144 216 // any other constraints that have been defined by WordPress or third party code.
145 217 $existing_meta_query = $query->get( 'meta_query' );
146 218 if ( is_array( $existing_meta_query ) ) {
@@ -149,43 +221,56 @@
149 221 } else {
150 222 $query->set( 'meta_query', array( $meta_query ) );
151 223 }
152 224
153 - // Store Restrict Content filter value.
154 - $this->restrict_content_filter = sanitize_text_field( $_REQUEST['convertkit_restrict_content'] ); // phpcs:ignore WordPress.Security.NonceVerification
155 -
156 225 }
157 226
158 227 /**
159 - * Outputs a button in the WP_List_Table filters to run the Restrict Content Setup process.
228 + * Registers a button in the Pages WP_List_Table linking to the the Restrict Content Setup Wizard.
160 229 *
161 - * JS will move this button to be displayed next to the "Add New" button when viewing the table of Pages or Posts,
162 - * as there is not a native WordPress action/filter for registering buttons next to the "Add New" button.
230 + * @since 2.5.5
163 231 *
164 - * @since 2.1.0
165 - *
166 - * @param array $views Views.
167 - * @return array Views
232 + * @param array $buttons Buttons.
233 + * @param string $post_type Post Type.
234 + * @return array Views
168 235 */
169 - public function output_wp_list_table_buttons( $views ) {
236 + public function register_add_new_button( $buttons, $post_type ) {
170 237
171 238 // If no API credentials have been set, don't output the button.
172 239 $settings = new ConvertKit_Settings();
173 - if ( ! $settings->has_api_key_and_secret() ) {
174 - return $views;
240 + if ( ! $settings->has_access_and_refresh_token() ) {
241 + return $buttons;
175 242 }
176 243
177 - // Get current post type that we're viewing.
178 - $post_type = $this->get_current_post_type();
244 + // If the Add New Landing Page / Member Content button is disabled, don't output the button.
245 + if ( $settings->add_new_button_disabled() ) {
246 + return $buttons;
247 + }
179 248
180 - // Don't output button if we couldn't determine the current post type.
181 - if ( ! $post_type ) {
182 - return $views;
249 + // Bail if the Post Type isn't supported.
250 + if ( ! in_array( $post_type, convertkit_get_supported_post_types(), true ) ) {
251 + return $buttons;
183 252 }
184 253
185 - $views['convertkit_restrict_content_setup'] = '<a href="admin.php?page=convertkit-restrict-content-setup&post_type=' . esc_attr( $post_type ) . '" class="convertkit-action page-title-action hidden">' . esc_html__( 'Add New Member Content', 'convertkit' ) . '</a>';
186 - return $views;
254 + // Don't show the button if the user cannot create and publish this Post Type.
255 + if ( ! convertkit_user_can_create_published_post_type( $post_type ) ) {
256 + return $buttons;
257 + }
187 258
259 + // Register button.
260 + $buttons['convertkit_restrict_content_setup'] = array(
261 + 'url' => add_query_arg(
262 + array(
263 + 'page' => 'convertkit-restrict-content-setup',
264 + 'ck_post_type' => $post_type,
265 + ),
266 + admin_url( 'options.php' )
267 + ),
268 + 'label' => __( 'Member Content', 'convertkit' ),
269 + );
270 +
271 + return $buttons;
272 +
188 273 }
189 274
190 275 /**
191 276 * Outputs a dropdown filter on a WP_List_Table filter section to permit
@@ -197,23 +282,25 @@
197 282 */
198 283 public function output_wp_list_table_filters( $post_type ) {
199 284
200 285 // Don't output filters if we're not viewing a Post Type that supports Restricted Content.
201 - if ( ! in_array( $post_type, convertkit_get_supported_restrict_content_post_types(), true ) ) {
286 + if ( ! in_array( $post_type, convertkit_get_supported_post_types(), true ) ) {
202 287 return;
203 288 }
204 289
205 290 // Don't output filters if API credentials have not been defined in the Plugin's settings.
206 291 $settings = new ConvertKit_Settings();
207 - if ( ! $settings->has_api_key_and_secret() ) {
292 + if ( ! $settings->has_access_and_refresh_token() ) {
208 293 return;
209 294 }
210 295
211 - // Fetch Products.
296 + // Initialize Forms, Products and Tags resource classes.
297 + $this->forms = new ConvertKit_Resource_Forms();
212 298 $this->products = new ConvertKit_Resource_Products();
299 + $this->tags = new ConvertKit_Resource_Tags();
213 300
214 - // Don't display filter if no Products exist.
215 - if ( ! $this->products->exist() ) {
301 + // Don't display filter if no Tags and no Products exist.
302 + if ( ! $this->products->exist() && ! $this->tags->exist() ) {
216 303 return;
217 304 }
218 305
219 306 // Output filter.
@@ -221,9 +308,9 @@
221 308
222 309 }
223 310
224 311 /**
225 - * Appends the 'ConvertKit Member Content' text to a Page's Title in the WP_List_Table,
312 + * Appends the 'Kit Member Content' text to a Page's Title in the WP_List_Table,
226 313 * if the given Page has a Restrict Content setting.
227 314 *
228 315 * @param string[] $post_states An array of post display states.
229 316 * @param WP_Post $post The current post object.
@@ -230,8 +317,13 @@
230 317 * @return string[] An array of post display states
231 318 */
232 319 public function maybe_display_restrict_content_post_state( $post_states, $post ) {
233 320
321 + // Bail if we're not on a WP_List_Table screen for a supported Post Type.
322 + if ( ! $this->is_wp_list_table_request_for_supported_post_type() ) {
323 + return $post_states;
324 + }
325 +
234 326 // Fetch Post's settings.
235 327 $convertkit_post = new ConvertKit_Post( $post->ID );
236 328
237 329 // Return post states, unedited, if Restrict Content isn't enabled on this Post.
@@ -239,9 +331,9 @@
239 331 return $post_states;
240 332 }
241 333
242 334 // Add Post State.
243 - $post_states['convertkit_restrict_content'] = esc_html__( 'ConvertKit Member Content', 'convertkit' );
335 + $post_states['convertkit_restrict_content'] = esc_html__( 'Kit Member Content', 'convertkit' );
244 336
245 337 // Return.
246 338 return $post_states;
247 339
@@ -256,45 +348,15 @@
256 348 * @return bool Is WP_List_Table request for a supported Post Type.
257 349 */
258 350 private function is_wp_list_table_request_for_supported_post_type() {
259 351
260 - // Bail if we cannot determine the screen.
261 - if ( ! function_exists( 'get_current_screen' ) ) {
262 - return false;
263 - }
264 -
265 - // Get screen.
266 - $screen = get_current_screen();
267 -
268 352 // Bail if we're not on an edit.php screen.
269 - if ( $screen->base !== 'edit' ) {
353 + if ( convertkit_get_current_screen( 'base' ) !== 'edit' ) {
270 354 return false;
271 355 }
272 356
273 357 // Return whether Post Type is supported for Restrict Content functionality.
274 - return in_array( $screen->post_type, convertkit_get_supported_restrict_content_post_types(), true );
275 -
276 - }
277 -
278 - /**
279 - * Get the current post type based on the screen that is viewed.
280 - *
281 - * @since 2.1.0
282 - *
283 - * @return bool|string
284 - */
285 - private function get_current_post_type() {
286 -
287 - // Bail if we cannot determine the screen.
288 - if ( ! function_exists( 'get_current_screen' ) ) {
289 - return false;
290 - }
291 -
292 - // Get screen.
293 - $screen = get_current_screen();
294 -
295 - // Return post type.
296 - return $screen->post_type;
358 + return in_array( convertkit_get_current_screen( 'post_type' ), convertkit_get_supported_post_types(), true );
297 359
298 360 }
299 361
300 362 }