Skip to content

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.

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;
}

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): true by 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 ​

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 a default, a type and optional rules. Example: report_cache_ttl has default 600, type number and rules min: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 ​

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): true by 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'];
}

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): true when the click comes from a bot or a blocked IP address, otherwise false.
  • $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' );
}

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 as bot, crawler, curl and GPTBot. 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;
}

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 setting advanced.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;
}

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): true when the setting advanced.trust_proxy_headers is yes, otherwise false.

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 WordPress allowed_redirect_hosts filter. Hosts are compared in lowercase without a port or www..

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;
}

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): false by default.
  • $data (array): the post data being saved.
  • $postarr (array): the raw post array passed to wp_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'] ?? '' );
}

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): true by 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, or null for 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' );
}

The picker adds short links to the block editor link box, the classic editor and the REST search.

Turns the editor link picker on or off.

When it runs: whenever the picker loads or answers a search.

Parameters:

  • $enabled (bool): true by default.

Returns: (bool) false turns the picker off.

Source: app/Support/LinkPicker.php

Usage:

php
add_filter( 'link_manager_pro_picker_enabled', '__return_false' );

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_posts by 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';
}

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_posts by 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';
}

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, classic or rest.

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;
}

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;
}

Decides whether affiliate links appear in the picker.

When it runs: when the picker loads and on each affiliate search.

Parameters:

  • $include (bool): true by 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' );

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_affiliate or classic.

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;
}

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): newTab false, nofollow true, sponsored false.

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;
}

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 ​

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 setting advanced.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 splits a post's equity budget over its links. Earlier links get more.

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 setting link_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;
}

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 setting link_intelligence.equity_position_penalty divided 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 from link_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 ​

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/geoip inside the uploads folder. When the uploads folder is not available, it is inside wp-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';
}

Changes the address the country database is downloaded from.

When it runs: when the plugin downloads or updates the database.

Parameters:

  • $url (string): the download_url from the plugin's config/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 ​

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. openai is gpt-4o-mini, gemini is gemini-2.5-flash and anthropic is claude-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;
}

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 with value and label.

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;
}

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 from link_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;
}

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 contains flash, 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;
}

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 setting ai.rate_limit_max, 30 by default, for the analyze bucket. The test bucket, used by the connection test, is 10. The setting accepts 0 to 100000.
  • $bucket (string): analyze or test.

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;
}

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 setting ai.rate_limit_window, 300 by default, for analyze. The test bucket is 300. The setting accepts 1 to 86400.
  • $bucket (string): analyze or test.

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 ​

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 has page_title, menu_title, capability, menu_slug and callback. Slugs look like link-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'];
			}
		)
	);
}

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';
}

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';
}

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 with label and url. The keys are x, facebook, linkedin, whatsapp, telegram, reddit and email. The url holds {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;
}

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): false by default.
  • $level (string): info, warning or error.
  • $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;
}