Appearance
Filter hooks
Link Manager Pro has 37 filter hooks. Each entry says what it changes, its default value and the range the plugin accepts.
They cover tracking, redirects, the editor link picker, report caching, Link Equity, GeoIP, AI and the admin menu. Each filter returns the same type it receives.
Add the code to your own plugin or a must-use plugin. See Use a hook for priority and argument rules.
Lifecycle
These two filters run while the plugin file loads. Register them in a must-use plugin, because a normal plugin that loads later is too late.
link_manager_pro_providers
Lets you add, remove or replace the plugin's service providers.
When it runs: while the plugin loads, before any provider is registered.
Parameters:
$providers(string[]): provider class names. The default holds six: database, app, route, admin, hook and console providers.
Returns: (string[]) the providers to register, in order.
Source: bootstrap/app.php
WARNING
Removing or reordering a provider can break redirects, the REST API, the admin screen or the database connection. The providers depend on the order they boot in. Only append your own provider.
Usage:
php
// wp-content/mu-plugins/myprefix-lmp.php
add_filter( 'link_manager_pro_providers', 'myprefix_add_provider' );
function myprefix_add_provider( array $providers ): array {
$providers[] = \MyPrefix\LmpProvider::class;
return $providers;
}link_manager_pro_migration_self_heal
Turns off the automatic database update that runs when the plugin version changes.
When it runs: on every load of the plugin, before it compares the stored version with the plugin version.
Parameters:
$enabled(bool):trueby default.
Returns: (bool) false skips the automatic update.
Source: app/Providers/DatabaseServiceProvider.php
WARNING
With false, a plugin update leaves the tables on the old schema until you run wp link-manager-pro migrate. Until then, new code can run against old tables. See WP-CLI for developers.
Usage:
php
// wp-content/mu-plugins/myprefix-lmp.php
add_filter( 'link_manager_pro_migration_self_heal', '__return_false' );Settings
link_manager_pro_settings_schema
Lets you add or change settings groups, keys, defaults and validation rules.
When it runs: the first time a setting is read or written in a request. Register it in a must-use plugin.
Parameters:
$schema(array): groups, each an array of setting keys. Every key has adefault, atypeand optionalrules. Example:report_cache_ttlhas default600, typenumberand rulesmin:0|max:86400.
Returns: (array) the schema to use for the whole request.
Source: app/Services/Settings/SettingsManager.php
WARNING
The schema decides which settings exist and how values are sanitized. Saving a group or key that is missing from the schema does nothing, and a wrong type or rules entry changes how values are checked. Only add keys; do not edit the built-in ones.
Usage:
php
// wp-content/mu-plugins/myprefix-lmp.php
add_filter( 'link_manager_pro_settings_schema', 'myprefix_schema' );
function myprefix_schema( array $schema ): array {
$schema['advanced']['report_cache_ttl']['default'] = 1800;
return $schema;
}Redirects and clicks
link_manager_pro_cookie_consent
Tells the plugin whether the visitor allows its tracking cookie.
When it runs: each time the plugin reads the tracking cookie. A consent plugin integration also uses this filter.
Parameters:
$allowed(bool):trueby default.
Returns: (bool) false stops the plugin from using the visitor's cookie ID.
Source: app/Services/Analytics/ClickService.php
Usage:
php
add_filter( 'link_manager_pro_cookie_consent', 'myprefix_consent' );
function myprefix_consent( bool $allowed ): bool {
return isset( $_COOKIE['myprefix_consent'] ) && 'yes' === $_COOKIE['myprefix_consent'];
}link_manager_pro_skip_filtered_click_count
Decides whether a click is left out of the link's click count.
When it runs: on every short link redirect, before the click is counted.
Parameters:
$skip(bool):truewhen the click comes from a bot or a blocked IP address, otherwisefalse.$link_id(int): the link ID.
Returns: (bool) true leaves the click uncounted and fires no click event. Return the same answer all through one request.
Source: app/Services/Analytics/ClickService.php
Usage:
php
add_filter( 'link_manager_pro_skip_filtered_click_count', 'myprefix_skip_staff', 10, 2 );
function myprefix_skip_staff( bool $skip, int $link_id ): bool {
return $skip || current_user_can( 'edit_posts' );
}link_manager_pro/bot_patterns
Changes the built-in list of user-agent texts counted as bots.
When it runs: when the plugin needs the built-in list. The list is not used when you enter your own patterns in the tracking settings.
Parameters:
$patterns(string[]): the 48 built-in texts, such asbot,crawler,curlandGPTBot. Matching ignores case and looks for the text anywhere in the user agent.
Returns: (string[]) the list to use. Entries that are not non-empty strings are removed. A non-array falls back to the built-in list.
Source: app/Services/Analytics/ClickService.php
Usage:
php
add_filter( 'link_manager_pro/bot_patterns', 'myprefix_bot_patterns' );
function myprefix_bot_patterns( array $patterns ): array {
$patterns[] = 'MyMonitorBot';
return $patterns;
}link_manager_pro_trusted_proxies
Sets the proxy IP addresses whose forwarded headers the plugin believes.
When it runs: each time the plugin finds the visitor's IP address or decides whether to trust forwarded headers.
Parameters:
$proxies(string[]): IP addresses or CIDR ranges. The default is the Trusted proxy IPs or CIDR ranges settingadvanced.trusted_proxies, split on new lines and commas.
Returns: (string[]) the trusted list. When it is not empty, headers are trusted only if the request comes from a listed address. When it is empty, link_manager_pro_trust_proxy_headers decides. A non-array counts as empty.
Source: app/Support/LinkHelper.php
Usage:
php
add_filter( 'link_manager_pro_trusted_proxies', 'myprefix_proxies' );
function myprefix_proxies( array $proxies ): array {
$proxies[] = '10.0.0.0/8';
return $proxies;
}link_manager_pro_trust_proxy_headers
Decides whether to trust headers such as X-Forwarded-For when no trusted proxy list is set.
When it runs: when the trusted proxy list is empty.
Parameters:
$trust(bool):truewhen the settingadvanced.trust_proxy_headersisyes, otherwisefalse.
Returns: (bool) true trusts the forwarded headers from any address.
Source: app/Support/LinkHelper.php
Usage:
php
add_filter( 'link_manager_pro_trust_proxy_headers', '__return_true' );link_manager_pro_post_credit_hosts
Lists the sites whose pages can credit a click to a post.
When it runs: on a short link redirect whose address carries a pid source post and a referrer. A click from a host not in the list is not credited to the post. A request with no referrer keeps the credit.
Parameters:
$hosts(string[]): your home and site hosts plus the hosts from the WordPressallowed_redirect_hostsfilter. Hosts are compared in lowercase without a port orwww..
Returns: (string[]) the allowed hosts. Entries that are not strings are removed.
Source: app/Http/Controllers/RedirectController.php
Usage:
php
add_filter( 'link_manager_pro_post_credit_hosts', 'myprefix_credit_hosts' );
function myprefix_credit_hosts( array $hosts ): array {
$hosts[] = 'app.example.com';
return $hosts;
}link_manager_pro_disable_auto_mask
Stops the plugin from turning links into short links when a post is saved.
When it runs: on wp_insert_post_data, before the check of the setting general.auto_mask_on_save.
Parameters:
$disable(bool):falseby default.$data(array): the post data being saved.$postarr(array): the raw post array passed towp_insert_post().
Returns: (bool) true skips masking for this save.
Source: app/Providers/AppServiceProvider.php
Usage:
php
add_filter( 'link_manager_pro_disable_auto_mask', 'myprefix_no_mask_pages', 10, 2 );
function myprefix_no_mask_pages( bool $disable, array $data ): bool {
return $disable || 'page' === ( $data['post_type'] ?? '' );
}link_manager_pro_mask_url
Decides whether one link in post content becomes a short link.
When it runs: for each link that masking is about to convert, before any short link is created or reused. Our own short links, internal links (unless Mask internal links is on) and URLs a block keeps in its attributes never reach it.
Parameters:
$mask(bool):trueby default.$destination(string): the link's URL as the browser requests it, with HTML entities such as&decoded.$post_id(int|null): the post being masked, ornullfor a post that has no ID yet.
Returns: (bool) false leaves the link exactly as written and makes no short link. Links that are already masked stay masked.
Source: app/Services/Content/LinkMaskerService.php
Usage:
php
add_filter( 'link_manager_pro_mask_url', 'myprefix_keep_partner_links', 10, 2 );
function myprefix_keep_partner_links( bool $mask, string $destination ): bool {
return $mask && false === strpos( $destination, 'partner.example.com' );
}Editor link picker
The picker adds short links to the block editor link box, the classic editor and the REST search.
link_manager_pro_picker_enabled
Turns the editor link picker on or off.
When it runs: whenever the picker loads or answers a search.
Parameters:
$enabled(bool):trueby default.
Returns: (bool) false turns the picker off.
Source: app/Support/LinkPicker.php
Usage:
php
add_filter( 'link_manager_pro_picker_enabled', '__return_false' );link_manager_pro_picker_capability
Sets the capability a user needs to use the picker.
When it runs: on every picker search and when the picker loads.
Parameters:
$capability(string):edit_postsby default.
Returns: (string) a capability name. An empty string blocks everyone.
Source: app/Support/LinkPicker.php
Usage:
php
add_filter( 'link_manager_pro_picker_capability', 'myprefix_picker_cap' );
function myprefix_picker_cap( string $capability ): string {
return 'publish_posts';
}link_manager_pro_picker_create_capability
Sets the capability a user needs to create a short link from the picker.
When it runs: when the editor tools load, and on a request to create a short link from the editor.
Parameters:
$capability(string):publish_postsby default.
Returns: (string) a capability name. An empty string means only users with full plugin access can create. Users with full plugin access can always create. Searching and inserting existing short links stays on link_manager_pro_picker_capability.
Source: app/Support/LinkPicker.php
Usage:
php
add_filter( 'link_manager_pro_picker_create_capability', 'myprefix_picker_create_cap' );
function myprefix_picker_create_cap( string $capability ): string {
return 'edit_posts';
}link_manager_pro_picker_per_page
Sets how many results the picker shows per search.
When it runs: each time the picker loads or searches.
Parameters:
$per_page(int): 5 in the block editor, 10 in the classic editor and in the REST search.$context(string):gutenberg,classicorrest.
Returns: (int) the number of results. The plugin keeps it between 1 and 20. A REST request that sends its own per_page skips this filter.
Source: app/Support/LinkPicker.php
Usage:
php
add_filter( 'link_manager_pro_picker_per_page', 'myprefix_per_page', 10, 2 );
function myprefix_per_page( int $per_page, string $context ): int {
return 'gutenberg' === $context ? 8 : $per_page;
}link_manager_pro_picker_excluded_statuses
Chooses which links the picker hides because of their access status.
When it runs: on each picker search.
Parameters:
$statuses(string[]):['expired']by default.
Returns: (string[]) any of expired, scheduled and password. Other values are removed. An empty array hides none. Hidden Simple Redirect links stay hidden whatever you return.
Source: app/Support/LinkPicker.php
Usage:
php
add_filter( 'link_manager_pro_picker_excluded_statuses', 'myprefix_hide_protected' );
function myprefix_hide_protected( array $statuses ): array {
$statuses[] = 'password';
return $statuses;
}link_manager_pro_picker_include_affiliates
Decides whether affiliate links appear in the picker.
When it runs: when the picker loads and on each affiliate search.
Parameters:
$include(bool):trueby default.
Returns: (bool) false removes affiliates from the picker.
Source: app/Support/LinkPicker.php
Usage:
php
add_filter( 'link_manager_pro_picker_include_affiliates', '__return_false' );link_manager_pro_picker_item
Changes one result before the picker shows it.
When it runs: for each result in the REST search, the affiliate search and the classic editor search.
Parameters:
$item(array): the prepared result.$link(object): the link, or for affiliates the affiliate record.$context(string):rest,rest_affiliateorclassic.
Returns: (array) the result to show. A non-array is ignored and the original is used.
Source: app/Support/LinkPicker.php
Usage:
php
add_filter( 'link_manager_pro_picker_item', 'myprefix_picker_item', 10, 3 );
function myprefix_picker_item( array $item, $link, string $context ): array {
return $item;
}link_manager_pro_picker_toolbar_defaults
Sets the link options that start ticked when an editor inserts a short link.
When it runs: when the block editor toolbar, the classic editor picker and the AI box load.
Parameters:
$defaults(array):newTabfalse,nofollowtrue,sponsoredfalse.
Returns: (array) the same keys with your values.
Source: app/Hooks/Handlers/LinkPickerHandler.php, app/Hooks/Handlers/AiAssistantMetaBoxHandler.php
Usage:
php
add_filter( 'link_manager_pro_picker_toolbar_defaults', 'myprefix_toolbar_defaults' );
function myprefix_toolbar_defaults( array $defaults ): array {
$defaults['newTab'] = true;
return $defaults;
}link_manager_pro_picker_debounce_ms
Sets how long the picker waits after typing before it searches.
When it runs: when the picker loads in the editor.
Parameters:
$ms(int): 250 by default.
Returns: (int) milliseconds. A negative value becomes 0.
Source: app/Hooks/Handlers/LinkPickerHandler.php
Usage:
php
add_filter( 'link_manager_pro_picker_debounce_ms', 'myprefix_debounce' );
function myprefix_debounce( int $ms ): int {
return 400;
}Caching
link_manager_pro_report_cache_ttl
Sets how long short link and affiliate reports stay cached. A link report with no clicks is never cached. An affiliate report with no clicks is capped at 60 seconds.
When it runs: each time a short link or affiliate report is built.
Parameters:
$ttl(int): seconds. The default is the settingadvanced.report_cache_ttl, 600 when unset. The setting accepts 0 to 86400.
Returns: (int) seconds. 0 or less turns report caching off.
Source: app/Services/Analytics/ReportService.php
Usage:
php
add_filter( 'link_manager_pro_report_cache_ttl', 'myprefix_report_ttl' );
function myprefix_report_ttl( int $ttl ): int {
return 60;
}Link Equity
Link Equity splits a post's equity budget over its links. Earlier links get more.
link_manager_pro_link_equity_budget
Sets the equity budget each post spreads over its links.
When it runs: at the start of each Link Equity scan.
Parameters:
$budget(float): the settinglink_intelligence.equity_budget, 100 by default. The setting accepts 1 to 10000.
Returns: (float) the budget per post.
Source: app/Services/Analytics/LinkEquityService.php
Usage:
php
add_filter( 'link_manager_pro_link_equity_budget', 'myprefix_equity_budget' );
function myprefix_equity_budget( float $budget ): float {
return 200.0;
}link_manager_pro_link_equity_position_penalty
Sets how much less equity later links in a post receive.
When it runs: at the start of each Link Equity scan.
Parameters:
$penalty(float): a fraction, not a percent. The default is the settinglink_intelligence.equity_position_penaltydivided by 100, so 0.5 by default.
Returns: (float) the penalty. The plugin keeps it between 0.0 and 1.0.
Source: app/Services/Analytics/LinkEquityService.php
Usage:
php
add_filter( 'link_manager_pro_link_equity_position_penalty', 'myprefix_penalty' );
function myprefix_penalty( float $penalty ): float {
return 0.25;
}link_manager_pro_link_equity_post_budget
Sets the equity budget for one post.
When it runs: for each post that has links, during a scan.
Parameters:
$budget(float): the budget fromlink_manager_pro_link_equity_budget.$post_id(int): the post ID.
Returns: (float) the budget for this post.
Source: app/Services/Analytics/LinkEquityService.php
Usage:
php
add_filter( 'link_manager_pro_link_equity_post_budget', 'myprefix_post_budget', 10, 2 );
function myprefix_post_budget( float $budget, int $post_id ): float {
return 'page' === get_post_type( $post_id ) ? $budget * 2 : $budget;
}GeoIP
link_manager_pro_geoip_dir
Moves the folder that holds the downloaded country database.
When it runs: each time the plugin needs the database path.
Parameters:
$dir(string):link-manager-pro/geoipinside the uploads folder. When the uploads folder is not available, it is insidewp-content.
Returns: (string) an absolute folder path without a trailing slash.
Source: app/Services/CountryResolver/GeoIpDatabaseManager.php
Usage:
php
add_filter( 'link_manager_pro_geoip_dir', 'myprefix_geoip_dir' );
function myprefix_geoip_dir( string $dir ): string {
return WP_CONTENT_DIR . '/private/geoip';
}link_manager_pro_geoip_download_url
Changes the address the country database is downloaded from.
When it runs: when the plugin downloads or updates the database.
Parameters:
$url(string): thedownload_urlfrom the plugin'sconfig/geoip.php.
Returns: (string) an https:// URL. The downloaded file must match the checksum pinned in config/geoip.php, or the plugin refuses it. Use this only for a mirror of the same file.
Source: app/Services/CountryResolver/GeoIpDatabaseManager.php
Usage:
php
add_filter( 'link_manager_pro_geoip_download_url', 'myprefix_geoip_url' );
function myprefix_geoip_url( string $url ): string {
return 'https://example.com/files/country.mmdb';
}AI
link_manager_pro_ai_default_models
Sets the model each AI provider uses when you have not chosen one.
When it runs: when a provider looks up its default model.
Parameters:
$models(array): provider to model.openaiisgpt-4o-mini,geminiisgemini-2.5-flashandanthropicisclaude-haiku-4-5-20251001.
Returns: (array) the same shape.
Source: app/Services/Ai/Providers/DefaultModels.php
Usage:
php
add_filter( 'link_manager_pro_ai_default_models', 'myprefix_ai_defaults' );
function myprefix_ai_defaults( array $models ): array {
$models['openai'] = 'gpt-4o';
return $models;
}link_manager_pro_ai_models
Changes the model lists shown in the AI settings dropdown.
When it runs: when the AI settings load, and when the plugin checks that a saved model belongs to the chosen provider. link_manager_pro_ai_models_{provider} runs right after it.
Parameters:
$catalog(array): provider (openai,gemini,anthropic) to a list of arrays, each withvalueandlabel.
Returns: (array) the same shape. A non-array gives an empty list.
Source: app/Services/Ai/Providers/DefaultModels.php
Usage:
php
add_filter( 'link_manager_pro_ai_models', 'myprefix_ai_models' );
function myprefix_ai_models( array $catalog ): array {
$catalog['openai'][] = array(
'value' => 'my-custom-model',
'label' => 'My custom model',
);
return $catalog;
}link_manager_pro_ai_models_{provider}
Changes the model list for one provider.
When it runs: inside DefaultModels::catalog(), right after link_manager_pro_ai_models, once for each provider key. Its result feeds the model dropdown in the AI settings and the check that a saved model belongs to the chosen provider.
Parameters:
$list(array): the provider's list fromlink_manager_pro_ai_models.$provider(string): the provider name.
The provider part is every key in the catalog: openai, gemini and anthropic, plus any provider you add through link_manager_pro_ai_models. A provider you add gets its own filter.
Returns: (array) a list of arrays with value and label. Entries without a value are removed.
Source: app/Services/Ai/Providers/DefaultModels.php
Usage:
php
add_filter( 'link_manager_pro_ai_models_openai', 'myprefix_openai_models', 10, 2 );
function myprefix_openai_models( array $list, string $provider ): array {
return $list;
}link_manager_pro_ai_gemini_thinking_budget
Sets how many tokens Gemini may spend thinking before it answers.
When it runs: each time the plugin builds a Gemini request.
Parameters:
$budget(int): 0 for models whose name containsflash, otherwise -1.$model(string): the model name.
Returns: (int) the budget. A value of 0 or more is sent as thinkingBudget. A negative value sends none.
Source: app/Services/Ai/Providers/GeminiProvider.php
Usage:
php
add_filter( 'link_manager_pro_ai_gemini_thinking_budget', 'myprefix_thinking', 10, 2 );
function myprefix_thinking( int $budget, string $model ): int {
return $budget;
}link_manager_pro_ai_rate_max
Sets how many AI requests one user can make in the time window.
When it runs: before each AI request that the plugin sends to a provider.
Parameters:
$max(int): the settingai.rate_limit_max, 30 by default, for theanalyzebucket. Thetestbucket, used by the connection test, is 10. The setting accepts 0 to 100000.$bucket(string):analyzeortest.
Returns: (int) the limit. 0 or less turns the limit off.
Source: app/Support/AiRateLimiter.php
Usage:
php
add_filter( 'link_manager_pro_ai_rate_max', 'myprefix_ai_max', 10, 2 );
function myprefix_ai_max( int $max, string $bucket ): int {
return 'analyze' === $bucket ? 60 : $max;
}link_manager_pro_ai_rate_window
Sets the length of the AI rate limit window in seconds.
When it runs: after link_manager_pro_ai_rate_max, unless the limit is off.
Parameters:
$window(int): the settingai.rate_limit_window, 300 by default, foranalyze. Thetestbucket is 300. The setting accepts 1 to 86400.$bucket(string):analyzeortest.
Returns: (int) seconds.
Source: app/Support/AiRateLimiter.php
Usage:
php
add_filter( 'link_manager_pro_ai_rate_window', 'myprefix_ai_window' );
function myprefix_ai_window( int $window ): int {
return 600;
}Admin and logging
link_manager_pro/menu_items
Adds, removes or changes the plugin's submenu items in the WordPress admin menu.
When it runs: on admin_menu, after the main Link Manager menu is added.
Parameters:
$items(array[]): six items (Dashboard, Short Links, Campaigns, Affiliates, Link Intelligence and Settings). Each haspage_title,menu_title,capability,menu_slugandcallback. Slugs look likelink-manager-pro#/links.
Returns: (array[]) items that keep all five keys. A missing key causes a PHP warning.
Source: app/Providers/AdminServiceProvider.php
Usage:
php
add_filter( 'link_manager_pro/menu_items', 'myprefix_menu_items' );
function myprefix_menu_items( array $items ): array {
return array_values(
array_filter(
$items,
static function ( array $item ): bool {
return 'Campaigns' !== $item['menu_title'];
}
)
);
}link_manager_pro_docs_url
Changes the Docs link in the plugin's row on the Plugins screen.
When it runs: when the Plugins screen builds the row links.
Parameters:
$url(string):https://docs.linkmanagerpro.com.
Returns: (string) a URL.
Source: app/Hooks/Handlers/PluginActionLinks.php
Usage:
php
add_filter( 'link_manager_pro_docs_url', 'myprefix_docs_url' );
function myprefix_docs_url( string $url ): string {
return 'https://example.com/help';
}link_manager_pro_support_url
Changes the Support link in the plugin's row on the Plugins screen.
When it runs: when the Plugins screen builds the row links.
Parameters:
$url(string):https://support.solvixstudio.com.
Returns: (string) a URL.
Source: app/Hooks/Handlers/PluginActionLinks.php
Usage:
php
add_filter( 'link_manager_pro_support_url', 'myprefix_support_url' );
function myprefix_support_url( string $url ): string {
return 'https://example.com/support';
}link_manager_pro_social_share_platforms
Changes the share buttons on a short link's details page.
When it runs: when the details page loads.
Parameters:
$platforms(array): key to an array withlabelandurl. The keys arex,facebook,linkedin,whatsapp,telegram,redditandemail. Theurlholds{url}and{text}placeholders.
Returns: (array) the same shape. Entries whose url does not start with https:// or mailto: are dropped. A non-array gives no buttons.
Source: app/Support/SocialShare.php
Usage:
php
add_filter( 'link_manager_pro_social_share_platforms', 'myprefix_share' );
function myprefix_share( array $platforms ): array {
$platforms['mastodon'] = array(
'label' => 'Mastodon',
'url' => 'https://example.com/share?text={text}%20{url}',
);
return $platforms;
}link_manager_pro_logger_suppress
Stops the plugin from writing a line to the PHP error log.
When it runs: each time the plugin logs a message.
Parameters:
$suppress(bool):falseby default.$level(string):info,warningorerror.$component(string): the part of the plugin that logs.$event(string): the message.$context(array): extra values.
Returns: (bool) true skips the line.
Source: app/Support/Logger.php
Usage:
php
add_filter( 'link_manager_pro_logger_suppress', 'myprefix_quiet_logs', 10, 2 );
function myprefix_quiet_logs( bool $suppress, string $level ): bool {
return $suppress || 'info' === $level;
}