Salesforce Sandbox Accounts

Salesforce Sandbox Accounts

It』s possible to connect WP Fusion to a Salesforce sandbox account for testing purposes. To do so you』ll need to add a filter to your theme』s functions.php file to override the authentication URL:
function salesforce_auth_url( $url ) {

return 'https://test.salesforce.com/services/oauth2/token';

}

add_filter( 'wpf_salesforce_auth_url', 'salesforce_auth_url' );
Then enter the credentials for your sandbox user into the main WP Fusion setup tab, and click Test Connection to establish a connection to Salesforce.
For more information about user credentials with Salesforce sandboxes please see https://help.salesforce.com/articleView?id=data_sandbox_create.htm&type=5.

#Was this helpful?

Let us know if you liked the post. That』s the only way we can improve.

Yes

No

Infusionsoft API Goals

Infusionsoft API Goals

WP Fusion supports making API calls to your Infusionsoft application when a user profile is updated on your WordPress site. This is useful if you want to trigger a campaign sequence after a user』s updated profile data is synced with your application. For example, you could perform actions based on the contents of certain fields, like assigning an owner, or applying a tag.
api-call
In the main WP Fusion settings page, check the API Call checkbox, and then optionally specify an integration name and API call name. For most setups you can leave these at default.
Then, in the Infusionsoft campaign builder, create an 「API Call goal」, and configure it to match the integration name and call name you set in the WP Fusion settings.
Now, whenever a user profile is updated, the goal will be achieved, and the contact will be moved through the subsequent campaign!

#Was this helpful?

Let us know if you liked the post. That』s the only way we can improve.

Yes

No

Email address changes with MailerLite

Email address changes with MailerLite

#Overview
MailerLite gives you a very capable email marketing automation solution, at a great price.
In almost every way it』s just as powerful as one of our A-rated marketing automation tools, like ActiveCampaign, but at a fraction of the cost.
The one limitation with MailerLite is that it is not possible for subscribers to change their email address.
Unfortunately this basically cripples MailerLite in terms of being a marketing automation tool for use with WP Fusion / WordPress, and makes it suitable only for the most basic of businesses.
#Email address changes
To get around this, WP Fusion has two options for ways to deal with email address changes. These can be configured at Settings » WP Fusion » Advanced.

The options are Ignore or Duplicate and Delete.
#Ignore
The default setting is to ignore email address changes and not sync them to MailerLite (since trying to update a subscriber』s email address will create an API error).
With this setting, if someone changes their email address in WordPress, their WordPress user record will become unlinked from their MailerLite subscriber record. This will remove any MailerLite groups from the user record, which means the user will lose access to any purchased courses or membership content until you manually create a new record for them in MailerLite.
#Duplicate and Delete
If you』re worried about members losing access to purchased content, you can choose Duplicate and Delete.
When this option is selected, if a user changes their email address, WP Fusion will load their subscriber record and groups over the MailerLite API. It will then create a new subscriber in MailerLite with the same custom fields and groups, but the updated email address. Then the original subscriber record (with the old email) will be deleted.
While this does allow users to change their email address without losing their groups (and group-based access), anything else about the subscriber will be lost. That means any site tracking data, email open history, and positions in automations and campaigns will be permanently lost.

#Was this helpful?

Let us know if you liked the post. That』s the only way we can improve.

Yes

No

Custom Objects with HubSpot

Custom Objects with HubSpot

#Overview
In addition to supporting custom objects with Zoho, Salesforce, and Ontraport via the wpf_crm_object_type filter and the add_object() method, WP Fusion supports adding and updating custom objects with HubSpot.
For a video walkthrough of custom objects, check out Data in HubSpot: Custom Objects and Other Tools in HubSpot』s Academy.
For additional information and examples please review HubSpot』s CRM Custom Objects documentation.
The examples below assume you have already created a custom object schema and know the object type ID as well as any association type IDs (if you plan to associate your objects with other objects).
#Authentication
Because custom objects are still in beta, your HubSpot API key is required to interact with them (your existing OAuth authorization via WP Fusion isn』t yet sufficient).
To use custom objects with HubSpot and WP Fusion, you must first define your HubSpot API key in your wp-config.php file, like so:
define( 'HUBSPOT_API_KEY', 'xx599590-7888-43ed-a896-5abbc2ef9aa2' );
#Methods
The methods are basically the same as those with other CRMs, those are:

add_object( $properties, $object_type_id )
update_object( $object_id, $properties, $object_type_id )
load_object( $object_id, $object_type_id, $properties )

#add_object()
This method creates a new object of the specified object type ID. Following the HubSpot custom objects walkthrough, we have created a new Car custom object, with an objectTypeId of 2-4370788.
$properties = array(
'condition' => 'used',
'date_received' => '1582416000000',
'year' => '2014',
'make' => 'Nissan',
'model' => 'Frontier',
'vin' => '4Y1SL65848Z411439',
'color' => 'White',
'mileage' => '80000',
'price' => '12000',
'notes' => 'Excellent condition. No accidents.',
);

$object_type_id = '2-4370788';

$object_id = wp_fusion()->crm->add_object( $properties, $object_type_id );

if ( is_wp_error( $object_id ) ) {
wpf_log( 'error', wpf_get_current_user_id(), 'Error adding object: ' . $object_id->get_error_message() );
return false;
}

// Do what you want with $object_id here.
Now we have an $object_id with the ID of the new object. This can then be used for additional operations.
For example to associate the new object with a contact ID 101, we can make a PUT request against the associations API:
$contact_id = '101';
$association_type_id = '3';

$request = "https://api.hubapi.com/crm/v3/objects/{$object_type_id}/{$object_id}/associations/contacts/{$contact_id}/{$association_type_id}/?hapikey=" . HUBSPOT_API_KEY;

$params = array( 'method' => 'PUT' );
$response = wp_safe_remote_request( $request, $params );

if ( is_wp_error( $response ) ) {
wpf_log( 'error', wpf_get_current_user_id(), 'Error associating object with contact: ' . $response->get_error_message() );
return false;
}
Then the new object is associated with the contact, like so:

#update_object()
This method allows you to update an existing object. For example to change our Nissan Frontier with ID 599237525 into a Ford Ranger:
$properties = array(
'make' => 'Ford',
'model' => 'Ranger',
);

$object_id = '599237525';
$object_type_id = '2-4370788';

$response = wp_fusion()->crm->update_object( $object_id, $properties, $object_type_id );

if ( is_wp_error( $response ) ) {
wpf_log( 'error', wpf_get_current_user_id(), 'Error updating object: ' . $response->get_error_message() );
return false;
}
#load_object()
This method loads an object by ID and returns its properties. Note that unlike other CRMs, you must specify the properties you want returned.
Using our Car example from above, we can request the Condition, Year, Make, and Model:
$object_id = '599237525';
$object_type_id = '2-4370788';
$properties = array( 'condition', 'year', 'make', 'model' );

$response = wp_fusion()->crm->load_object( $object_id, $object_type_id, $properties );

if ( is_wp_error( $response ) ) {
wpf_log( 'error', wpf_get_current_user_id(), 'Error loading object: ' . $response->get_error_message() );
return false;
}

print_r( $response );

/*

Array
(
[id] => 599237525
[properties] => Array
(
[condition] => used
[hs_createdate] => 2021-12-15T09:41:24.159Z
[hs_lastmodifieddate] => 2021-12-15T10:10:22.801Z
[hs_object_id] => 599237525
[make] => Ford
[model] => Ranger
[year] => 2014
)

[createdAt] => 2021-12-15T09:41:24.159Z
[updatedAt] => 2021-12-15T10:10:22.801Z
[archived] =>
)

*/

#Was this helpful?

Let us know if you liked the post. That』s the only way we can improve.

Yes

No

Custom fields not loading with AgileCRM

Custom fields not loading with AgileCRM

AgileCRM doesn』t currently have an API method for listing all of the custom fields in your account. To get around this, we query the first 100 contacts in your account, and build the list of available custom fields based on fields found on those contacts.
If you』re missing custom fields in WP Fusion, or if you』ve just added a custom field in Agile, try adding some data to the custom field for a few contacts, then resynchronize the available fields by going to Settings >> WP Fusion >> Setup, and clicking the green Resynchronize button.

#Was this helpful?

Let us know if you liked the post. That』s the only way we can improve.

Yes

No

ConvertKit Unsubscribe Notifications

ConvertKit Unsubscribe Notifications

When a contact unsubscribes from emails in ConvertKit, ConvertKit prevents the subscriber from being accessed via the API.
This means that any tags associated with the subscriber will no longer be available in WordPress.
Unfortunately the only way around this is to manually delete the subscriber and re-add them, then manually apply their access tags.
Under the Advanced tab in the WP Fusion settings you can choose to be notified via email when a subscriber unsubscribes.

When this setting is enabled you』ll receive an email at the specified address containing the email address of the unsubscribed person. You can then log into ConvertKit, delete them, and add them again.

#Was this helpful?

Let us know if you liked the post. That』s the only way we can improve.

Yes

No

Unexpected Tags with ConvertKit

Unexpected Tags with ConvertKit

Due to some quirks with ConvertKit, you cannot create a new subscriber via the API without also applying a tag. It』s recommended to set a general tag in the Assign Tags setting to be applied to all new subscribers.

If you don』t specify a tag here, the first available tag in the list will be applied.

#Was this helpful?

Let us know if you liked the post. That』s the only way we can improve.

Yes

No

ActiveCampaign Event Tracking

ActiveCampaign Event Tracking

#Overview
ActiveCampaign includes a feature called Event Tracking which can be used in addition to site tracking to track additional engagement points on your website, for example video plays, course progress, forum activity, etc.

WP Fusion』s ActiveCampaign integration includes a helper function to allow you to track events over the ActiveCampaign events API.
To use event tracking with WP Fusion it must first be enabled in your ActiveCampaign account, at Settings » Tracking » Event Tracking.
These examples work with the full version of WP Fusion as well as WP Fusion Lite.
#Examples
#Basic example
Events are tracked by making a call to wp_fusion()->crm->track_event(), for example:
wp_fusion()->crm->track_event( 'My event' );
You can also optionally pass an event description:
wp_fusion()->crm->track_event( 'My event', 'Event description' );
#Track LearnDash course progress as events
Tracking data from other plugins can be achieved by calling the track_event function while hooked to other plugins』 actions.
For example to send LearnDash course progress to ActiveCampaign as events:
function wpf_track_learndash_events( $data ) {

if ( doing_action( 'learndash_course_completed' ) ) {
$post_id = $data['course']->ID;
} elseif ( doing_action( 'learndash_lesson_completed' ) ) {
$post_id = $data['lesson']->ID;
} elseif ( doing_action( 'learndash_topic_completed' ) ) {
$post_id = $data['topic']->ID;
} elseif ( doing_action( 'learndash_quiz_completed' ) ) {
$post_id = $data['quiz']->ID;
}

$last_item = get_post( $post_id );

// Get the post type label

$post_type = get_post_type_object( $last_item->post_type );
$label = $post_type->labels->singular_name;

wp_fusion()->crm->track_event( 'Completed ' . $label, $last_item->post_title );

// Quizzes

if ( isset( $data['quiz'] ) ) {

if ( true == $data['pass'] ) {
wp_fusion()->crm->track_event( 'Passed quiz' );
} else {
wp_fusion()->crm->track_event( 'Failed quiz' );
}
}

}

add_action( 'learndash_course_completed', 'wpf_track_learndash_events', 5 );
add_action( 'learndash_lesson_completed', 'wpf_track_learndash_events', 5 );
add_action( 'learndash_quiz_completed', 'wpf_track_learndash_events', 5 );
add_action( 'learndash_topic_completed', 'wpf_track_learndash_events', 5 );
That data then shows up on the student』s contact record in ActiveCampaign like so

#Was this helpful?

Let us know if you liked the post. That』s the only way we can improve.

Yes

No

The WP Fusion User Class

The WP Fusion User Class

#Overview
As we discussed in the first section, WP Fusion achieves its flexibility and extensibility by standardizing the way WordPress communicates with different CRM systems.
The first section covered how to interface with your selected CRM directly by utilizing the wp_fusion()->crm object. Those methods are 「low level」, they require you to already know the contact ID of the contact you want to edit, and do very little in terms of validation of data or redundancy checking.
So while WP Fusion』s CRM class deals with contacts and contact data, the WPF_User class deals with WordPress users and user data.
This class works like a central dispatch, taking incoming events and data from our various plugin integrations and routing it to the appropriate method in your selected CRM.
#A basic example of how this all works, using LifterLMS

When a student completes a lesson in LifterLMS, LifterLMS triggers the 'lifterlms_lesson_completed' action.
In our LifterLMS integration file, we have a function attached to this hook. This function checks to see if any tags have been configured to be applied when the lesson is marked complete.
If there are tags to apply, the function then calls:
wp_fusion()->user->apply_tags( $tags, $user_id );

In the apply_tags() function, we first check to see if there is a contact ID available for that user. If the user doesn』t have a contact record, then nothing else happens.
Then we check the user』s current tags and see if the tags being applied are actually new. If the user already has the tag, then we don』t need to send an unnecessary API call.
Then apply_tags() sends the new tags to the CRM wrapper class (discussed in the previous article), by calling:
wp_fusion()->crm->apply_tags( $tags, $contact_id );

It checks the response from the API call, and if there were any errors, these are recorded in WP Fusion』s error log for troubleshooting purposes.
Finally we update the tags stored in in the usermeta table for that user, at '{crm_slug}_tags' so they can be quickly accessed again in the future.

#The available methods in the WPF_User class:

#user_register()

wp_fusion()->user->user_register( $user_id, $post_data = null, $force = false );
This function is triggered whenever a user registers on your site, from any plugin or other source. It can also be manually called to create a new CRM contact from an existing user ID.
Parameters:

$user_id (int) (Required) The ID of the user you』d like to use to create the new contact
$post_data (array) (Optional) You can pass in additional data you』d like to be included with the new contact. If this is left blank, WP Fusion will attempt to get as much data as possible out of the database
$force (bool) (Optional) If you have the setting for 「Create Contacts」 disabled in the WP Fusion settings, then you can set this argument to true to force creating a new contact.

Return values:

$contact_id (int) The contact ID of the new contact
false (bool) If there wasn』t enough data available to create a new contact, or if there was an API connection failure

#get_contact_id()

wp_fusion()->user->get_contact_id( $user_id, $force_update = false );
Gets the contact ID for a user from their local user meta, or forces an update of the contact ID by looking up their email address in your CRM.
Parameters:

$user_id (int) (Required) The ID of the user you』d like to get the contact ID for
$force_update (bool) (Optional) If set to true, this will force an update of the saved contact ID for the user by looking up their email address in your CRM

Return values:

$contact_id (int) The contact ID of the user
false (bool) If the user has no contact ID saved on the site, or if WP Fusion was unable to locate their email address in your CRM

#get_tags()

wp_fusion()->user->get_tags( $user_id, $force_update = false );
Gets the tags for a user from their local user meta, or forces an update of their tags by performing an API call.
Parameters:

$user_id (int) (Required) The ID of the user you』d like to get the tags ID for
$force_update (bool) (Optional) If set to true, this will force an update of the saved tags for the user by force-checking their contact ID and then re-loading the user』s tags from your CRM

Return values:

$user_tags (array) An array of tag IDs applied to the contact. Will be an empty array if no tags were found
false (bool) If the user has no contact ID saved on the site, or if WP Fusion was unable to locate their email address in your CRM

#pull_user_meta()

wp_fusion()->user->pull_user_meta( $user_id );
Loads the latest meta data from the CRM contact record for the specified user, and updates their saved data on your site.
Parameters:

$user_id (int) (Required) The ID of the user you』d like to load from the CRM

Return values:

$user_meta (array) An array of WordPress meta fields and their values that were loaded for the user
false (bool) If the user has no eligible meta to load, or if there was an error loading their contact record

#push_user_meta()

wp_fusion()->user->push_user_meta( $user_id, $user_meta = false );
Pushes meta data for a user from WordPress to your CRM.
Parameters:

$user_id (int) (Required) The ID of the user you』d like to update
$user_meta (array) (Optional) An associative array of WordPress meta keys and values to update. If left blank, WP Fusion will send all meta data found for that user in the database.

Return values:

true (bool) The contact was successfully updated
false (bool) If the user has no saved contact ID, or there was no eligible meta data to send

#apply_tags()

wp_fusion()->user->apply_tags( $tags, $user_id = false );
Applies an array of tags to a user.
Parameters:

$tags (array) (Required) An array of tag IDs to apply to the user
$user_id (int) (Optional) The user to apply the tags to. Will use the current logged in user if left blank

Return values:

true (bool) The tags were successfully applied
false (bool) If no contact ID was found for the user, or if the user already had the specified tags and no API call was needed

#remove_tags()

wp_fusion()->user->remove_tags( $tags, $user_id = false );
Removes an array of tags from a user.
Parameters:

$tags (array) (Required) An array of tag IDs to remove from the user
$user_id (int) (Optional) The user to remove the tags from. Will use the current logged in user if left blank

Return values:

true (bool) The tags were successfully removed
false (bool) If no contact ID was found for the user, or if the user didn』t have those tags in the first place

#import_user()

wp_fusion()->user->import_user( $contact_id, $send_notification = false, $role = false );
This function imports a contact from your CRM, by contact ID, and creates a new WordPress user. If a user already exists with the same contact ID, that user will just be updated.
New users will be given a randomly generated password. If you have enabled 「Return Password」 in the WP Fusion settings, this password will be stored back to their contact record.
Parameters:

$contact_id (int) (Required) The contact ID to import
$send_notification (bool) (Optional) Whether to send the new user the default WordPress welcome email
$role (bool / string) (Optional) If provided, the new user will be given the specified role. Otherwise they will be created with the site default role.

Return values:

$user_id (int) The ID of the new user (or existing user if updated)
$error (WP Error object) If there was an API error importing the user, or if the loaded contact data didn』t contain an email address

#Utility and helper functions:

#get_user_id()

wp_fusion()->user->get_user_id( $contact_id );
Looks up a user by their contact ID.
Parameters:

$contact_id (int / string) (Required) The contact ID to search by

Return values:

$user_id (int) The ID of the user
false (bool) If no user was found with that contact ID

#has_tag()

wp_fusion()->user->has_tag( $tag, $user_id = false );
Checks a given user to see if they have the specified tag.
Parameters:

$tag (int / string) (Required) The tag ID or tag label to check for
$user_id (int) (Optional) The user ID to check. Will default to the current user ID if left blank

Return values:

true (bool) The user has the tag
false (bool) The user does not have the tag

#get_tag_id()

wp_fusion()->user->get_tag_id( $tag_label );
For CRMs that use internal IDs for their tags (like Infusionsoft), this function will return the tag ID for a given tag label.
Parameters:

$tag_label (string) (Required) The tag label to check for

Return values:

$tag_id (int / string) The internal ID for the supplied tag label
false (bool) If no tag was found with that label

#get_tag_label()

wp_fusion()->user->get_tag_label( $tag_id );
For CRMs that use internal IDs for their tags (like Infusionsoft), this function will return the tag label for a given tag ID.
Parameters:

$tag_id ( int / string) (Required) The tag ID to check for

Return values:

$label (string) The tag label for that ID. If no tag is found, it will return 「Unknown Tag:」 with the tag ID

#Was this helpful?

Let us know if you liked the post. That』s the only way we can improve.

Yes

No

The WP Fusion CRM API

The WP Fusion CRM API

#Overview
WP Fusion takes a completely original approach to connecting WordPress to our supported CRMs and marketing automation systems. There is no other plugin available that is as flexible or extensible.
Normally, with a plugin like Gravity Forms (for example), you would download one of several available add-ons that connect Gravity Forms to your CRM of choice, like the ActiveCampaign add-on or AgileCRM add-on. These are created from scratch and use code unique to the API in question.
Before WP Fusion, many sites would have to use several different plugins to get a basic level of integration with their CRM. An ActiveCampaign user might need ActiveCampaign add-on for Gravity Forms, ActiveWoo to send WooCommerce order data, and the official ActiveCampaign plugin to enable site tracking and embedding forms.
This introduces a lot of unnecessary overlap, with the ActiveCampaign SDK being included multiple times, and redundant API calls being sent.
#How we solved that problem
When designing WP Fusion, we realized that all of these CRM systems offer the same basic functionality: adding new contacts, updating existing contacts, applying and removing tags, and loading contact data from the CRM.
So with that in mind, we created a wrapper class for each CRM, with a standardized set of functions to send and receive data from WordPress, then reformat it according to the rules of each API. Every one of our integrations has at least the following methods:
#connect()
wp_fusion()->crm->connect( $auth = null, $test = false );
The connect() function is called by all the member functions in the class to initialize the connection to the CRM. It』s not necessary to use this in your code, but it can be used to validate an API key or OAuth token by setting $test to true.
Parameters:

$auth (string) (Optional) The API key or other authorization code required to connect. There may be more than one parameter depending on the CRM. If this is left blank, WP Fusion will use the authentication data you entered on the original setup page.
$test (bool) (Optional) If set to true, WP Fusion will also verify the connection by attempting to make an API call.

Return values:

true (bool) If the connection was successful
$error (WP_Error object) If the connection was unsuccessful

#sync_tags()
wp_fusion()->crm->sync_tags();
Loads all available tags from the CRM and updates the available tags in the tag dropdowns for WP Fusion.
Return values:

$tags (array) An array of tags in the CRM
$error (WP_Error object) If the API call failed

#sync_crm_fields()
wp_fusion()->crm->sync_crm_fields();
Loads all available fields and custom fields from the CRM and updates the available fields in the dropdowns for WP Fusion.
Return values:

$crm_fields (array) An array of available fields in the CRM
$error (WP_Error object) If the API call failed

#get_contact_id()
wp_fusion()->crm->get_contact_id( $email_address );
Looks up a contact ID in the CRM by their email address.
Parameters:

$email_address (string) The email address to search for a contact by

Return values:

$contact_id (int) A contact ID for that email address
false (bool) If no contact ID was found with that email address
$error (WP_Error object) If the API call failed

#get_tags()
wp_fusion()->crm->get_tags( $contact_id );
Loads a contact』s tags from the CRM.
Parameters:

$contact_id (int) The contact ID to load tags for

Return values:

$tags (array) An array of tag IDs for the contact (or an empty array if no tags were found)
$error (WP_Error object) If the API call failed

#apply_tags()
wp_fusion()->crm->apply_tags( $tags, $contact_id );
Applies one or more tags to a contact.
Parameters:

$tags (array) An array of tags to apply
$contact_id (int) The contact ID to apply the tags to

Return values:

true (bool) The tags were successfully removed
$error (WP_Error object) If the API call failed

#remove_tags()
wp_fusion()->crm->remove_tags( $tags, $contact_id );
Removes one or more tags to a contact.
Parameters:

$tags (array) An array of tags to remove
$contact_id (int) The contact ID to remove the tags from

Return values:

true (bool) The tags were successfully removed
$error (WP_Error object) If the API call failed

#add_contact()
wp_fusion()->crm->add_contact( $contact_data, $map_meta_fields = true );
Adds a new contact to the CRM.
Parameters:

$contact_data (array) An associative array containing the data for the new contact, with the WordPress field as the key and the data as the value, like array( 'user_email' => '[email protected]' );
$map_meta_fields (bool) If set to true, WP Fusion will convert the field keys from WordPress meta keys into the field names in the CRM. Set to false to bypass this conversion.

Return values:

$contact_id (int) The contact ID for the newly created contact
$error (WP_Error object) If the API call failed or the data was rejected

#update_contact()
wp_fusion()->crm->update_contact( $contact_id, $contact_data, $map_meta_fields = true );
Updates a contact in the CRM.
Parameters:

$contact_id (int) The contact ID to update
$contact_data (array) An associative array containing the update data, in the same format as add_contact();
$map_meta_fields (bool) If set to true, WP Fusion will convert the field keys from WordPress meta keys into the field names in the CRM. Set to false to bypass this conversion.

Return values:

true (bool) The contact was successfully updated
$error (WP_Error object) If the API call failed or the data was rejected

#load_contact()
wp_fusion()->crm->load_contact( $contact_id );
Loads the contact record for a contact ID and returns an associative array of WordPress field / value pairs, based on the WP Fusion 「Contact Field」 settings.
Parameters:

$contact_id (int) The contact to load

Return values:

$user_meta (array) Array containing the contact data
$error (WP_Error object) If the API call failed or the contact was not found

#load_contacts()
wp_fusion()->crm->load_contacts( $tag_id );
Searches the CRM for any contacts with the specified tag and returns an array of contact IDs.
Parameters:

$tag (int or string) The tag to search by

Return values:

$contact_ids (array) Array of contact IDs returned by the search. Will be an empty array if no results were found
$error (WP_Error object) If the API call failed

See the next section for more information on how to utilize WP Fusion』s core helper functions while interfacing with your CRM.

#Was this helpful?

Let us know if you liked the post. That』s the only way we can improve.

Yes

No