sanitize_url( string $url, string[] $protocols = null ): string
- Since
- 2.3.1, 2.8.0, 5.9.0
- Source
wp-includes/formatting.php:4611
Cleans a URL for storage or redirection by running it through esc_url() with the 'db' context instead of the default display context. Use it when a URL is headed into the database, post meta, an option, or a Location header, not when it's about to be echoed into HTML markup. For markup output, esc_url() itself remains the right call because it entity-encodes ampersands for valid HTML.
Compatibility
- WordPress
- since 5.9.0
- PHP
- 7.4–8.6-dev
- 6.7.7
- 6.8.8
- 6.9.7
- 7.0.4
- 7.1.0
Present in every tracked release (6.7.7 to 7.1.0), and compiles on PHP 7.4 through 8.6-dev.
Parameters
$urlstring- The URL to be cleaned.
$protocolsstring[]optional- An array of acceptable protocols.
Defaults to return value of wp_allowed_protocols().Default:null
Return value
string- The cleaned URL after esc_url() is run with the 'db' context.
Code examples
Every example is editable and runs in a real WordPress booted in your browser by WordPress Playground. Press Run, then edit the code: clicking away re-runs it. Nothing is sent anywhere until you do.
Sanitize a URL before saving it as post meta
Post 2 already carries a price meta value, so add a related external link field to it and clean the incoming URL before storing it.
$raw_link = 'http://example.com/product?id=2&ref=<script>alert(1)</script>';
$clean_link = sanitize_url( $raw_link );
update_post_meta( 2, 'external_link', $clean_link );
echo esc_html( 'Stored meta value: ' . $clean_link );The stripped script tag disappears because esc_url() rejects disallowed characters and protocols before the value ever reaches the database.
Restrict a redirect URL to a limited set of protocols
Build a safe redirect target for a login-like flow where only http and https links should ever be honored.
$requested_url = 'javascript:alert(document.cookie)';
$safe_url = sanitize_url( $requested_url, array( 'http', 'https' ) );
if ( empty( $safe_url ) ) {
echo esc_html( 'Redirect blocked: no allowed protocol found in the submitted URL.' );
} else {
echo esc_html( 'Redirecting to: ' . $safe_url );
}Passing a custom $protocols array replaces the full default list from wp_allowed_protocols(), so it must include every scheme the redirect legitimately needs.
Common problems and fixes · 3
- Why does sanitize_url() encode ampersands differently than esc_url()?
- Why did my custom protocols list break normal http links?
- Why does sanitize_url() return an empty string for a URL that looks fine?
Why does sanitize_url() encode ampersands differently than esc_url()?
Why did my custom protocols list break normal http links?
Why does sanitize_url() return an empty string for a URL that looks fine?
Alternatives and related functions
esc_url- When the URL is about to be printed into HTML markup, such as an href or src attribute, and needs entity-encoded ampersands.
esc_url_raw- When working against an older WordPress code reference or a codebase that still calls the pre-6.9 name for this same database-context sanitization.
wp_kses_bad_protocol- When only the protocol portion of a string needs stripping and the rest of esc_url()'s cleanup, like query string handling, isn't wanted.
wp_allowed_protocols- When building a custom $protocols array and the goal is to extend the core defaults rather than replace them outright.
Performance profile
How much work a call to sanitize_url() does, and what it touches: the algorithmic scaling, the Zend instruction count per call across PHP versions, the hooks it hands control to, and the core code that calls it. Measured from the compiled opcodes, not a stopwatch, so every number is identical on any machine running the same PHP version, and every function in core is ranked by cost.
- Cost class
- Trivial
- Scaling
- Constant
- Instructions
- 8
- Plugin surface
- None
- Called by
- 50
Touches nothing outside its own arguments.
No loop in the body: the same number of instructions runs whatever you pass in.
Executed per call on PHP 8.5. The body compiles to 8.
Nothing here hands control to plugin code.
50 places in core call this, so the cost is paid more often than your own code shows.
What it touches
- hookthird-party callbacks
apply_filters()one call below sanitize_url()
What one call costs · 1 distinct outcome
One number would be a lie: the work depends on which branch runs. These are every distinct cost sanitize_url() can have, taken from its control-flow graph on PHP 8.5.
| When | Instructions | Calls it makes |
|---|---|---|
| always | 8 | esc_url() |
Across PHP versions
Compiles the same on PHP 7.4, 8.1, 8.2, 8.3, 8.4, 8.5 and 8.6-dev: 8 instructions, 8 executed per call, 0 branches. The work does not change between versions.
An instruction is not a fixed amount of time, so a matching count is not necessarily the same speed; what it rules out is a difference in the work itself.
Uses · 1
- esc_url()Checks and cleans a URL.
Used by · 50
- Custom_Background::handle_upload()Handles an Image upload for the background image.
- Custom_Background::wp_set_background_image()
- Custom_Image_Header::set_header_image()Chooses a header image, selected from existing uploaded and default headers, or provides an array of uploaded header data (either new, or from media library).
- WP_Customize_Manager::_sanitize_background_setting()Callback for validating a background setting value.
- WP_Customize_Manager::_sanitize_external_header_video()Callback for sanitizing the external_header_video value.
- WP_Customize_Manager::_validate_external_header_video()Callback for validating the external_header_video value.
- WP_Customize_Manager::customize_pane_settings()Prints JavaScript settings for parent window.
- WP_Customize_Manager::customize_preview_settings()Prints JavaScript settings for preview frame.
- WP_Customize_Manager::set_preview_url()Sets the initial URL to be previewed.
- WP_Customize_Manager::set_return_url()Sets URL to link the user to when closing the Customizer.
- WP_Customize_Nav_Menu_Item_Setting::sanitize()Sanitize an input.
- WP_REST_Font_Faces_Controller::sanitize_src()Sanitizes a single src value for a font face.
Show all 50
- WP_REST_Menu_Items_Controller::get_item_schema()Retrieves the nav menu item's schema, conforming to JSON Schema.
- WP_REST_Server::serve_request()Handles serving a REST API request.
- WP_Theme::sanitize_header()Sanitizes a theme header.
- WP_Theme_JSON_Resolver::get_resolved_theme_uris()Resolves relative paths in theme.json styles to theme absolute paths and returns them in an array that can be embedded as the value of `_link` object in REST API responses.
- _custom_background_cb()Default custom background callback.
- _wp_ajax_delete_comment_response()Sends back current comment total and new page links if they need to be updated.
- _wp_privacy_send_erasure_fulfillment_notification()Notifies the user when their erasure request is fulfilled.
- _wp_privacy_send_request_confirmation_notification()Notifies the site administrator via email when a request is confirmed.
- _wp_theme_json_webfonts_handler()Runs the theme.json webfonts handler.
- edit_post()Updates an existing post with values provided in `$_POST`.
- edit_user()Edit user settings based on contents of $_POST
- esc_url_raw()Sanitizes a URL for database or redirect usage.
- export_wp()Generates the WXR export file for download.
- get_blogaddress_by_domain()Get a full site URL, given a domain and a path.
- get_editor_stylesheets()Retrieves any registered editor stylesheet URLs.
- get_header_image()Retrieves header image for custom header.
- get_header_video_url()Retrieves header video URL for custom header.
- get_pagenum_link()Retrieves the link for a page number.
- get_post_embed_url()Retrieves the URL to embed a specific post in an iframe.
- get_the_generator()Creates the generator XML or Comment for RSS, ATOM, etc.
- get_uploaded_header_images()Gets the header images uploaded for the active theme.
- get_url_in_content()Extracts and returns the first URL from passed content.
- login_footer()Outputs the footer for the login page.
- rest_output_link_header()Sends a Link header for the REST API.
- rest_sanitize_value_from_schema()Sanitize a value based on a schema.
- rest_send_cors_headers()Sends Cross-Origin Resource Sharing headers with API requests.
- sanitize_option()Sanitizes various option values based on the nature of the option.
- upgrade_682()Executes changes made in WordPress 6.8.2.
- wp_ajax_send_link_to_editor()Handles sending a link to the editor via AJAX.
- wp_default_packages_inline_scripts()Adds inline scripts required for the WordPress JavaScript packages.
- wp_default_scripts()Registers all WordPress scripts.
- wp_media_upload_handler()Handles the process of uploading media.
- wp_nonce_ays()Displays "Are You Sure" message to confirm the action being taken.
- wp_prepare_themes_for_js()Prepares themes for JavaScript.
- wp_privacy_send_personal_data_export_email()Send an email to the user with a link to the personal data export file
- wp_send_user_request()Send a confirmation request email to confirm an action.
- wp_update_nav_menu_item()Saves the properties of a menu item or create a new one.
- wp_update_plugins()Checks for available updates to plugins based on the latest versions hosted on WordPress.org.
Source code
function sanitize_url( $url, $protocols = null ) { return esc_url( $url, $protocols, 'db' );}Changelog
Introduced in 2.3.1. Unchanged from 6.7.7 through 7.1.0.
Signature, return type and hooks compared across 5 parsed releases.
About this page
- Parsed data
- Generated from the wordpress-develop 6.8.8 tag, from
src/wp-includes/formatting.php, and regenerated for each WordPress release so it tracks the code rather than a snapshot of it. - Corrections
- Something wrong on this page? Report it and it gets fixed in the next regeneration.