get_results( $wpdb->prepare( 'SELECT ' . $wpdb->posts . '.ID FROM ' . $wpdb->postmeta . ' LEFT JOIN ' . $wpdb->posts . ' ON ' . $wpdb->postmeta . '.post_id = ' . $wpdb->posts . ".ID WHERE ( (meta_key = '_wp_convertkit_post_meta' AND meta_value LIKE %s) AND (meta_key = '_wp_convertkit_post_meta' AND meta_value NOT LIKE %s) AND (meta_key = '_wp_convertkit_post_meta' AND meta_value NOT LIKE %s) ) AND " . $wpdb->posts . ".post_status = 'publish' AND " . $wpdb->posts . ".post_type IN ('" . implode( "', '", convertkit_get_supported_post_types() ) . "') LIMIT 1;", // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQLPlaceholders.QuotedDynamicPlaceholderGeneration '%' . $wpdb->esc_like( '"restrict_content";' ) . '%', '%' . $wpdb->esc_like( '"restrict_content";s:0:' ) . '%', '%' . $wpdb->esc_like( '"restrict_content";s:1:"0"' ) . '%' ) ); // If results are not empty, a Page, Post or CPT is configured to use Restrict Content. $restrict_content_enabled = ! empty( $results ); // Update option. update_option( $this->restrict_content_enabled_key, $restrict_content_enabled ); } /** * Returns whether any Pages, Posts or CPTs are configured to use Restrict Content. * * @since 3.0.4 * * @return bool */ public function restrict_content_enabled() { return (bool) get_option( $this->restrict_content_enabled_key, false ); } /** * Query Pages in the WP_List_Table by the Restrict Content filter, if a filter * was included in the request. * * @since 2.1.0 * * @param WP_Query $query WordPress Query. */ public function filter_wp_list_table_output( $query ) { // Bail if no Restrict Content filter specified. if ( ! filter_has_var( INPUT_GET, 'convertkit_restrict_content' ) ) { return; } // Bail if the filter is empty. if ( empty( filter_input( INPUT_GET, 'convertkit_restrict_content', FILTER_SANITIZE_FULL_SPECIAL_CHARS ) ) ) { return; } // Don't filter if we're not querying a Post Type that supports Restricted Content. if ( ! in_array( $query->get( 'post_type' ), convertkit_get_supported_post_types(), true ) ) { return; } // Store Restrict Content filter value. $this->restrict_content_filter = filter_input( INPUT_GET, 'convertkit_restrict_content', FILTER_SANITIZE_FULL_SPECIAL_CHARS ); switch ( $this->restrict_content_filter ) { case 'all-member-only': $meta_query = array( 'key' => '_wp_convertkit_post_meta', 'value' => '.*?(form|tag|product)_[0-9]+.*?', 'compare' => 'REGEXP', ); break; default: // Build query. // Because WordPress stores metadata in a single serialized string for a single key, we have to search // the string for the Restrict Content setting. However, other settings will also be in this serialized string, // so to avoid false positives, we define our search value formatted as a serialized string comprising of the // setting name and value, to be as accurate as possible. $value = maybe_serialize( array( 'restrict_content' => $this->restrict_content_filter, ) ); // Strip a:1:{ and final }, as a Post's serialized settings will include other settings. $value = str_replace( 'a:1:{', '', $value ); // e.g. s:16:"restrict_content";s:13:"product_36377";}. $value = substr( $value, 0, strlen( $value ) - 1 ); // e.g. s:16:"restrict_content";s:13:"product_36377";. // Add value to query. $meta_query = array( 'key' => '_wp_convertkit_post_meta', 'value' => $value, 'compare' => 'LIKE', ); break; } // If the existing meta query is an array, append our query to it, so we honor // any other constraints that have been defined by WordPress or third party code. $existing_meta_query = $query->get( 'meta_query' ); if ( is_array( $existing_meta_query ) ) { $existing_meta_query[] = $meta_query; $query->set( 'meta_query', $existing_meta_query ); } else { $query->set( 'meta_query', array( $meta_query ) ); } } /** * Registers a button in the Pages WP_List_Table linking to the the Restrict Content Setup Wizard. * * @since 2.5.5 * * @param array $buttons Buttons. * @param string $post_type Post Type. * @return array Views */ public function register_add_new_button( $buttons, $post_type ) { // If no API credentials have been set, don't output the button. $settings = new ConvertKit_Settings(); if ( ! $settings->has_access_and_refresh_token() ) { return $buttons; } // If the Add New Landing Page / Member Content button is disabled, don't output the button. if ( $settings->add_new_button_disabled() ) { return $buttons; } // Bail if the Post Type isn't supported. if ( ! in_array( $post_type, convertkit_get_supported_post_types(), true ) ) { return $buttons; } // Don't show the button if the user cannot create and publish this Post Type. if ( ! convertkit_user_can_create_published_post_type( $post_type ) ) { return $buttons; } // Register button. $buttons['convertkit_restrict_content_setup'] = array( 'url' => add_query_arg( array( 'page' => 'convertkit-restrict-content-setup', 'ck_post_type' => $post_type, ), admin_url( 'options.php' ) ), 'label' => __( 'Member Content', 'convertkit' ), ); return $buttons; } /** * Outputs a dropdown filter on a WP_List_Table filter section to permit * filtering by a Restrict Content Form, Tag or Product. * * @since 2.1.0 * * @param string $post_type Post Type. */ public function output_wp_list_table_filters( $post_type ) { // Don't output filters if we're not viewing a Post Type that supports Restricted Content. if ( ! in_array( $post_type, convertkit_get_supported_post_types(), true ) ) { return; } // Don't output filters if API credentials have not been defined in the Plugin's settings. $settings = new ConvertKit_Settings(); if ( ! $settings->has_access_and_refresh_token() ) { return; } // Initialize Forms, Products and Tags resource classes. $this->forms = new ConvertKit_Resource_Forms(); $this->products = new ConvertKit_Resource_Products(); $this->tags = new ConvertKit_Resource_Tags(); // Don't display filter if no Tags and no Products exist. if ( ! $this->products->exist() && ! $this->tags->exist() ) { return; } // Output filter. include_once CONVERTKIT_PLUGIN_PATH . '/views/backend/post/wp-list-table-filter.php'; } /** * Appends the 'Kit Member Content' text to a Page's Title in the WP_List_Table, * if the given Page has a Restrict Content setting. * * @param string[] $post_states An array of post display states. * @param WP_Post $post The current post object. * @return string[] An array of post display states */ public function maybe_display_restrict_content_post_state( $post_states, $post ) { // Bail if we're not on a WP_List_Table screen for a supported Post Type. if ( ! $this->is_wp_list_table_request_for_supported_post_type() ) { return $post_states; } // Fetch Post's settings. $convertkit_post = new ConvertKit_Post( $post->ID ); // Return post states, unedited, if Restrict Content isn't enabled on this Post. if ( ! $convertkit_post->restrict_content_enabled() ) { return $post_states; } // Add Post State. $post_states['convertkit_restrict_content'] = esc_html__( 'Kit Member Content', 'convertkit' ); // Return. return $post_states; } /** * Determines if the current request is for a WP_List_Table, and if so that * the Post Type we're viewing supports Restrict Content functionality. * * @since 2.1.0 * * @return bool Is WP_List_Table request for a supported Post Type. */ private function is_wp_list_table_request_for_supported_post_type() { // Bail if we're not on an edit.php screen. if ( convertkit_get_current_screen( 'base' ) !== 'edit' ) { return false; } // Return whether Post Type is supported for Restrict Content functionality. return in_array( convertkit_get_current_screen( 'post_type' ), convertkit_get_supported_post_types(), true ); } }