Need to change how SaveTo Wishlist Pro behaves without editing the plugin? You can do it with WordPress hooks and the plugin’s REST API. This article lists the hooks and routes you can use, with the arguments each one passes and short PHP examples. Everything here applies to SaveTo Wishlist Pro 1.0.4.
Before you start
SaveTo Wishlist Pro runs on top of SaveTo Wishlist Lite, so both plugins must be active. Put your hook code in a small custom plugin or a must-use plugin, not in the SaveTo Wishlist Pro files, because plugin updates replace those files.
Every Pro hook name starts with stwpro_. The hooks for the free plugin are covered in How to extend SaveTo Wishlist with hooks and the REST API.
The hooks and filters below are listed with the arguments they pass. When you add a filter, set the accepted argument count to match, or WordPress only passes you the first argument. Return the first argument (or a changed copy of it) from every filter.
REST API routes
All SaveTo Wishlist Pro routes use the namespace saveto-wishlist-pro/v1, so the full URL looks like https://example.com/wp-json/saveto-wishlist-pro/v1/analytics/products-insight.
Who can call the routes
The analytics, automations, default wishlists and license routes serve the plugin’s own admin screens, and they may change. They only answer requests from a logged-in user who has the manage_options capability (administrators by default). Anyone else gets a 401 or 403 error. Send the request with a normal WordPress login session and a REST nonce, or with any other REST authentication method your site supports.
The analytics read routes, the automations routes and the license routes also have a rate limit per user. Read requests (GET) get 300 requests per minute. All other methods get 60 requests per minute. When you go over, the route returns a 429 error with the code rate_limit_exceeded. You can change the limits with the stwpro_api_rate_limit filter, covered below.
Analytics routes
The base path is /analytics.
| Route | Method | Who can call it | What it does |
|---|---|---|---|
/analytics/products-insight | GET | Administrators, rate limited | Returns most popular, trending and recently added products. Accepts period with the value 7days or 30days. The default is 7days. |
/analytics/category-brand-insight | GET | Administrators, rate limited | Returns category and brand insights. |
/analytics/engagement-insight | GET | Administrators, rate limited | Returns engagement insights for products. |
/analytics/timebased-trends | GET | Administrators, rate limited | Returns trends over time. Accepts range with the value 7days, 30days, 90days or 365days. The default is 30days. |
/analytics/customer-behavior | GET | Administrators, rate limited | Returns customer behavior insights, including top wishlisters and customer segments. |
/analytics/refresh | POST | Administrators | Clears the analytics caches. A user can refresh once every 30 seconds. A faster request returns a 429 error with the code cooldown_active. |
The analytics responses are cached for one hour by default. A successful call to /analytics/refresh clears the cache, so the next read returns fresh data.
This example reads the trending products for the last 30 days from the browser, in a script that runs on a WordPress admin screen:
wp.apiFetch( {
path: '/saveto-wishlist-pro/v1/analytics/products-insight?period=30days',
} ).then( ( data ) => {
console.log( data.most_popular, data.trending, data.recently_added );
} );
Automation routes
The base path is /automations. All four routes need an administrator and are rate limited.
| Route | Method | What it does |
|---|---|---|
/automations/get-automations | GET | Returns saved automations. Query parameters are used as filters. |
/automations/save-automation | POST | Creates or updates an automation. It reads id, trigger_type, action_type, status, description and action_data. |
/automations/delete-automation | DELETE | Deletes the automation with the ID in the id parameter. Returns a 400 error when the ID is empty. |
/automations/send-test-email | POST | Sends a test email with dummy data. It reads email_to, email_subject and email_body. |
Default wishlists routes
The base path is /default-wishlists. All routes need an administrator.
| Route | Method | What it does |
|---|---|---|
/default-wishlists/settings | GET, POST | Reads or saves the default wishlist settings. The POST request reads the list parameter. |
/default-wishlists/migration-status | GET | Returns the progress of the job that creates default wishlists for existing users who have none, and how many users are still eligible. |
/default-wishlists/start-migration | POST | Starts that job. |
/default-wishlists/cancel-migration | POST | Cancels that job. |
Webhook route
The route /webhook/wishlist-created is different from the others. It does not use a WordPress login. It uses the webhook API key, sent in the x-api-key header or the api_key query parameter, and it answers 401 when the key is missing or wrong. A POST request fires the stwpro_wishlist_created action. A GET request with a wishlist_id parameter returns a public, published wishlist. For setup and security details, read How to connect external tools using wishlist webhooks and How to secure the SaveTo Wishlist Pro webhook API endpoint.
Filters for the route permissions
| Filter | Arguments | What it does |
|---|---|---|
stwpro_api_admin_permissions_check | $response, $request | Filters the result of the administrator check on the admin-only routes. Return true to allow, or a WP_Error to deny. |
stwpro_webhook_permissions_check | $response, $request | Filters the result of the API key check on the webhook route. |
stwpro_api_rate_limit | $limit, $request, $is_read | Sets the requests allowed per minute. The defaults are 300 for read requests and 60 for the rest. |
stwpro_api_rate_limit_check | $result, $request | Filters the final result of the rate limit check. |
For example, this raises the write limit to 120 requests per minute:
add_filter( 'stwpro_api_rate_limit', function ( $limit, $request, $is_read ) {
return $is_read ? $limit : 120;
}, 10, 3 );
Automation hooks
Automations connect a trigger, such as a product going on sale, to an action, such as sending an email. These hooks let you add your own actions and change what the built-in actions send.
Add your own automation action
Two filters work together. Use stwpro_automation_actions to add your action to the list of actions, and use stwpro_automation_action_handlers to say which function runs it. The built-in action types are send_email, call_webhook and update_user_meta.
| Filter | Arguments | What it does |
|---|---|---|
stwpro_automation_actions | $actions | Filters the list of action types. Each item is an action key and its label. |
stwpro_automation_action_handlers | $handlers | Filters the map of action type to handler. The handler must be callable. If your callback returns something other than an array, the plugin ignores it and keeps the built-in handlers. |
WordPress calls your handler with five arguments: the active automations of that type for the trigger, the automation data, the trigger context object, a boolean for the product category condition, and an array of extra parameters.
add_filter( 'stwpro_automation_actions', function ( $actions ) {
$actions['send_to_crm'] = __( 'Send to my CRM', 'my-plugin' );
return $actions;
} );
add_filter( 'stwpro_automation_action_handlers', function ( $handlers ) {
$handlers['send_to_crm'] = 'my_plugin_process_crm_automations';
return $handlers;
} );
function my_plugin_process_crm_automations( $automations, $automation_data, $context_data, $category_condition, $params ) {
foreach ( $automations as $automation ) {
// Send $automation_data to your CRM here.
}
}
Change who receives an automation email
Two filters set the email recipient. stwpro_automation_filter_email_to_customer runs once per wishlist owner for the product on sale and product back in stock triggers. stwpro_automation_filter_email_to runs for every other trigger. With both filters, an empty or invalid address skips the email.
| Filter | Arguments |
|---|---|
stwpro_automation_filter_email_to | $email_to, $action_data, $context_data, $data, $params |
stwpro_automation_filter_email_to_customer | $email_to, $action_data, $per_customer_data, $context_data, $params |
This example sends every automation email to a test address on a staging site, and skips customers who opted out:
add_filter( 'stwpro_automation_filter_email_to', function ( $email_to ) {
if ( 'production' !== wp_get_environment_type() ) {
return 'dev@example.com';
}
return $email_to;
}, 10, 1 );
add_filter( 'stwpro_automation_filter_email_to_customer', function ( $email_to, $action_data, $per_customer_data ) {
$customer_id = (int) ( $per_customer_data['customer_id'] ?? 0 );
if ( $customer_id && get_user_meta( $customer_id, 'no_wishlist_alerts', true ) ) {
return '';
}
return $email_to;
}, 10, 3 );
Change automation content and data
These four filters pass the value you filter first. The next arguments are the automation record, the action settings, the trigger context, the resolved variable data and the extra parameters. They run before the plugin replaces the variable tags, so your changes can still contain tags such as {customer_name}.
| Filter | Arguments | What it filters |
|---|---|---|
stwpro_automation_email_subject_template | $subject_template, $automation, $action_data, $context_data, $data, $params | The raw email subject. |
stwpro_automation_email_message_template | $message_template, $automation, $action_data, $context_data, $data, $params | The raw email message. |
stwpro_automation_webhook_payload_template | $payload_template, $automation, $action_data, $context_data, $data, $params | The raw webhook payload. |
stwpro_automation_usermeta_meta_value_template | $meta_value, $automation, $action_data, $context_data, $data, $params | The raw value for the update user meta action. |
Three more filters have their own arguments:
| Filter | Arguments | What it filters |
|---|---|---|
stwpro_automation_variables | $trigger_variables, $trigger_type | The variable tags available for a trigger. |
stwpro_automation_webhook_recipes | $recipes | The webhook quick-start recipes. |
stwpro_automations_get_all_automations | $automations, $trigger_type, $action_type | The active automations for a trigger and action type. |
For the variable data of each trigger, use one of these filters. They all pass $variable_data, $trigger_type, $context_data.
stwpro_automation_data_wishlist_createdstwpro_automation_data_item_added_to_wishliststwpro_automation_data_item_removed_from_wishliststwpro_automation_data_product_on_salestwpro_automation_data_product_back_in_stock
Analytics hooks
Customer tier and segment thresholds
The customer analytics put each top wishlister into a tier. A customer reaches a tier when both numbers are met: the wishlist count and the total amount spent. The plugin checks the tiers from platinum down to bronze, and customers who meet none are regular. Each filter takes one argument, the default value, and returns a number.
| Tier | Wishlist count filter | Default | Spent filter | Default |
|---|---|---|---|---|
| Platinum | stwpro_admin_platinum_threshold | 8 | stwpro_admin_platinum_spent_threshold | 1500 |
| Gold | stwpro_admin_gold_threshold | 5 | stwpro_admin_gold_spent_threshold | 800 |
| Silver | stwpro_admin_silver_threshold | 3 | stwpro_admin_silver_spent_threshold | 400 |
| Bronze | stwpro_admin_bronze_threshold | 2 | stwpro_admin_bronze_spent_threshold | 200 |
add_filter( 'stwpro_admin_platinum_threshold', function () {
return 10;
} );
add_filter( 'stwpro_admin_platinum_spent_threshold', function () {
return 2500;
} );
Other analytics filters change the customer segments and the lists shown on the analytics screens:
| Filter | Arguments | Default | What it does |
|---|---|---|---|
stwpro_admin_vip_threshold | $value | 5 | Wishlist count for the VIP customers segment. |
stwpro_admin_vip_spent_threshold | $value | 800 | Total spent for the VIP customers segment. |
stwpro_admin_inactive_days | $value | 90 | Days without activity before a customer counts as inactive. |
stwpro_admin_top_wishlisters_limit | $limit | 15 | How many customers the top wishlisters list returns. |
stwpro_admin_top_wishlisters_excluded_roles | $excluded_roles | array( 'administrator', 'shop_manager' ) | Roles left out of the top wishlisters list. |
stwpro_admin_customer_segments | $segments, $total_customers | None | The final list of customer segments. |
Analytics data, cache and refresh
| Hook | Type and arguments | What it does |
|---|---|---|
stwpro_analytics_products_insight_data | Filter: $products_insight, $request | Changes the data the products-insight route returns. |
stwpro_analytics_products_insight_cache_duration | Filter: $seconds | Sets how long that response is cached. The default is one hour. The category and brand, engagement, time-based trends and customer behavior routes have matching filters: stwpro_analytics_category_brand_insight_cache_duration, stwpro_analytics_engagement_insight_cache_duration, stwpro_analytics_timebased_trends_cache_duration and stwpro_analytics_customer_behavior_cache_duration. |
stwpro_analytics_refresh_cooldown | Filter: $seconds | Sets the seconds a user waits between refreshes. The default is 30. Return 0 to turn the wait off. |
stwpro_analytics_refreshed | Action: $timestamp | Runs after a refresh clears the caches. Use it to rebuild your own derived data. |
The thresholds above are read when the analytics are calculated. If you change one and the screen does not change, refresh the analytics so the cached results are rebuilt.
Default wishlists hooks
These hooks control the wishlists that Pro creates automatically for new users.
| Hook | Type and arguments | What it does |
|---|---|---|
stwpro_default_wishlists_sync_threshold | Filter: $threshold | If the configured list has more wishlists than this number, Pro creates them in the background with Action Scheduler instead of during registration. The default is 3. |
stwpro_default_wishlists_max_entries | Filter: $max | The most default wishlists you can save in the list. The default is 20. |
stwpro_after_seed_default_wishlists | Action: $user_id, $created, $list | Runs after a user receives the default wishlists. $created is the number of wishlists created. It does not run when none were created. |
add_action( 'stwpro_after_seed_default_wishlists', function ( $user_id, $created, $list ) {
update_user_meta( $user_id, 'default_wishlists_created', $created );
}, 10, 3 );
Other hooks
| Hook | Type and arguments | What it does |
|---|---|---|
stwpro_wholesale_price | Filter: $price, $product_id, $user, $user_wholesale_role | Lets another wholesale plugin supply the wholesale price. Return a float to skip the Wholesale Prices lookup. Return false to use the default lookup. |
stwpro_disable_abilities | Filter: $disabled | Return true to stop Pro from registering its abilities. You can also define the constant STWPRO_DISABLE_ABILITIES as true. |
stwpro_show_powered_by_in_email | Filter: $show | Return false to remove the “Powered by SaveTo Wishlist” line from emails sent by Pro. |
stwpro_wishlist_created | Action: $wishlist_data, $wishlist_items | Runs when a valid POST request reaches the webhook route /webhook/wishlist-created. |
add_filter( 'stwpro_show_powered_by_in_email', '__return_false' );
Frequently asked questions
Can I call the analytics or automations routes from outside WordPress?
Only as a logged-in administrator. These routes check for the manage_options capability and serve the plugin’s own screens, so build on the hooks above for anything that must stay stable. For outside systems, use the webhook route with its API key.
Why do my threshold changes not show on the analytics screen?
The analytics results are cached, for one hour by default. Refresh the analytics, or shorten the cache with the cache duration filters, and the new thresholds apply.
Need help?
If you have a question or run into any issues, we’re here to help.
- Premium users: Open a support ticket
- Free users: Visit our community forum
