array( 'name' => __( 'Setup', 'convertkit' ), ), 'configuration' => array( 'name' => __( 'Configure', 'convertkit' ), 'next_button' => array( 'label' => __( 'Submit', 'convertkit' ), ), ), 'finish' => array( 'name' => __( 'Done', 'convertkit' ), ), ); } /** * Process posted data from the submitted form. * * @since 2.1.0 * * @param string $step Current step. */ public function process_form( $step ) { // Set and authorize the Post Type before processing data. $this->set_post_type(); if ( ! convertkit_user_can_create_published_post_type( $this->post_type ) ) { $this->error = __( 'You are not allowed to create and publish this type of content.', 'convertkit' ); return; } // Run security checks. if ( ! isset( $_REQUEST['_wpnonce'] ) ) { return; } if ( ! wp_verify_nonce( sanitize_key( $_REQUEST['_wpnonce'] ), $this->page_name ) ) { $this->error = __( 'Invalid nonce specified.', 'convertkit' ); return; } // Depending on the step, process the form data. switch ( $step ) { case 'finish': // Sanitize configuration. $configuration = array( 'type' => ( isset( $_POST['type'] ) ? sanitize_text_field( wp_unslash( $_POST['type'] ) ) : 'download' ), 'title' => ( isset( $_POST['title'] ) ? sanitize_text_field( wp_unslash( $_POST['title'] ) ) : '' ), 'description' => ( isset( $_POST['description'] ) ? sanitize_textarea_field( wp_unslash( $_POST['description'] ) ) : '' ), 'number_of_pages' => ( isset( $_POST['number_of_pages'] ) ? absint( $_POST['number_of_pages'] ) : 0 ), 'restrict_content' => ( isset( $_POST['restrict_content'] ) ? sanitize_text_field( wp_unslash( $_POST['restrict_content'] ) ) : '' ), 'post_type' => $this->post_type, ); // Depending on the type of content selected, create WordPress Page(s) now. switch ( $configuration['type'] ) { /** * Download * - Single page with a link to a downloadable product. */ case 'download': $result = $this->create_download( $configuration ); break; /** * Course */ case 'course': default: $result = $this->create_course( $configuration ); break; } // If here, an error occured as create_download() and create_course() perform a redirect on success. // Show an error message if Account Details could not be fetched e.g. API credentials supplied are invalid. // Decrement the step. $this->step = $this->get_step_key_by_number( $this->get_current_step_number() - 1 ); $this->error = $result->get_error_message(); return; } // phpcs:enable } /** * Load any data into class variables for the given setup wizard name and current step. * * @since 2.1.0 * * @param string $step Current step. */ public function load_screen_data( $step ) { // Show an error screen if API credentials have not been specified. // This shouldn't happen, because the 'Add New Member Content' button is only displayed // if valid credentials have been specified. $settings = new ConvertKit_Settings(); if ( ! $settings->has_access_and_refresh_token() ) { wp_die( esc_html__( 'Connect your ConvertKit account in the ConvertKit Plugin\'s settings to get started', 'convertkit' ) ); } // Set and authorize the Post Type. $this->set_post_type(); if ( ! convertkit_user_can_create_published_post_type( $this->post_type ) ) { wp_die( esc_html__( 'Sorry, you are not allowed to create and publish this type of content.', 'convertkit' ) ); } // Define Exit URL to take the user back to the WP_List_Table for the Post Type they were viewing. $this->exit_url = add_query_arg( array( 'post_type' => $this->post_type, ), admin_url( 'edit.php' ) ); // Load data depending on the current step. switch ( $step ) { case 'start': // Fetch Forms, Products and Tags. $this->forms = new ConvertKit_Resource_Forms( 'restrict_content_wizard' ); $this->products = new ConvertKit_Resource_Products( 'restrict_content_wizard' ); $this->tags = new ConvertKit_Resource_Tags( 'restrict_content_wizard' ); // Refresh Forms, Products and Tags resources, in case the user just created their first Form, Product or Tag // in ConvertKit. $result = $this->forms->refresh(); // Bail if an error occured. if ( is_wp_error( $result ) ) { // Change the next label and make it a link to reload the screen. unset( $this->steps['start']['next_button'] ); $this->current_url = add_query_arg( array( 'page' => $this->page_name, 'ck_post_type' => $this->post_type, 'step' => 'start', ), admin_url( 'options.php' ) ); return; } // Refresh Products. $result = $this->products->refresh(); // Bail if an error occured. if ( is_wp_error( $result ) ) { // Change the next label and make it a link to reload the screen. unset( $this->steps['start']['next_button'] ); $this->current_url = add_query_arg( array( 'page' => $this->page_name, 'ck_post_type' => $this->post_type, 'step' => 'start', ), admin_url( 'options.php' ) ); return; } // Refresh Tags. $result = $this->tags->refresh(); // Bail if an error occured. if ( is_wp_error( $result ) ) { // Change the next label and make it a link to reload the screen. unset( $this->steps['start']['next_button'] ); $this->current_url = add_query_arg( array( 'page' => $this->page_name, 'ck_post_type' => $this->post_type, 'step' => 'start', ), admin_url( 'options.php' ) ); return; } // If no Forms, Products and Tags exist in ConvertKit, change the next button label and make it a link to reload // the screen. if ( ! $this->forms->exist() && ! $this->products->exist() && ! $this->tags->exist() ) { unset( $this->steps['start']['next_button'] ); $this->current_url = add_query_arg( array( 'page' => $this->page_name, 'ck_post_type' => $this->post_type, 'step' => 'start', ), admin_url( 'options.php' ) ); } else { // Define Download and Course button links. $this->download_url = add_query_arg( array( 'type' => 'download', 'ck_post_type' => $this->post_type, ), $this->next_step_url ); $this->course_url = add_query_arg( array( 'type' => 'course', 'ck_post_type' => $this->post_type, ), $this->next_step_url ); } break; case 'configuration': // Define Member Content Type. if ( filter_has_var( INPUT_GET, 'type' ) ) { $this->type = filter_input( INPUT_GET, 'type', FILTER_SANITIZE_FULL_SPECIAL_CHARS ); } else { $this->type = 'download'; } // Define Label for Title. switch ( $this->type ) { case 'download': $this->type_label = __( 'Download', 'convertkit' ); break; case 'course': $this->type_label = __( 'Course', 'convertkit' ); break; } // Fetch Forms, Products and Tags. $this->forms = new ConvertKit_Resource_Forms( 'restrict_content_wizard' ); $this->products = new ConvertKit_Resource_Products( 'restrict_content_wizard' ); $this->tags = new ConvertKit_Resource_Tags( 'restrict_content_wizard' ); break; } } /** * Creates a single WordPress Page for a downloadable product, restricted by * a ConvertKit Form, Tag or Product, based on the supplied configuration. * * @since 2.1.0 * * @param array $configuration Configuration. * @return WP_Error WP_Error or Page ID */ private function create_download( $configuration ) { // Create Page. $page_id = $this->create_page( $configuration['title'], $configuration['description'], $configuration['post_type'], __( 'The downloadable member-only content goes here.', 'convertkit' ), $configuration['restrict_content'] ); // Bail if an error occured. if ( is_wp_error( $page_id ) ) { return $page_id; } // Redirect to the Pages WP_List_Table screen, showing the generated page. wp_safe_redirect( add_query_arg( array( 's' => rawurlencode( $configuration['title'] ), 'post_type' => $configuration['post_type'], ), 'edit.php' ) ); die(); } /** * Creates multiple WordPress Pages for a course, restricted by * a ConvertKit Form, Tag or Product, based on the supplied configuration. * * @since 2.1.0 * * @param array $configuration Configuration. * @return WP_Error WP_Error on error, wp_safe_redirect() on success. */ private function create_course( $configuration ) { // If here, we need to generate multiple pages. // Build top level Page, which pages will be children of. $parent_page_id = $this->create_page( $configuration['title'], $configuration['description'], $configuration['post_type'] ); // Bail if an error occured. if ( is_wp_error( $parent_page_id ) ) { return $parent_page_id; } // Build child Pages. $page_ids = array(); for ( $i = 1; $i <= $configuration['number_of_pages']; $i++ ) { $result = $this->create_page( sprintf( '%s: %s/%s', $configuration['title'], $i, $configuration['number_of_pages'] ), // e.g. Title: 1/10. sprintf( '%s %s', esc_html__( 'Some introductory text about lesson', 'convertkit' ), $i ), $configuration['post_type'], sprintf( '%s %s %s', esc_html__( 'Lesson', 'convertkit' ), $i, esc_html__( 'member-only content goes here.', 'convertkit' ) ), $configuration['restrict_content'], $i, $configuration['number_of_pages'], $parent_page_id ); // Bail if an error occured. if ( is_wp_error( $result ) ) { return $result; } // Add Page ID to array. $page_ids[] = $result; } // Add a link from the parent page to the first child page. $this->add_link_from_parent_to_child_page( $parent_page_id, $page_ids[0] ); // Redirect to the Pages WP_List_Table screen, showing the generated pages. wp_safe_redirect( add_query_arg( array( 's' => rawurlencode( $configuration['title'] ), 'post_type' => $configuration['post_type'], ), 'edit.php' ) ); die(); } /** * Creates a WordPress Page for the given title, restricted to the given restrict content setting. * * @since 2.1.0 * * @param string $title Page Title. * @param string $content Non-restricted Content. * @param string $post_type Post Type. * @param bool|string $restricted_content Restricted Content. * @param bool|string $restrict_content_setting ConvertKit Form, Tag or Product to restrict content to. * @param int $page_number Page Number. * @param int $total_pages Total Pages that will be created. * @param bool|int $parent_page_id Parent Page ID (false if none). * @return WP_Error|int Error or Page ID */ private function create_page( $title, $content, $post_type = 'page', $restricted_content = false, $restrict_content_setting = false, $page_number = 0, $total_pages = 0, $parent_page_id = false ) { // Build content. $content = $this->element_paragraph( $content ); // If restricted content is defined, append it to the post content using a more block. if ( $restricted_content && $restrict_content_setting ) { $content .= $this->element_more_tag(); $content .= $this->element_paragraph( $restricted_content ); } // Define previous / next links, depending on the page number and total pages. $content .= $this->element_navigation( $page_number, $total_pages ); // Build arguments to create Page. $args = array( 'post_type' => $post_type, 'post_status' => 'publish', 'post_author' => get_current_user_id(), 'post_title' => $title, 'post_content' => $content, 'menu_order' => $page_number, ); // If a parent page is specified, apply it to the arguments. if ( $parent_page_id !== false ) { $args['post_parent'] = $parent_page_id; } // Create Page. $page_id = wp_insert_post( $args, true ); // Bail if an error occured. if ( is_wp_error( $page_id ) ) { return $page_id; } // Define Page's settings, ensuring no default Form displays. // If a restrict content setting was supplied, it's set to the Page now. WP_ConvertKit()->get_class( 'admin_post' )->save_post_settings( $page_id, array( 'form' => '0', // Don't display a Form. 'restrict_content' => ( $restrict_content_setting !== false ? $restrict_content_setting : '0' ), ) ); // Return. return $page_id; } /** * Returns a paragraph for the given text, depending on if the Classic Editor or Block Editor is used. * * @since 2.1.0 * * @param string $text Text. * @return string Text */ private function element_paragraph( $text ) { return '

' . $text . '

'; } /** * Returns the more tag, depending on if the Classic Editor or Block Editor is used. * * @since 2.1.0 * * @return string More Tag */ private function element_more_tag() { return ''; } /** * Returns previous/next links, depending on if the Classic Editor or Block Editor is used. * * @since 2.1.0 * * @param int $page_number Page Number. * @param int $total_pages Total Pages. * @return string Previous / Next Links */ private function element_navigation( $page_number, $total_pages ) { // Assume no previous or next link required. $previous_link = ''; $next_link = ''; // If the page number is greater than zero, a previous link is required. if ( $page_number > 0 ) { $previous_link = ''; } // If the page number is less than the total pages, a next link is required. if ( $page_number < $total_pages ) { $next_link = ''; } // Return a blank string if no previous or next links required. if ( empty( $previous_link ) && empty( $next_link ) ) { return ''; } // Return links. return '
' . $previous_link . '
' . $next_link . '
'; } /** * Adds a link from the parent page to the child page. * * @since 2.1.0 * * @param int $parent_page_id Parent Page ID. * @param int $child_page_id Child Page ID. */ private function add_link_from_parent_to_child_page( $parent_page_id, $child_page_id ) { // Define button block linking to first child page. $button_block = '
' . __( 'Start Course', 'convertkit' ) . '
'; // Fetch parent page's content. $parent_page = get_post( $parent_page_id ); // Update parent page's content to include a link to the first child page. return wp_update_post( array( 'ID' => $parent_page_id, 'post_content' => $parent_page->post_content .= $button_block, ), true ); } }