Kit > General. * * @package ConvertKit * @author ConvertKit */ class ConvertKit_Admin_Section_General extends ConvertKit_Admin_Section_Base { /** * Holds the API instance. * * @since 1.9.6 * * @var ConvertKit_API_V4 */ private $api; /** * Holds the ConvertKit Account Name. * * @since 1.9.6 * * @var bool|WP_Error|array */ private $account = false; /** * Holds the ConvertKit Forms Resource. * * @since 1.9.6 * * @var bool|ConvertKit_Resource_Forms */ private $forms = false; /** * Constructor. */ public function __construct() { // Define the class that reads/writes settings. $this->settings = new ConvertKit_Settings(); // Define the settings key. $this->settings_key = $this->settings::SETTINGS_NAME; // Define the programmatic name, Title and Tab Text. $this->name = 'general'; $this->title = __( 'General Settings', 'convertkit' ); $this->tab_text = __( 'General', 'convertkit' ); // Define settings sections. $this->settings_sections = array( 'general' => array( 'title' => $this->title, 'callback' => array( $this, 'print_section_info' ), 'wrap' => true, ), 'site-wide' => array( 'title' => __( 'Site Wide', 'convertkit' ), 'callback' => array( $this, 'print_section_info_site_wide' ), 'wrap' => true, ), 'advanced' => array( 'title' => __( 'Advanced', 'convertkit' ), 'callback' => array( $this, 'print_section_info_advanced' ), 'wrap' => true, ), ); // Register and maybe output notices for this settings screen, and the Intercom messenger. if ( $this->on_settings_screen( $this->name ) ) { add_filter( 'convertkit_settings_base_register_notices', array( $this, 'register_notices' ) ); add_action( 'convertkit_settings_base_render_before', array( $this, 'maybe_output_notices' ) ); add_action( 'admin_footer', array( $this, 'output_intercom' ) ); } // Enqueue scripts and CSS. add_action( 'convertkit_admin_settings_enqueue_scripts', array( $this, 'enqueue_scripts' ) ); add_action( 'convertkit_admin_settings_enqueue_styles', array( $this, 'enqueue_styles' ) ); parent::__construct(); $this->check_credentials(); $this->maybe_disconnect(); } /** * Registers success and error notices for the General screen, to be displayed * depending on the action. * * @since 2.5.1 * * @param array $notices Regsitered success and error notices. * @return array */ public function register_notices( $notices ) { return array_merge( $notices, array( 'oauth2_success' => __( 'Successfully authorized with Kit.', 'convertkit' ), ) ); } /** * Test the access token, if it exists. * If the access token has been revoked or is invalid, remove it from the settings now. * * @since 2.5.0 */ private function check_credentials() { // Bail if we're not on the settings screen. if ( ! $this->on_settings_screen( $this->name ) ) { return; } // Bail if no access and refresh token exist. if ( ! $this->settings->has_access_and_refresh_token() ) { return; } // Initialize the API. $this->api = new ConvertKit_API_V4( CONVERTKIT_OAUTH_CLIENT_ID, CONVERTKIT_OAUTH_CLIENT_REDIRECT_URI, $this->settings->get_access_token(), $this->settings->get_refresh_token(), $this->settings->debug_enabled(), 'settings' ); // Get Account Details, which we'll use in account_name_callback(), but also lets us test // whether the API credentials are valid. $this->account = $this->api->get_account(); // If the request succeeded, no need to perform further actions. if ( ! is_wp_error( $this->account ) ) { // Remove any existing persistent notice. WP_ConvertKit()->get_class( 'admin_notices' )->delete( 'authorization_failed' ); return; } // Depending on the error code, maybe persist a notice in the WordPress Administration until the user // fixes the problem. switch ( $this->account->get_error_data( $this->account->get_error_code() ) ) { case 401: // Access token either expired or was revoked in ConvertKit. // Remove from settings. $this->settings->delete_credentials(); // Display a site wide notice. WP_ConvertKit()->get_class( 'admin_notices' )->add( 'authorization_failed' ); // Redirect to General screen, which will now show the ConvertKit_Admin_Section_OAuth screen, because // the Plugin has no access token. wp_safe_redirect( add_query_arg( array( 'page' => $this->settings_key, ), 'options-general.php' ) ); exit(); } // Output a non-401 error now. $this->output_error( $this->account->get_error_message() ); } /** * Deletes the OAuth Access Token, Refresh Token and Expiry from the Plugin's settings, if the user * clicked the Disconnect button. * * @since 2.5.0 */ private function maybe_disconnect() { // Bail if we're not on the settings screen. if ( ! $this->on_settings_screen( $this->name ) ) { return; } // Bail if nonce verification fails. if ( ! isset( $_REQUEST['_convertkit_settings_oauth_disconnect'] ) ) { return; } if ( ! wp_verify_nonce( sanitize_key( $_REQUEST['_convertkit_settings_oauth_disconnect'] ), 'convertkit-oauth-disconnect' ) ) { return; } // Delete Access Token. $settings = new ConvertKit_Settings(); $settings->delete_credentials(); // Delete cached resources. $creator_network = new ConvertKit_Resource_Creator_Network_Recommendations(); $forms = new ConvertKit_Resource_Forms(); $landing_pages = new ConvertKit_Resource_Landing_Pages(); $posts = new ConvertKit_Resource_Posts(); $products = new ConvertKit_Resource_Products(); $tags = new ConvertKit_Resource_Tags(); $creator_network->delete(); $forms->delete(); $landing_pages->delete(); $posts->delete(); $products->delete(); $tags->delete(); // Redirect to General screen, which will now show the ConvertKit_Settings_OAuth screen, because // the Plugin has no access token. wp_safe_redirect( add_query_arg( array( 'page' => $this->settings_key, ), 'options-general.php' ) ); exit(); } /** * Enqueues scripts for the Settings > General screen. * * @since 2.2.4 * * @param string $section Settings section / tab (general|tools|restrict-content). */ public function enqueue_scripts( $section ) { // Bail if we're not on the general section. if ( $section !== $this->name ) { return; } // Enqueue Select2 JS. convertkit_select2_enqueue_scripts(); // Enqueue JS. wp_enqueue_script( 'convertkit-admin-preview-output', CONVERTKIT_PLUGIN_URL . 'resources/backend/js/preview-output.js', array( 'jquery' ), CONVERTKIT_PLUGIN_VERSION, true ); wp_enqueue_script( 'convertkit-admin-settings-conditional-display', CONVERTKIT_PLUGIN_URL . 'resources/backend/js/settings-conditional-display.js', array( 'jquery' ), CONVERTKIT_PLUGIN_VERSION, true ); } /** * Enqueues styles for the Settings > General screen. * * @since 2.2.4 * * @param string $section Settings section / tab (general|tools|restrict-content). */ public function enqueue_styles( $section ) { // Bail if we're not on the general section. if ( $section !== $this->name ) { return; } // Enqueue Select2 CSS. convertkit_select2_enqueue_styles(); } /** * Registers settings fields for this section. */ public function register_fields() { // Initialize resource classes. $this->maybe_initialize_and_refresh_resources(); add_settings_field( 'account_name', __( 'Account Name', 'convertkit' ), array( $this, 'account_name_callback' ), $this->settings_key, $this->name ); // Initialize resource classes and perform a refresh if this hasn't yet been done. foreach ( convertkit_get_supported_post_types() as $supported_post_type ) { // Get Post Type's Label. $post_type = get_post_type_object( $supported_post_type ); // Skip if the Post Type doesn't exist. if ( ! $post_type ) { continue; } // Add Settings Fields. add_settings_field( $supported_post_type . '_form', sprintf( /* translators: Post Type Name, plural */ __( 'Default Form (%s)', 'convertkit' ), $post_type->label ), array( $this, 'default_form_callback' ), $this->settings_key, $this->name, array( 'label_for' => '_wp_convertkit_settings_' . $supported_post_type . '_form', 'post_type' => $supported_post_type, 'post_type_object' => $post_type, ) ); if ( $this->forms->exist() ) { add_settings_field( $supported_post_type . '_form_position', sprintf( /* translators: Post Type Name, plural */ __( 'Form Position (%s)', 'convertkit' ), $post_type->label ), array( $this, 'default_form_position_callback' ), $this->settings_key, $this->name, array( 'label_for' => '_wp_convertkit_settings_' . $supported_post_type . '_form_position', 'post_type' => $supported_post_type, 'post_type_object' => $post_type, ) ); add_settings_field( $supported_post_type . '_form_position_element', '', array( $this, 'default_form_position_element_callback' ), $this->settings_key, $this->name, array( 'label_for' => '_wp_convertkit_settings_' . $supported_post_type . '_form_position_element', 'post_type' => $supported_post_type, 'post_type_object' => $post_type, ) ); } } // Site Wide. add_settings_field( 'non_inline_form', __( 'Default Forms (Site Wide)', 'convertkit' ), array( $this, 'non_inline_form_callback' ), $this->settings_key, $this->name . '-site-wide', array( 'label_for' => 'non_inline_form', ) ); add_settings_field( 'non_inline_form_honor_none_setting', __( 'Behavior', 'convertkit' ), array( $this, 'non_inline_form_honor_none_setting_callback' ), $this->settings_key, $this->name . '-site-wide', array( 'label_for' => 'non_inline_form_honor_none_setting', ) ); // Advanced. add_settings_field( 'debug', __( 'Debug', 'convertkit' ), array( $this, 'debug_callback' ), $this->settings_key, $this->name . '-advanced', array( 'label_for' => 'debug', ) ); add_settings_field( 'no_scripts', __( 'Disable JavaScript', 'convertkit' ), array( $this, 'no_scripts_callback' ), $this->settings_key, $this->name . '-advanced', array( 'label_for' => 'no_scripts', ) ); add_settings_field( 'no_css', __( 'Disable CSS', 'convertkit' ), array( $this, 'no_css_callback' ), $this->settings_key, $this->name . '-advanced', array( 'label_for' => 'no_css', ) ); } /** * Prints help info for this section */ public function print_section_info() { ?>

tags */ esc_html__( 'The default form can be inserted into the middle of post or page content by using either the %s shortcode or block.', 'convertkit' ), '[convertkit]' ); ?>

%s

', isset( $this->account['account']['name'] ) ? esc_attr( $this->account['account']['name'] ) : esc_html__( '(Not specified)', 'convertkit' ) ); // Display an option to disconnect. $html .= sprintf( '

%2$s

', esc_url( add_query_arg( array( 'page' => '_wp_convertkit_settings', '_convertkit_settings_oauth_disconnect' => wp_create_nonce( 'convertkit-oauth-disconnect' ), ), 'options-general.php' ) ), esc_html__( 'Disconnect', 'convertkit' ) ); // Output has already been run through escaping functions above. echo $html; // phpcs:ignore WordPress.Security.EscapeOutput } /** * Initialize resource classes and perform a and refresh of resources, * if initialization has not yet taken place. * * @since 2.5.9 */ public function maybe_initialize_and_refresh_resources() { // If the Forms resource class is initialized, this has already been done. if ( $this->forms !== false ) { return; } // Initialize forms resource class. $this->forms = new ConvertKit_Resource_Forms( 'settings' ); // Don't refresh resources if we're not on the settings screen, as // it's a resource intense process that can take several seconds. // We don't want to block other parts of the admin UI. if ( ! $this->on_settings_screen( $this->name ) ) { return; } // Refresh Forms. $this->forms->refresh(); // Also refresh Landing Pages, Tags and Posts. Whilst not displayed in the Plugin Settings, this ensures up to date // lists are stored for when editing e.g. Pages. $landing_pages = new ConvertKit_Resource_Landing_Pages( 'settings' ); $landing_pages->refresh(); remove_all_actions( 'convertkit_resource_refreshed_posts' ); $posts = new ConvertKit_Resource_Posts( 'settings' ); $posts->refresh(); $products = new ConvertKit_Resource_Products( 'settings' ); $products->refresh(); $sequences = new ConvertKit_Resource_Sequences( 'settings' ); $sequences->refresh(); $tags = new ConvertKit_Resource_Tags( 'settings' ); $tags->refresh(); } /** * Renders the input for the Default Form setting for the given Post Type. * * @since 1.9.6 * * @param array $args Field arguments. */ public function default_form_callback( $args ) { // Bail if no Forms exist. if ( ! $this->forms->exist() ) { esc_html_e( 'No Forms exist in Kit.', 'convertkit' ); echo '
' . esc_html__( 'Click here to create your first form', 'convertkit' ) . ''; return; } // Build description with preview link. $description = false; $preview_url = WP_ConvertKit()->get_class( 'preview_output' )->get_preview_form_url( $args['post_type'] ); if ( $preview_url ) { // Include a preview link in the description. $description = sprintf( '%s %s %s', sprintf( /* translators: Post Type name, plural */ esc_html__( 'Select a form above to automatically output below all %s.', 'convertkit' ), $args['post_type_object']->label ), '' . esc_html__( 'Click here', 'convertkit' ) . '', esc_html__( 'to preview how this will display.', 'convertkit' ) ); } else { // Just output the field's description. $description = sprintf( /* translators: Post Type name, plural */ esc_html__( 'Select a form above to automatically output below all %s.', 'convertkit' ), $args['post_type_object']->label ); } // Build field. $select_field = $this->forms->get_select_field_all( $this->settings_key . '[' . $args['post_type'] . '_form]', $this->settings_key . '_' . $args['post_type'] . '_form', array( 'convertkit-select2', 'convertkit-preview-output-link', ), $this->settings->get_default_form( $args['post_type'] ), array( 'default' => esc_html__( 'None', 'convertkit' ), ), array( 'data-target' => '#convertkit-preview-form-' . esc_attr( $args['post_type'] ), 'data-link' => esc_attr( $preview_url ) . '&convertkit_form_id=', ), $description ); // Output field. echo '
' . $select_field . '
'; // phpcs:ignore WordPress.Security.EscapeOutput } /** * Renders the input for the Default Form Position setting for the given Post Type. * * @since 2.5.8 * * @param array $args Field arguments. */ public function default_form_position_callback( $args ) { echo $this->get_select_field( // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped $args['post_type'] . '_form_position', esc_attr( $this->settings->get_default_form_position( $args['post_type'] ) ), array( 'before_content' => sprintf( /* translators: Post type singular name */ esc_attr__( 'Before %s content', 'convertkit' ), esc_attr( $args['post_type_object']->labels->singular_name ) ), 'after_content' => sprintf( /* translators: Post type singular name */ esc_attr__( 'After %s content', 'convertkit' ), esc_attr( $args['post_type_object']->labels->singular_name ) ), 'before_after_content' => sprintf( /* translators: Post type singular name */ esc_attr__( 'Before and after %s content', 'convertkit' ), esc_attr( $args['post_type_object']->labels->singular_name ) ), 'after_element' => esc_html__( 'After element', 'convertkit' ), ), sprintf( /* translators: Post Type name, plural */ esc_html__( 'Where forms should display relative to the %s content', 'convertkit' ), esc_html( $args['post_type_object']->labels->singular_name ) ), array( 'convertkit-conditional-display' ), array( 'data-conditional-value' => 'after_element', 'data-conditional-element' => esc_attr( $args['post_type'] ) . '_form_position_element_index', ) ); } /** * Renders the input for the Default Form Position Index setting for the given Post Type. * * @since 2.6.1 * * @param array $args Field arguments. */ public function default_form_position_element_callback( $args ) { echo $this->get_number_field( // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped $args['post_type'] . '_form_position_element_index', esc_attr( (string) $this->settings->get_default_form_position_element_index( $args['post_type'] ) ), 1, 999, 1, false, array( 'after_element' ) ); echo $this->get_select_field( // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped $args['post_type'] . '_form_position_element', esc_attr( $this->settings->get_default_form_position_element( $args['post_type'] ) ), array( 'p' => esc_html__( 'Paragraphs', 'convertkit' ), 'h2' => esc_html__( 'Headings

', 'convertkit' ), 'h3' => esc_html__( 'Headings

', 'convertkit' ), 'h4' => esc_html__( 'Headings

', 'convertkit' ), 'h5' => esc_html__( 'Headings

', 'convertkit' ), 'h6' => esc_html__( 'Headings
', 'convertkit' ), 'img' => esc_html__( 'Images', 'convertkit' ), ), esc_html__( 'The number of elements before outputting the form.', 'convertkit' ), array( 'after_element' ) ); } /** * Renders the input for the Non-inline Form setting. * * @since 2.2.3 * * @param array $args Field arguments. */ public function non_inline_form_callback( $args ) { // Bail if no non-inline Forms exist. if ( ! $this->forms->non_inline_exist() ) { esc_html_e( 'No non-inline Forms exist in Kit.', 'convertkit' ); echo '
' . esc_html__( 'Click here to create your first modal, slide in or sticky bar form', 'convertkit' ) . ''; return; } // Build description with preview link. $preview_url = WP_ConvertKit()->get_class( 'preview_output' )->get_preview_form_home_url(); $description = sprintf( '%s %s %s', esc_html__( 'Automatically display one or more modal, slide-in, or sticky bar forms across your site. This setting is overridden if a default non-inline form is set above, a specific non-inline form or "None" option is chosen for a post/page, or a non-inline form is specified in a block/shortcode.', 'convertkit' ), '' . esc_html__( 'Click here', 'convertkit' ) . '', esc_html__( 'to preview how this will display.', 'convertkit' ) ); // Build field. $select_field = $this->forms->get_select_field_non_inline( $this->settings_key . '[non_inline_form]', $this->settings_key . '_non_inline_form', array( 'convertkit-select2', 'convertkit-preview-output-link', ), $this->settings->get_non_inline_form(), false, array( 'data-target' => '#convertkit-preview-non-inline-form', 'data-link' => esc_attr( $preview_url ) . '&convertkit_form_id=', ), $description ); // Output field. echo '
' . $select_field . '
'; // phpcs:ignore WordPress.Security.EscapeOutput } /** * Renders the input for the Non-inline Form override setting. * * @since 2.7.3 */ public function non_inline_form_honor_none_setting_callback() { // Output field. echo $this->get_checkbox_field( // phpcs:ignore WordPress.Security.EscapeOutput 'non_inline_form_honor_none_setting', 'on', $this->settings->non_inline_form_honor_none_setting(), // phpcs:ignore WordPress.Security.EscapeOutput esc_html__( 'If checked, do not display the site wide form(s) above on Pages / Posts that have their Kit Form setting = None.', 'convertkit' ) ); } /** * Renders the input for the Debug setting. * * @since 1.9.6 */ public function debug_callback() { // Output field. echo $this->get_checkbox_field( // phpcs:ignore WordPress.Security.EscapeOutput 'debug', 'on', $this->settings->debug_enabled(), // phpcs:ignore WordPress.Security.EscapeOutput esc_html__( 'Log requests to file and output browser console messages.', 'convertkit' ), esc_html__( 'You can ignore this unless you\'re working with our support team to resolve an issue. Decheck this option to improve performance.', 'convertkit' ) ); } /** * Renders the input for the Disable Javascript setting. * * @since 1.9.6 */ public function no_scripts_callback() { // Output field. echo $this->get_checkbox_field( // phpcs:ignore WordPress.Security.EscapeOutput 'no_scripts', 'on', $this->settings->scripts_disabled(), // phpcs:ignore WordPress.Security.EscapeOutput esc_html__( 'Prevent plugin from loading JavaScript files. This will disable the custom content and tagging features of the plugin. Does not apply to landing pages. Use with caution!', 'convertkit' ) ); } /** * Renders the input for the Disable CSS setting. * * @since 1.9.6.9 */ public function no_css_callback() { // Output field. echo $this->get_checkbox_field( // phpcs:ignore WordPress.Security.EscapeOutput 'no_css', 'on', $this->settings->css_disabled(), // phpcs:ignore WordPress.Security.EscapeOutput esc_html__( 'Prevents loading plugin CSS files. This will disable styling on broadcasts, form trigger buttons, product buttons and member\'s content. Use with caution!', 'convertkit' ), array( sprintf( '%s %s', esc_html__( 'To customize forms and their styling, use the', 'convertkit' ), esc_url( convertkit_get_form_editor_url() ), esc_html__( 'Kit form editor', 'convertkit' ) ), sprintf( '%s Contact Form 7, Gravity Forms %s WPForms %s', esc_html__( 'For developers who require custom form designs through use of CSS, consider using the', 'convertkit' ), esc_html__( 'or', 'convertkit' ), esc_html__( 'integrations.', 'convertkit' ) ), ) ); } /** * Sanitizes the settings prior to being saved. * * @since 2.4.3 * * @param null|array $settings Submitted Settings Fields. * @return array Sanitized Settings with Defaults */ public function sanitize_settings( $settings ) { // If no Access Token, Refresh Token or Token Expiry keys were specified in the settings // prior to save, don't overwrite them with the blank setting from get_defaults(). // This ensures we only blank these values if we explicitly do so via $settings, // as they won't be included in the Settings screen for security. if ( ! array_key_exists( 'disconnect', $_REQUEST ) ) { // phpcs:ignore WordPress.Security.NonceVerification // If settings are null, no checkboxes were ticked and no other form elements // were submitted i.e. the Kit account has no forms. if ( is_null( $settings ) ) { $settings = array(); } if ( ! array_key_exists( 'access_token', $settings ) ) { $settings['access_token'] = $this->settings->get_access_token(); } if ( ! array_key_exists( 'refresh_token', $settings ) ) { $settings['refresh_token'] = $this->settings->get_refresh_token(); } if ( ! array_key_exists( 'token_expires', $settings ) ) { $settings['token_expires'] = $this->settings->get_token_expiry(); } } // Call parent class to merge settings with defaults. $settings = parent::sanitize_settings( $settings ); // If a Form or Landing Page was specified that isn't the default, // request a review. // Since switching to OAuth means the settings screen will only display // settings if the access token is valid, the Default Forms options will // always be submitted. Previously, if no API Key/Secret was specified, // no Default Forms options would render. // This can safely be called multiple times, as the review request // class will ensure once a review request is dismissed by the user, // it is never displayed again. if ( ( isset( $settings['page_form'] ) && $settings['page_form'] !== 'default' ) || ( isset( $settings['post_form'] ) && $settings['post_form'] !== 'default' ) ) { WP_ConvertKit()->get_class( 'review_request' )->request_review(); } // Return settings to be saved. return $settings; } }