diff --git a/modules/custom-status/custom-status.php b/modules/custom-status/custom-status.php index 334a257..9b79c63 100644 --- a/modules/custom-status/custom-status.php +++ b/modules/custom-status/custom-status.php @@ -32,11 +32,11 @@ class CustomStatus { const SETTINGS_SLUG = 'vw-custom-status'; // The metadata keys for the custom status term - const METADATA_POSITION_KEY = 'position'; + const METADATA_POSITION_KEY = 'position'; const METADATA_REQ_EDITORIAL_IDS_KEY = 'required_metadata_ids'; - const METADATA_REQ_EDITORIALS_KEY = 'required_metadatas'; - const METADATA_REQ_USER_IDS_KEY = 'required_user_ids'; - const METADATA_REQ_USERS_KEY = 'required_users'; + const METADATA_REQ_EDITORIALS_KEY = 'required_metadatas'; + const METADATA_REQ_USER_IDS_KEY = 'required_user_ids'; + const METADATA_REQ_USERS_KEY = 'required_users'; public static function init(): void { // Register the taxonomy we use with WordPress core, and ensure it's registered after editorial metadata @@ -161,10 +161,10 @@ public static function setup_install(): void { 'position' => 4, ], [ - 'name' => __( 'Pending Review' ), - 'slug' => 'pending', - 'description' => __( 'Post needs to be reviewed by an editor.', 'vip-workflow' ), - 'position' => 5, + 'name' => __( 'Pending Review' ), + 'slug' => 'pending', + 'description' => __( 'Post needs to be reviewed by an editor.', 'vip-workflow' ), + 'position' => 5, ], ]; @@ -208,10 +208,10 @@ public static function action_admin_enqueue_scripts(): void { wp_enqueue_style( 'vip-workflow-custom-status-styles', VIP_WORKFLOW_URL . 'dist/modules/custom-status/custom-status-configure.css', [ 'wp-components' ], $asset_file['version'] ); wp_localize_script( 'vip-workflow-custom-status-configure', 'VW_CUSTOM_STATUS_CONFIGURE', [ - 'custom_statuses' => self::get_custom_statuses(), + 'custom_statuses' => self::get_custom_statuses(), 'editorial_metadatas' => EditorialMetadata::get_editorial_metadata_terms(), - 'url_edit_status' => CustomStatusEndpoint::get_crud_url(), - 'url_reorder_status' => CustomStatusEndpoint::get_reorder_url(), + 'url_edit_status' => CustomStatusEndpoint::get_crud_url(), + 'url_reorder_status' => CustomStatusEndpoint::get_reorder_url(), ] ); } @@ -271,7 +271,7 @@ private static function modify_custom_statuses_with_editorial_metadata(): array // Add the required editorial metadata to the custom statuses for UI purposes foreach ( $custom_statuses as $status ) { $required_metadata_ids = $status->meta[ self::METADATA_REQ_EDITORIAL_IDS_KEY ] ?? []; - $required_metadatas = []; + $required_metadatas = []; foreach ( $required_metadata_ids as $metadata_id ) { $required_metadatas[] = $editorial_metadatas[ $metadata_id ]; } @@ -333,7 +333,7 @@ public static function post_admin_header(): void { $custom_statuses = self::get_custom_statuses(); // $selected can be empty, but must be set because it's used as a JS variable - $selected = ''; + $selected = ''; if ( ! empty( $post ) ) { // Get the status of the current post @@ -547,9 +547,9 @@ public static function add_custom_status( array $args ): WP_Term|WP_Error { $term_id = $inserted_term['term_id']; - $position = $args[ self::METADATA_POSITION_KEY ]; + $position = $args[ self::METADATA_POSITION_KEY ]; $required_metadata_ids = $args[ self::METADATA_REQ_EDITORIAL_IDS_KEY ] ?? []; - $required_user_ids = $args[ self::METADATA_REQ_USER_IDS_KEY ] ?? []; + $required_user_ids = $args[ self::METADATA_REQ_USER_IDS_KEY ] ?? []; // In case of failure, data cleanup happens which includes the term and the meta keys. @@ -570,6 +570,15 @@ public static function add_custom_status( array $args ): WP_Term|WP_Error { $term_result = self::get_custom_status_by( 'id', $term_id ); + if ( false !== $term_result ) { + /** + * Fires after a custom status is added to the database. + * + * @param WP_Term $term The custom status term object. + */ + do_action( 'vw_add_custom_status', $term_result ); + } + return $term_result; } @@ -584,7 +593,7 @@ public static function update_custom_status( int $status_id, array $args = [] ): $old_status = self::get_custom_status_by( 'id', $status_id ); if ( is_wp_error( $old_status ) ) { return $old_status; - } else if ( ! $old_status ) { + } elseif ( ! $old_status ) { return new WP_Error( 'invalid', __( "Custom status doesn't exist.", 'vip-workflow' ), array( 'status' => 400 ) ); } @@ -614,8 +623,8 @@ public static function update_custom_status( int $status_id, array $args = [] ): } $term_fields_to_update = [ - 'name' => isset( $args['name'] ) ? $args['name'] : $old_status->name, - 'slug' => isset( $args['slug'] ) ? $args['slug'] : $old_status->slug, + 'name' => isset( $args['name'] ) ? $args['name'] : $old_status->name, + 'slug' => isset( $args['slug'] ) ? $args['slug'] : $old_status->slug, 'description' => isset( $args['description'] ) ? $args['description'] : $old_status->description, ]; @@ -648,9 +657,19 @@ public static function update_custom_status( int $status_id, array $args = [] ): return $updated_term; } - $status_result = self::get_custom_status_by( 'id', $status_id ); + $updated_status = self::get_custom_status_by( 'id', $status_id ); - return $status_result; + if ( $updated_status ) { + /** + * Fires after a custom status is updated in the database. + * + * @param WP_Term $updated_status The updated status WP_Term object. + * @param array $update_args The arguments used to update the status. + */ + do_action( 'vw_update_custom_status', $updated_status, $args ); + } + + return $updated_status; } /** @@ -664,7 +683,7 @@ public static function delete_custom_status( int $status_id ): bool|WP_Error { $old_status = self::get_custom_status_by( 'id', $status_id ); if ( is_wp_error( $old_status ) ) { return $old_status; - } else if ( ! $old_status ) { + } elseif ( ! $old_status ) { return new WP_Error( 'invalid', __( "Custom status doesn't exist.", 'vip-workflow' ), array( 'status' => 400 ) ); } @@ -698,6 +717,15 @@ public static function delete_custom_status( int $status_id ): bool|WP_Error { return new WP_Error( 'invalid', __( 'Unable to delete custom status.', 'vip-workflow' ) ); } + /** + * Fires after a custom status is deleted from the database. + * + * @param int $term_id The ID of the status being deleted + * @param string $term_name The name of the status being deleted + * @param string $old_status_slug The slug of the status being deleted + */ + do_action( 'vw_delete_custom_status', $status_id, $old_status->name, $old_status_slug ); + // Re-order the positions after deletion $custom_statuses = self::get_custom_statuses(); @@ -727,9 +755,9 @@ public static function get_custom_statuses(): array { $statuses = get_terms( [ 'taxonomy' => self::TAXONOMY_KEY, 'hide_empty' => false, - 'orderby' => 'meta_value_num', - 'order' => 'ASC', - 'meta_key' => self::METADATA_POSITION_KEY, + 'orderby' => 'meta_value_num', + 'order' => 'ASC', + 'meta_key' => self::METADATA_POSITION_KEY, ]); if ( is_wp_error( $statuses ) || empty( $statuses ) ) { @@ -738,7 +766,7 @@ public static function get_custom_statuses(): array { // Add metadata to each term $statuses = array_map( function ( $status ) { - $term_meta = apply_filters( 'vw_register_custom_status_meta', [], $status ); + $term_meta = apply_filters( 'vw_register_custom_status_meta', [], $status ); $status->meta = $term_meta; return $status; @@ -771,8 +799,8 @@ public static function get_custom_status_by( string $field, int|string $value, $ if ( is_wp_error( $custom_status ) || ! $custom_status ) { $custom_status = false; - } else if ( $include_metadata ) { - $term_meta = apply_filters( 'vw_register_custom_status_meta', [], $custom_status ); + } elseif ( $include_metadata ) { + $term_meta = apply_filters( 'vw_register_custom_status_meta', [], $custom_status ); $custom_status->meta = $term_meta; } @@ -794,9 +822,9 @@ public static function get_core_statuses(): array { 'description' => __( 'Post is a draft; not ready for review or publication.', 'vip-workflow' ), ], [ - 'name' => __( 'Pending Review' ), - 'slug' => 'pending', - 'description' => __( 'Post needs to be reviewed by an editor.', 'vip-workflow' ), + 'name' => __( 'Pending Review' ), + 'slug' => 'pending', + 'description' => __( 'Post needs to be reviewed by an editor.', 'vip-workflow' ), ], ]; diff --git a/modules/notifications/notifications.php b/modules/notifications/notifications.php index 404a70b..c7a2569 100644 --- a/modules/notifications/notifications.php +++ b/modules/notifications/notifications.php @@ -54,9 +54,9 @@ public static function notification_status_change( string $new_status, string $o $body = ''; - $post_id = $post->ID; - $post_title = vw_draft_or_post_title( $post_id ); - $post_type = $post->post_type; + $post_id = $post->ID; + $post_title = vw_draft_or_post_title( $post_id ); + $post_type = $post->post_type; $subject_post_type = ucfirst( $post_type ); if ( 0 != $current_user->ID ) { @@ -147,13 +147,36 @@ public static function notification_status_change( string $new_status, string $o $action = 'status-change'; - self::schedule_emails( $action, $post, $subject, $body ); + $notification_email = OptionsUtilities::get_options_by_key( 'email_address' ); + $is_email_scheduled = '' !== $notification_email; - /* translators: 1: user name, 2: post type, 3: post id, 4: edit link, 5: post title, 6: old status, 7: new status */ - $webhook_format = __( '*%1$s* changed the status of *%2$s #%3$s - <%4$s|%5$s>* from *%6$s* to *%7$s*', 'vip-workflow' ); - $webhook_message = sprintf( $webhook_format, $current_user_display_name, $post_type, $post_id, $edit_link, $post_title, $old_status, $new_status ); + if ( $is_email_scheduled ) { + $recipients = [ $notification_email ]; + self::schedule_emails( $recipients, $action, $post, $subject, $body ); + } + + $webhook_url = OptionsUtilities::get_options_by_key( 'webhook_url' ); + $is_webhook_scheduled = '' !== $webhook_url; + + if ( $is_webhook_scheduled ) { + /* translators: 1: user name, 2: post type, 3: post id, 4: edit link, 5: post title, 6: old status, 7: new status */ + $webhook_format = __( '*%1$s* changed the status of *%2$s #%3$s - <%4$s|%5$s>* from *%6$s* to *%7$s*', 'vip-workflow' ); + $webhook_message = sprintf( $webhook_format, $current_user_display_name, $post_type, $post_id, $edit_link, $post_title, $old_status, $new_status ); + + self::schedule_webhook_notification( $webhook_message, $action, $post->post_modified_gmt ); + } - self::schedule_webhook_notification( $webhook_message, $action, $post->post_modified_gmt ); + // Fire the notification status change action if any notifications were scheduled + if ( $is_email_scheduled || $is_webhook_scheduled ) { + /** + * Fires after a notification is sent + * + * @param int $post_id The post ID of the post that was updated. + * @param bool $is_email_scheduled True if an email was scheduled as part of the notification, false otherwise. + * @param bool $is_webhook_scheduled True if a webhook was scheduled as part of the notification, false otherwise. + */ + do_action( 'vw_notification_status_change', $post->ID, $is_email_scheduled, $is_webhook_scheduled ); + } } } @@ -174,27 +197,21 @@ public static function get_notification_footer(): string { /** * Send email notifications * + * @param array $recipients An array of string email addresses to send to * @param string $action (status-change) * @param string $subject Subject of the email * @param string $message Body of the email * @param string $message_headers. (optional) Message headers */ - public static function schedule_emails( string $action, WP_Post $post, string $subject, string $message, string $message_headers = '' ): void { - // Ensure the email address is set from settings. - if ( empty( OptionsUtilities::get_options_by_key( 'email_address' ) ) ) { - return; - } - - $email_recipients = [ OptionsUtilities::get_options_by_key( 'email_address' ) ]; - + public static function schedule_emails( array $recipients, string $action, WP_Post $post, string $subject, string $message, string $message_headers = '' ): void { /** * Filter the email recipients * - * @param array $email_recipients Array of email recipients + * @param array $recipients Array of email recipients * @param string $action Action being taken, eg. status-change * @param WP_Post $post Post object */ - $email_recipients = apply_filters( 'vw_notification_email_recipients', $email_recipients, $action, $post ); + $recipients = apply_filters( 'vw_notification_email_recipients', $recipients, $action, $post ); /** * Filter the email subject @@ -203,7 +220,7 @@ public static function schedule_emails( string $action, WP_Post $post, string $s * @param string $action Action being taken, eg. status-change * */ - $subject = apply_filters( 'vw_notification_email_subject', $subject, $action, $post ); + $subject = apply_filters( 'vw_notification_email_subject', $subject, $action, $post ); /** * Filter the email message @@ -212,7 +229,7 @@ public static function schedule_emails( string $action, WP_Post $post, string $s * @param string $action Action being taken, eg. status-change * @param WP_Post $post Post object */ - $message = apply_filters( 'vw_notification_email_message', $message, $action, $post ); + $message = apply_filters( 'vw_notification_email_message', $message, $action, $post ); /** * Filter the email headers @@ -223,8 +240,8 @@ public static function schedule_emails( string $action, WP_Post $post, string $s */ $message_headers = apply_filters( 'vw_notification_email_headers', $message_headers, $action, $post ); - if ( ! empty( $email_recipients ) ) { - wp_schedule_single_event( time(), 'vw_send_scheduled_emails', [ $email_recipients, $subject, $message, $message_headers ] ); + if ( [] !== $recipients ) { + wp_schedule_single_event( time(), 'vw_send_scheduled_emails', [ $recipients, $subject, $message, $message_headers ] ); } } @@ -247,16 +264,11 @@ public static function send_emails( array $recipients, string $subject, string $ /** * Schedule a webhook notification * - * @param string $webhook_message Message to be sent to webhook + * @param string $webhook_url URL to be send the webhook to * @param string $action Action being taken, eg. status-change * @param string $timestamp Timestamp of the message, eg. the time at which the post was updated */ public static function schedule_webhook_notification( string $webhook_message, string $action, string $timestamp ): void { - // Ensure the webhook URL is set from settings. - if ( empty( OptionsUtilities::get_options_by_key( 'webhook_url' ) ) ) { - return; - } - $message_type = 'plugin:vip-workflow:' . $action; wp_schedule_single_event( time(), 'vw_send_scheduled_webhook', [ $webhook_message, $message_type, $timestamp ] ); @@ -273,6 +285,11 @@ public static function schedule_webhook_notification( string $webhook_message, s public static function send_to_webhook( string $message, string $message_type, string $timestamp ): bool { $webhook_url = OptionsUtilities::get_options_by_key( 'webhook_url' ); + if ( ! is_string( $webhook_url ) || strlen( $webhook_url ) === 0 ) { + // This can happen if the webhook URL was cleared after scheduling this notification + return false; + } + // Set up the payload $payload = [ 'type' => $message_type, diff --git a/modules/settings/settings.php b/modules/settings/settings.php index fb01c96..062a4b9 100644 --- a/modules/settings/settings.php +++ b/modules/settings/settings.php @@ -15,13 +15,13 @@ class Settings { // Its key to centralize these, so we can easily update them in the future const DEFAULT_SETTINGS_OPTIONS = [ - 'post_types' => [ + 'post_types' => [ 'post' => 'on', 'page' => 'on', ], - 'publish_guard' => 'on', - 'email_address' => '', - 'webhook_url' => '', + 'publish_guard' => 'on', + 'email_address' => '', + 'webhook_url' => '', ]; /** @@ -53,7 +53,7 @@ public static function add_admin_menu(): void { */ public static function action_admin_enqueue_scripts(): void { if ( HelperUtilities::is_settings_view_loaded( self::SETTINGS_SLUG ) ) { - $asset_file = include VIP_WORKFLOW_ROOT . '/dist/modules/settings/settings.asset.php'; + $asset_file = include VIP_WORKFLOW_ROOT . '/dist/modules/settings/settings.asset.php'; $dependencies = [ ...$asset_file['dependencies'], 'jquery' ]; wp_enqueue_script( 'vip-workflow-settings-js', VIP_WORKFLOW_URL . 'dist/modules/settings/settings.js', $dependencies, $asset_file['version'], true ); } @@ -63,7 +63,7 @@ public static function action_admin_enqueue_scripts(): void { * Register the settings for the module */ public static function register_settings(): void { - $settings_section_id = OptionsUtilities::get_module_options_general_key(); + $settings_section_id = OptionsUtilities::get_module_options_general_key(); $settings_section_page = OptionsUtilities::get_module_options_key(); add_settings_section( $settings_section_id, false, '__return_false', $settings_section_page ); @@ -233,10 +233,19 @@ public static function helper_settings_validate_and_save(): bool { $new_options = ( isset( $_POST[ OptionsUtilities::get_module_options_key() ] ) ) ? $_POST[ OptionsUtilities::get_module_options_key() ] : []; $new_options = self::settings_validate( $new_options ); + $old_options = (array) OptionsUtilities::get_module_options( self::SETTINGS_SLUG ); // Blend the new options with the old options, including any new options that may have been added OptionsUtilities::update_module_options( $new_options ); + /** + * Fires before saving the settings for all modules + * + * @param array $new_options The new options + * @param array $old_options The old options + */ + do_action( 'vw_save_settings', $new_options, $old_options ); + // Redirect back to the settings page that was submitted without any previous messages $goback = add_query_arg( 'message', 'settings-updated', remove_query_arg( [ 'message' ], wp_get_referer() ) ); wp_safe_redirect( $goback ); diff --git a/modules/telemetry/telemetry.php b/modules/telemetry/telemetry.php new file mode 100644 index 0000000..c2b21f4 --- /dev/null +++ b/modules/telemetry/telemetry.php @@ -0,0 +1,246 @@ + VIP_WORKFLOW_VERSION ] ); + + // Custom Status events + add_action( 'transition_post_status', [ __CLASS__, 'record_custom_status_change' ], 10, 3 ); + add_action( 'vw_add_custom_status', [ __CLASS__, 'record_add_custom_status' ], 10, 3 ); + add_action( 'vw_delete_custom_status', [ __CLASS__, 'record_delete_custom_status' ], 10, 3 ); + add_action( 'vw_update_custom_status', [ __CLASS__, 'record_update_custom_status' ], 10, 2 ); + + // Notification events + add_action( 'vw_notification_status_change', [ __CLASS__, 'record_notification_sent' ], 10, 3 ); + + // Settings events + add_action( 'vw_upgrade_version', [ __CLASS__, 'record_admin_update' ], 10, 2 ); + add_action( 'vw_save_settings', [ __CLASS__, 'record_settings_update' ], 10, 2 ); + } + + // Custom Status events + + /** + * Record an event when a post's custom status changes + * + * @param string $new_status The new status + * @param string $old_status The old status + * @param WP_Post $post The post object + */ + public static function record_custom_status_change( string $new_status, string $old_status, WP_Post $post ): void { + if ( ! in_array( $post->post_type, HelperUtilities::get_supported_post_types() ) ) { + // This isn't a supported post type + return; + } elseif ( $old_status === $new_status ) { + // The status hasn't changed + return; + } elseif ( in_array( $new_status, [ 'inherit', 'auto-draft' ] ) ) { + // The status hasn't changed, or it moved into an auto-generated status + return; + } + + $status_slugs = wp_list_pluck( CustomStatus::get_custom_statuses(), 'slug' ); + + if ( ! in_array( $new_status, $status_slugs, true ) && ! in_array( $old_status, $status_slugs, true ) ) { + // The status isn't moving to or from a custom status + return; + } + + self::$tracks->record_event( 'post_custom_status_changed', [ + 'old_status' => $old_status, + 'new_status' => $new_status, + 'post_id' => $post->ID, + ] ); + } + + /** + * Record an event when a custom status is created + * + * @param WP_Term $term The custom status term object + */ + + public static function record_add_custom_status( WP_Term $term ): void { + $required_user_count = count( $updated_status->meta[ CustomStatus::METADATA_REQ_USER_IDS_KEY ] ?? [] ); + $required_editorial_metadata_count = count( $updated_status->meta[ CustomStatus::METADATA_REQ_EDITORIAL_IDS_KEY ] ?? [] ); + + self::$tracks->record_event( 'custom_status_created', [ + 'term_id' => $term->term_id, + 'name' => $term->name, + 'slug' => $term->slug, + 'required_users' => $required_user_count, + 'required_em' => $required_editorial_metadata_count, + ] ); + } + + /** + * Record an event when a custom status is deleted + * + * @param int $term_id The custom status term ID + * @param string $term_name The custom status term name + * @param string $slug The status slug + */ + public static function record_delete_custom_status( int $term_id, string $term_name, string $slug ): void { + self::$tracks->record_event( 'custom_status_deleted', [ + 'term_id' => $term_id, + 'name' => $term_name, + 'slug' => $slug, + ] ); + } + + /** + * Record an event when a custom status is updated + * + * @param WP_Term $updated_status The updated status WP_Term object. + * @param array $update_args The arguments used to update the status. + */ + public static function record_update_custom_status( WP_Term $updated_status, array $update_args ): void { + $is_position_update = 1 === count( $update_args ) && isset( $update_args['position'] ); + if ( $is_position_update ) { + // Ignore position changes, as they fire for every custom status when statuses are reordered + return; + } + + $required_user_count = count( $updated_status->meta[ CustomStatus::METADATA_REQ_USER_IDS_KEY ] ?? [] ); + $required_editorial_metadata_count = count( $updated_status->meta[ CustomStatus::METADATA_REQ_EDITORIAL_IDS_KEY ] ?? [] ); + + self::$tracks->record_event( 'custom_status_changed', [ + 'term_id' => $updated_status->term_id, + 'name' => $updated_status->name, + 'slug' => $updated_status->slug, + 'required_users' => $required_user_count, + 'required_em' => $required_editorial_metadata_count, + ] ); + } + + // Notification events + + /** + * Record an event when a notification is sent + * + * @param int $post_id The post ID of the post that was updated. + * @param bool $is_email_scheduled True if an email was scheduled as part of the notification, false otherwise. + * @param bool $is_webhook_scheduled True if a webhook was scheduled as part of the notification, false otherwise. + */ + public static function record_notification_sent( int $post_id, $is_email_scheduled, $is_webhook_scheduled ): void { + self::$tracks->record_event( 'notification_sent', [ + 'post_id' => $post_id, + 'email' => $is_email_scheduled, + 'webhook' => $is_webhook_scheduled, + ] ); + } + + // Settings events + + /** + * Record an event when the plugin is upgraded + * + * @param string $previous_version The previous version + * @param string $new_version The new version + */ + public static function record_admin_update( string $previous_version, string $new_version ): void { + $custom_statuses = CustomStatus::get_custom_statuses(); + $supported_post_types = HelperUtilities::get_supported_post_types(); + + $published_post_count = 0; + $custom_status_post_count = 0; + + foreach ( $supported_post_types as $post_type ) { + // Get all posts count for this post type + $posts_count = wp_count_posts( $post_type ); + + $published_post_count += (int) $posts_count->publish; + + foreach ( $custom_statuses as $status ) { + if ( isset( $posts_count->{ $status->slug } ) ) { + $custom_status_post_count += (int) $posts_count->{ $status->slug }; + } + } + } + + self::$tracks->record_event( 'plugin_update', [ + 'previous_version' => $previous_version, + 'new_version' => $new_version, + 'published_posts' => $published_post_count, + 'custom_status_posts' => $custom_status_post_count, + ] ); + } + + /** + * Record presence of publish guard and webhook settings if toggled + * + * @param array $new_options The new options + * @param array $old_options The old options + */ + public static function record_settings_update( array $new_options, array $old_options ): void { + if ( $new_options['publish_guard'] !== $old_options['publish_guard'] ) { + self::record_publish_guard_toggle( $new_options['publish_guard'] ); + } + + if ( $new_options['webhook_url'] !== $old_options['webhook_url'] ) { + self::record_send_to_webhook_toggle( $new_options['webhook_url'] ); + } + + if ( $new_options['email_address'] !== $old_options['email_address'] ) { + self::record_send_to_email_toggle( $new_options['email_address'] ); + } + } + + /** + * Record an event when the publish guard is toggled + * + * @param string $publish_guard_value Either 'on' or 'off'. + */ + protected static function record_publish_guard_toggle( string $publish_guard_value ): void { + if ( 'on' === $publish_guard_value ) { + self::$tracks->record_event( 'publish_guard_enabled' ); + } else { + self::$tracks->record_event( 'publish_guard_disabled' ); + } + } + + /** + * Record an event when send to webhook is toggled + * + * @param string $webhook_url A string indicating a webhook URL, or an empty string if none is set. + */ + protected static function record_send_to_webhook_toggle( string $webhook_url ): void { + if ( '' === $webhook_url ) { + self::$tracks->record_event( 'send_to_webhook_disabled' ); + } else { + self::$tracks->record_event( 'send_to_webhook_enabled' ); + } + } + + /** + * Record an event when send to email is changed + * + * @param string $email_address A string indicating a webhook URL, or an empty string if none is set. + */ + protected static function record_send_to_email_toggle( string $email_address ): void { + if ( '' === $email_address ) { + self::$tracks->record_event( 'send_to_email_disabled' ); + } else { + self::$tracks->record_event( 'send_to_email_enabled' ); + } + } +} + +Telemetry::init(); diff --git a/vip-workflow.php b/vip-workflow.php index e77f04f..a01302c 100644 --- a/vip-workflow.php +++ b/vip-workflow.php @@ -45,6 +45,14 @@ add_action( 'admin_init', function () { $previous_version = get_option( 'vip_workflow_version' ); if ( $previous_version && version_compare( $previous_version, VIP_WORKFLOW_VERSION, '<' ) ) { + /** + * Fires when the plugin is upgraded + * + * @param string $previous_version The previous version of the plugin + * @param string $new_version The new version of the plugin + */ + do_action( 'vw_upgrade_version', $previous_version, VIP_WORKFLOW_VERSION ); + update_option( 'vip_workflow_version', VIP_WORKFLOW_VERSION ); } elseif ( ! $previous_version ) { update_option( 'vip_workflow_version', VIP_WORKFLOW_VERSION ); @@ -61,8 +69,16 @@ require_once VIP_WORKFLOW_ROOT . '/modules/shared/php/log-level-enum.php'; require_once VIP_WORKFLOW_ROOT . '/modules/shared/php/logging-utility.php'; -// Modules +// Modules - Telemetry +if ( class_exists( '\Automattic\VIP\Telemetry\Tracks' ) ) { + // Telemetry is only initialized if the Telemetry library is available on VIP's platform + require_once VIP_WORKFLOW_ROOT . '/modules/telemetry/telemetry.php'; +} + +// Modules - Settings require_once VIP_WORKFLOW_ROOT . '/modules/settings/settings.php'; + +// Other modules require_once VIP_WORKFLOW_ROOT . '/modules/custom-status/custom-status.php'; require_once VIP_WORKFLOW_ROOT . '/modules/editorial-metadata/editorial-metadata.php'; require_once VIP_WORKFLOW_ROOT . '/modules/notifications/notifications.php';