settings = $this->get_defaults(); } else { $this->settings = array_merge( $this->get_defaults(), $settings ); } } /** * Returns Plugin settings. * * @since 1.9.6 * * @return array */ public function get() { return $this->settings; } /** * Returns the API Key Plugin setting. * * @since 1.9.6 * * @return string */ public function get_api_key() { // Return API Key from constant, if defined. if ( defined( 'CONVERTKIT_API_KEY' ) ) { return CONVERTKIT_API_KEY; } // Return API Key from settings. return $this->settings['api_key']; } /** * Returns whether the API Key has been set in the Plugin settings. * * @since 1.9.6 * * @return bool */ public function has_api_key() { return ( ! empty( $this->get_api_key() ) ? true : false ); } /** * Returns whether the API Key is stored as a constant in the wp-config.php file. * * @since 1.9.6 * * @return bool */ public function is_api_key_a_constant() { return defined( 'CONVERTKIT_API_KEY' ); } /** * Returns the API Secret Plugin setting. * * @since 1.9.6 * * @return string */ public function get_api_secret() { // Return API Secret from constant, if defined. if ( defined( 'CONVERTKIT_API_SECRET' ) ) { return CONVERTKIT_API_SECRET; } // Return API Secret from settings. return $this->settings['api_secret']; } /** * Returns whether the API Secret has been set in the Plugin settings. * * @since 1.9.6 * * @return bool */ public function has_api_secret() { return ( ! empty( $this->get_api_secret() ) ? true : false ); } /** * Returns whether the API Secret is stored as a constant in the wp-config.php file. * * @since 1.9.6 * * @return bool */ public function is_api_secret_a_constant() { return defined( 'CONVERTKIT_API_SECRET' ); } /** * Returns whether the API Key and Secret have been set in the Plugin settings. * * @since 1.9.6 * * @return bool */ public function has_api_key_and_secret() { _deprecated_function( __FUNCTION__, '2.6.3', 'has_access_and_refresh_token()' ); // Use check for access and refresh token. return $this->has_access_and_refresh_token(); } /** * Returns the Access Token Plugin setting. * * @since 2.5.0 * * @return string */ public function get_access_token() { // Reload settings from options table, to ensure we have the latest tokens. $this->refresh_settings(); // Return Access Token from settings. return $this->settings['access_token']; } /** * Returns whether the Access Token has been set in the Plugin settings. * * @since 2.5.0 * * @return bool */ public function has_access_token() { return ( ! empty( $this->get_access_token() ) ? true : false ); } /** * Returns the Refresh Token Plugin setting. * * @since 2.5.0 * * @return string */ public function get_refresh_token() { // Reload settings from options table, to ensure we have the latest tokens. $this->refresh_settings(); // Return Refresh Token from settings. return $this->settings['refresh_token']; } /** * Returns whether the Refresh Token has been set in the Plugin settings. * * @since 2.5.0 * * @return bool */ public function has_refresh_token() { return ( ! empty( $this->get_refresh_token() ) ? true : false ); } /** * Returns whether to use Access and Refresh Tokens for API requests, * based on whether an Access Token and Refresh Token have been saved * in the Plugin settings. * * @since 2.5.0 * * @return bool */ public function has_access_and_refresh_token() { return $this->has_access_token() && $this->has_refresh_token(); } /** * Returns the Access Token expiry timestamp. * * @since 2.5.0 * * @return int */ public function get_token_expiry() { // Return Token Expiry from settings. return $this->settings['token_expires']; } /** * Returns the Default Form Plugin setting. * * @since 1.9.6 * * @param string $post_type Post Type. * @return string|int Default Form (default|form id) */ public function get_default_form( $post_type ) { // Return default if this Post Type doesn't exist as a setting. if ( ! array_key_exists( $post_type . '_form', $this->settings ) ) { return 'default'; } // Backward compat. where older Plugin versions would store API errors in the option value // with id = -2 and name = 'Error contacting API'. if ( is_array( $this->settings[ $post_type . '_form' ] ) ) { return 'default'; } return $this->settings[ $post_type . '_form' ]; } /** * Returns whether the Default Form has been set in the Plugin settings. * * @since 1.9.6 * * @param string $post_type Post Type. * @return bool Post Type has a Default Form setting specified in Plugin Settings. */ public function has_default_form( $post_type ) { return ( ! empty( $this->settings[ $post_type . '_form' ] ) ? true : false ); } /** * Returns the Default Form Position Plugin setting. * * @since 2.5.8 * * @param string $post_type Post Type. * @return string|int Default Form (default|form id) */ public function get_default_form_position( $post_type ) { // Return after_content if this Post Type's position doesn't exist as a setting. if ( ! array_key_exists( $post_type . '_form_position', $this->settings ) ) { return 'after_content'; } return $this->settings[ $post_type . '_form_position' ]; } /** * Returns the Default Form Position Element Plugin setting. * * @since 2.6.1 * * @param string $post_type Post Type. * @return string Element to insert form after */ public function get_default_form_position_element( $post_type ) { // Return after_content if this Post Type's position doesn't exist as a setting. if ( ! array_key_exists( $post_type . '_form_position_element', $this->settings ) ) { return 'p'; } return $this->settings[ $post_type . '_form_position_element' ]; } /** * Returns the Default Form Position Index Plugin setting. * * @since 2.6.1 * * @param string $post_type Post Type. * @return int Number of elements before inserting form */ public function get_default_form_position_element_index( $post_type ) { // Return 1 if this Post Type's position index doesn't exist as a setting. if ( ! array_key_exists( $post_type . '_form_position_element_index', $this->settings ) ) { return 1; } return (int) $this->settings[ $post_type . '_form_position_element_index' ]; } /** * Returns the Global non-inline Form Plugin setting. * * @since 2.3.3 * * @return array */ public function get_non_inline_form() { // Return blank array if no inline form is specified. if ( ! $this->has_non_inline_form() ) { return array(); } // 2.6.8 and earlier stored a single Form ID in a string. if ( is_string( $this->settings['non_inline_form'] ) ) { return array( (int) $this->settings['non_inline_form'] ); } // Cast values to integers and return. return array_map( 'intval', $this->settings['non_inline_form'] ); } /** * Returns whether the Global non-inline Form has been set in the Plugin settings. * * @since 2.3.3 * * @return bool Global non-inline Form setting specified in Plugin Settings. */ public function has_non_inline_form() { // 2.6.8 and earlier stored a single Form ID in a string. if ( is_string( $this->settings['non_inline_form'] ) ) { if ( ! empty( $this->settings['non_inline_form'] ) ) { return true; } return false; } return ( count( $this->settings['non_inline_form'] ) > 0 ? true : false ); } /** * Returns whether the Global non-inline Form setting should honor the Page / Post * None setting. * * @since 2.7.3 * * @return bool */ public function non_inline_form_honor_none_setting() { return ( $this->settings['non_inline_form_honor_none_setting'] === 'on' ? true : false ); } /** * Returns whether the Non-inline Form Limit per Session setting has been set in the Plugin settings. * * @since 3.0.0 * * @return bool */ public function non_inline_form_limit_per_session() { return ( $this->settings['non_inline_form_limit_per_session'] === 'on' ? true : false ); } /** * Returns the active spam protection provider Plugin setting. * * @since 3.3.7 * * @return string none|recaptcha|turnstile */ public function spam_protection_provider() { return $this->settings['spam_protection_provider']; } /** * Returns the reCAPTCHA Site Key Plugin setting. * * @since 3.0.0 * * @return string */ public function recaptcha_site_key() { return $this->settings['recaptcha_site_key']; } /** * Returns whether the reCAPTCHA Site Key has been set in the Plugin settings. * * @since 3.0.0 * * @return bool */ public function has_recaptcha_site_key() { return ! empty( $this->recaptcha_site_key() ); } /** * Returns the reCAPTCHA Secret Key Plugin setting. * * @since 3.0.0 * * @return string */ public function recaptcha_secret_key() { return $this->settings['recaptcha_secret_key']; } /** * Returns whether the reCAPTCHA Secret Key has been set in the Plugin settings. * * @since 3.0.0 * * @return bool */ public function has_recaptcha_secret_key() { return ! empty( $this->recaptcha_secret_key() ); } /** * Returns whether the reCAPTCH Site Key and Secret Key are defined * in the Plugin settings. * * @since 3.0.0 * * @return bool */ public function has_recaptcha_site_and_secret_keys() { return $this->has_recaptcha_site_key() && $this->has_recaptcha_secret_key(); } /** * Returns the reCAPTCHA minimum score Plugin setting. * * @since 3.0.0 * * @return float */ public function recaptcha_minimum_score() { return (float) $this->settings['recaptcha_minimum_score']; } /** * Returns the Cloudflare Turnstile Site Key Plugin setting. * * @since 3.3.7 * * @return string */ public function cloudflare_turnstile_site_key() { return $this->settings['cloudflare_turnstile_site_key']; } /** * Returns whether the Cloudflare Turnstile Site Key has been set in the Plugin settings. * * @since 3.3.7 * * @return bool */ public function has_cloudflare_turnstile_site_key() { return ! empty( $this->cloudflare_turnstile_site_key() ); } /** * Returns the Cloudflare Turnstile Secret Key Plugin setting. * * @since 3.3.7 * * @return string */ public function cloudflare_turnstile_secret_key() { return $this->settings['cloudflare_turnstile_secret_key']; } /** * Returns whether the Cloudflare Turnstile Secret Key has been set in the Plugin settings. * * @since 3.3.7 * * @return bool */ public function has_cloudflare_turnstile_secret_key() { return ! empty( $this->cloudflare_turnstile_secret_key() ); } /** * Returns whether the Cloudflare Turnstile Site Key and Secret Key are defined * in the Plugin settings. * * @since 3.3.7 * * @return bool */ public function has_cloudflare_turnstile_site_and_secret_keys() { return $this->has_cloudflare_turnstile_site_key() && $this->has_cloudflare_turnstile_secret_key(); } /** * Returns whether debugging is enabled in the Plugin settings. * * @since 1.9.6 * * @return bool */ public function debug_enabled() { return ( $this->settings['debug'] === 'on' ? true : false ); } /** * Returns whether scripts are disabled in the Plugin settings. * * @since 1.9.6 * * @return bool */ public function scripts_disabled() { return ( $this->settings['no_scripts'] === 'on' ? true : false ); } /** * Returns whether stylesheets are disabled in the Plugin settings. * * @since 1.9.6.9 * * @return bool */ public function css_disabled() { return ( $this->settings['no_css'] === 'on' ? true : false ); } /** * Returns whether the Add New Landing Page / Member Content button is disabled in the Plugin settings. * * @since 3.2.0 * * @return bool */ public function add_new_button_disabled() { return ( $this->settings['no_add_new_button'] === 'on' ? true : false ); } /** * Returns whether usage tracking is enabled in the Plugin settings. * * @since 3.0.4 * * @return bool */ public function usage_tracking() { return ( $this->settings['usage_tracking'] === 'on' ? true : false ); } /** * Returns this settings group's programmatic name. * * @since 3.4.0 * * @return string */ public function get_name() { return 'general'; } /** * Returns the title of this settings group. * * @since 3.4.0 * * @return string */ public function get_title() { return __( 'General Settings', 'convertkit' ); } /** * Returns the keys in this settings group that hold credentials or other * sensitive values. * * @since 3.4.0 * * @return string[] */ public function get_secret_keys() { return array( 'access_token', 'refresh_token', 'token_expires', 'api_key', 'api_secret', 'recaptcha_secret_key', ); } /** * Returns the JSON Schema describing this settings group, in the shape * stored by save() / returned by get(), excluding secret keys. * * @since 3.4.0 * * @return array */ public function get_schema() { $properties = array( 'non_inline_form' => array( 'type' => 'array', 'items' => array( 'type' => 'integer' ), 'description' => __( 'IDs of non-inline Forms to display site-wide.', 'convertkit' ), ), 'non_inline_form_honor_none_setting' => array( 'type' => 'string', 'enum' => array( '', 'on' ), 'description' => __( 'Whether the site-wide non-inline Form honors a per-Page / per-Post "None" Form setting.', 'convertkit' ), ), 'non_inline_form_limit_per_session' => array( 'type' => 'string', 'enum' => array( '', 'on' ), 'description' => __( 'Whether to limit non-inline Form display to once per session.', 'convertkit' ), ), 'recaptcha_site_key' => array( 'type' => 'string', 'description' => __( 'Google reCAPTCHA v3 site key.', 'convertkit' ), ), 'recaptcha_minimum_score' => array( 'type' => 'number', 'minimum' => 0, 'maximum' => 1, 'description' => __( 'Minimum Google reCAPTCHA v3 score (0.0 - 1.0) below which a request is treated as spam.', 'convertkit' ), ), 'debug' => array( 'type' => 'string', 'enum' => array( '', 'on' ), 'description' => __( 'Whether debug logging is enabled.', 'convertkit' ), ), 'no_scripts' => array( 'type' => 'string', 'enum' => array( '', 'on' ), 'description' => __( 'Whether the Plugin\'s frontend JavaScript is disabled.', 'convertkit' ), ), 'no_css' => array( 'type' => 'string', 'enum' => array( '', 'on' ), 'description' => __( 'Whether the Plugin\'s frontend CSS is disabled.', 'convertkit' ), ), 'no_add_new_button' => array( 'type' => 'string', 'enum' => array( '', 'on' ), 'description' => __( 'Whether the "Add New" button for Landing Pages / Member Content is hidden in the WordPress Admin.', 'convertkit' ), ), 'usage_tracking' => array( 'type' => 'string', 'enum' => array( '', 'on' ), 'description' => __( 'Whether anonymous usage tracking is enabled.', 'convertkit' ), ), ); // Per-post-type Default Form settings, mirroring get_defaults(). foreach ( convertkit_get_supported_post_types() as $post_type ) { $properties[ $post_type . '_form' ] = array( 'type' => 'integer', 'minimum' => -1, 'description' => sprintf( /* translators: Post type slug. */ __( 'Default Form ID to display on %s. `-1` = Plugin Default; `0` = None; positive integer = specific Kit Form ID.', 'convertkit' ), $post_type ), ); $properties[ $post_type . '_form_position' ] = array( 'type' => 'string', 'enum' => array( 'before_content', 'after_content', 'before_after_content', 'after_element' ), 'description' => sprintf( /* translators: Post type slug. */ __( 'Where the Default Form displays relative to the %s content.', 'convertkit' ), $post_type ), ); $properties[ $post_type . '_form_position_element' ] = array( 'type' => 'string', 'enum' => array( 'p', 'h2', 'h3', 'h4', 'h5', 'h6', 'img' ), 'description' => sprintf( /* translators: 1: Post type slug, 2: Post type slug. */ __( 'HTML element after which to display the Default Form on %1$s. Only used when `%2$s_form_position` is `after_element`.', 'convertkit' ), $post_type, $post_type ), ); $properties[ $post_type . '_form_position_element_index' ] = array( 'type' => 'integer', 'minimum' => 1, 'maximum' => 999, 'description' => sprintf( /* translators: 1: Post type slug, 2: Post type slug. */ __( 'Nth occurrence of the element after which to display the Default Form on %1$s. Only used when `%2$s_form_position` is `after_element`.', 'convertkit' ), $post_type, $post_type ), ); } return array( 'type' => 'object', 'additionalProperties' => false, 'properties' => $properties, ); } /** * The default settings, used when the ConvertKit Plugin Settings haven't been saved * e.g. on a new installation. * * @since 1.9.6 * * @return array */ public function get_defaults() { $defaults = array( // OAuth. 'access_token' => '', // string. 'refresh_token' => '', // string. 'token_expires' => '', // integer. // API Key. Retained if needed for backward compat. 'api_key' => '', // string. 'api_secret' => '', // string. // Site Wide. 'non_inline_form' => array(), // array. 'non_inline_form_honor_none_setting' => '', // blank|on. 'non_inline_form_limit_per_session' => '', // blank|on. // Spam Protection. 'spam_protection_provider' => 'recaptcha', // recaptcha|turnstile. // reCAPTCHA. 'recaptcha_site_key' => '', // string. 'recaptcha_secret_key' => '', // string. 'recaptcha_minimum_score' => 0.5, // float. // Cloudflare Turnstile. 'cloudflare_turnstile_site_key' => '', // string. 'cloudflare_turnstile_secret_key' => '', // string. // Advanced. 'debug' => '', // blank|on. 'no_scripts' => '', // blank|on. 'no_css' => '', // blank|on. 'no_add_new_button' => '', // blank|on. 'usage_tracking' => '', // blank|on. ); // Add Post Type Default Forms. foreach ( convertkit_get_supported_post_types() as $post_type ) { $defaults[ $post_type . '_form' ] = 0; // -1, 0 or Form ID. $defaults[ $post_type . '_form_position' ] = 'after_content'; // before_content,after_content,before_after_content,element. $defaults[ $post_type . '_form_position_element' ] = 'p'; $defaults[ $post_type . '_form_position_element_index' ] = 1; } /** * The default settings, used when the ConvertKit Plugin Settings haven't been saved * e.g. on a new installation. * * @since 1.9.6 * * @param array $defaults Default Settings. */ $defaults = apply_filters( 'convertkit_settings_get_defaults', $defaults ); return $defaults; } /** * Saves the new access token, refresh token and its expiry, and schedules * a WordPress Cron event to refresh the token on expiry. * * @since 2.8.3 * * @param array $result New Access Token, Refresh Token and Expiry. */ public function update_credentials( $result ) { // Remove any existing persistent notice. WP_ConvertKit()->get_class( 'admin_notices' )->delete( 'authorization_failed' ); $this->save( array( 'access_token' => $result['access_token'], 'refresh_token' => $result['refresh_token'], 'token_expires' => ( time() + $result['expires_in'] ), ) ); // Clear any existing scheduled WordPress Cron event. wp_clear_scheduled_hook( 'convertkit_refresh_token' ); // Schedule a WordPress Cron event to refresh the token on expiry. wp_schedule_single_event( ( time() + $result['expires_in'] ), 'convertkit_refresh_token' ); } /** * Deletes any existing access token, refresh token and its expiry from the Plugin settings, * and clears any existing scheduled WordPress Cron event to refresh the token on expiry. * * @since 2.5.0 */ public function delete_credentials() { $this->save( array( // OAuth. 'access_token' => '', 'refresh_token' => '', 'token_expires' => '', // API Key. 'api_key' => '', 'api_secret' => '', ) ); // Clear any existing scheduled WordPress Cron event. wp_clear_scheduled_hook( 'convertkit_refresh_token' ); } /** * Saves the given array of settings to the WordPress options table. * * @since 1.9.8.4 * * @param array $settings Settings. */ public function save( $settings ) { update_option( self::SETTINGS_NAME, array_merge( $this->get(), $settings ) ); // Reload settings in class, to reflect changes. $this->refresh_settings(); } /** * Reloads settings from the options table so this instance has the latest values. * * @since 3.1.1 */ private function refresh_settings() { $settings = get_option( self::SETTINGS_NAME ); if ( ! $settings ) { $this->settings = $this->get_defaults(); return; } $this->settings = array_merge( $this->get_defaults(), $settings ); } }