diff --git a/composer.json b/composer.json index c7080d8..8e6bb51 100644 --- a/composer.json +++ b/composer.json @@ -4,7 +4,7 @@ "type": "project", "license": "GPLv3", "require": { - "convertkit/convertkit-wordpress-libraries": "2.1.2" + "convertkit/convertkit-wordpress-libraries": "dev-add-invalid-access-token-to-hook" }, "require-dev": { "php-webdriver/webdriver": "^1.0", diff --git a/includes/class-integrate-convertkit-wpforms-admin-notices.php b/includes/class-integrate-convertkit-wpforms-admin-notices.php new file mode 100644 index 0000000..fcbe274 --- /dev/null +++ b/includes/class-integrate-convertkit-wpforms-admin-notices.php @@ -0,0 +1,223 @@ +key_prefix ); + if ( ! $notices ) { + return; + } + + // Output notices. + foreach ( $notices as $notice ) { + switch ( $notice ) { + case 'authorization_failed': + $output = sprintf( + '%s %s', + esc_html__( 'Kit for WPForms: Authorization failed. Please', 'integrate-convertkit-wpforms' ), + sprintf( + '%s', + esc_url( admin_url( 'admin.php?page=wpforms-settings&view=integrations' ) ), + esc_html__( 'reconnect your Kit account.', 'integrate-convertkit-wpforms' ) + ) + ); + break; + + default: + $output = ''; + + /** + * Define the text to output in an admin error notice. + * + * @since 1.8.9 + * + * @param string $notice Admin notice name. + */ + $output = apply_filters( 'integrate_convertkit_wpforms_admin_notices_output_' . $notice, $output ); + break; + } + + // If no output defined, skip. + if ( empty( $output ) ) { + continue; + } + ?> +
+

+ +

+
+ exist() ) { + return update_option( $this->key_prefix, array( $notice ) ); + } + + // Fetch existing persistent notices. + $notices = $this->get(); + + // Add notice to existing notices. + $notices[] = $notice; + + // Remove any duplicate notices. + $notices = array_values( array_unique( $notices ) ); + + // Update and return. + return update_option( $this->key_prefix, $notices ); + + } + + /** + * Returns all notices stored in the options table. + * + * @since 1.8.9 + * + * @return array + */ + public function get() { + + // Fetch all notices from the options table. + return get_option( $this->key_prefix ); + + } + + /** + * Whether any persistent notices are stored in the option table. + * + * @since 1.8.9 + * + * @return bool + */ + public function exist() { + + if ( ! $this->get() ) { + return false; + } + + return true; + + } + + /** + * Delete all persistent notices. + * + * @since 1.8.9 + * + * @param string $notice Notice name. + * @return bool Success + */ + public function delete( $notice ) { + + // If no persistent notices exist, there's nothing to delete. + if ( ! $this->exist() ) { + return false; + } + + // Fetch existing persistent notices. + $notices = $this->get(); + + // Remove notice from existing notices. + $index = array_search( $notice, $notices, true ); + if ( $index !== false ) { + unset( $notices[ $index ] ); + } + + // Update and return. + return update_option( $this->key_prefix, $notices ); + + } + + /** + * Returns the singleton instance of the class. + * + * @since 1.8.9 + * + * @return object Class. + */ + public static function get_instance() { + + if ( null === self::$instance ) { + self::$instance = new self(); + } + + return self::$instance; + + } + +} + +new Integrate_ConvertKit_WPForms_Admin_Notices(); diff --git a/includes/class-integrate-convertkit-wpforms-api.php b/includes/class-integrate-convertkit-wpforms-api.php index a766a0e..01c9d30 100644 --- a/includes/class-integrate-convertkit-wpforms-api.php +++ b/includes/class-integrate-convertkit-wpforms-api.php @@ -113,4 +113,17 @@ public function __construct( $client_id, $redirect_uri, $access_token = false, $ } + /** + * Returns the access token. + * + * @since 1.8.9 + * + * @return string + */ + public function access_token() { + + return $this->access_token; + + } + } diff --git a/includes/class-integrate-convertkit-wpforms-resource.php b/includes/class-integrate-convertkit-wpforms-resource.php index 551b730..91e8b77 100644 --- a/includes/class-integrate-convertkit-wpforms-resource.php +++ b/includes/class-integrate-convertkit-wpforms-resource.php @@ -14,6 +14,13 @@ */ class Integrate_ConvertKit_WPForms_Resource extends ConvertKit_Resource_V4 { + /** + * The API class + * + * @var bool|Integrate_ConvertKit_WPForms_API + */ + public $api = false; + /** * Constructor. * @@ -33,8 +40,34 @@ public function __construct( $api_instance, $account_id = '' ) { $this->settings_name .= '_' . $account_id; } - // Call parent initialization function. - parent::init(); + // Get last query time and existing resources. + $this->last_queried = get_option( $this->settings_name . '_last_queried' ); + $this->resources = get_option( $this->settings_name ); + + } + + /** + * Fetches resources (custom fields, forms, sequences or tags) from the API, storing them in the options table + * with a last queried timestamp. + * + * If the refresh results in a 401, removes the access and refresh tokens from the connection. + * + * @since 1.8.9 + * + * @return WP_Error|array + */ + public function refresh() { + + // Call parent refresh method. + $result = parent::refresh(); + + // If an error occured, maybe delete credentials from the Plugin's settings + // if the error is a 401 unauthorized. + if ( is_wp_error( $result ) ) { + integrate_convertkit_wpforms_maybe_delete_credentials( $result, INTEGRATE_CONVERTKIT_WPFORMS_OAUTH_CLIENT_ID, $this->api->access_token() ); + } + + return $result; } diff --git a/includes/class-integrate-convertkit-wpforms.php b/includes/class-integrate-convertkit-wpforms.php index cc0e54b..b87e7e1 100644 --- a/includes/class-integrate-convertkit-wpforms.php +++ b/includes/class-integrate-convertkit-wpforms.php @@ -667,8 +667,8 @@ public function output_accounts( $connection_id = '', $connection = array() ) { } /** - * Outputs a dropdown of Kit Forms, Sequences and Tags, allowing the user + * to choose which resource to send form submissions to. * * @since 1.5.0 * @@ -691,28 +691,67 @@ public function output_lists( $connection_id = '', $connection = array() ) { return ''; } + // Get the selected ConvertKit subscribe setting, if one was already defined. + $value = ! empty( $connection['list_id'] ) ? $connection['list_id'] : ''; + + // Initialize resource classes. + $forms = new Integrate_ConvertKit_WPForms_Resource_Forms( $api, $connection['account_id'] ); + $sequences = new Integrate_ConvertKit_WPForms_Resource_Sequences( $api, $connection['account_id'] ); + $tags = new Integrate_ConvertKit_WPForms_Resource_Tags( $api, $connection['account_id'] ); + // Fetch Forms. // We use refresh() to ensure we get the latest data, as we're in the admin interface // and need to populate the select dropdown. - $forms = new Integrate_ConvertKit_WPForms_Resource_Forms( $api, $connection['account_id'] ); - $forms->refresh(); + $result = $forms->refresh(); + + // Return the dropdown if an error occurred, so the cached resources are + // available for selection. + if ( is_wp_error( $result ) ) { + return $this->output_select_dropdown( $forms, $sequences, $tags, $value, $connection_id, $result->get_error_message() ); + } // Fetch Tags. // We use refresh() to ensure we get the latest data, as we're in the admin interface // and need to populate the select dropdown. - $tags = new Integrate_ConvertKit_WPForms_Resource_Tags( $api, $connection['account_id'] ); - $tags->refresh(); + $result = $tags->refresh(); - // Get the selected ConvertKit subscribe setting, if one was already defined. - $value = ! empty( $connection['list_id'] ) ? $connection['list_id'] : ''; + // Return the dropdown. + return $this->output_select_dropdown( $forms, $sequences, $tags, $value, $connection_id ); + + } + + /** + * Outputs the