sanitize_title( string $title, string $fallback_title = '', string $context = 'save' ): string
- Since
- 1.0.0
- Source
wp-includes/formatting.php:2228
Runs a raw title through the core slug-sanitization filter to produce a lowercase, hyphen-safe string suitable for permalinks or HTML id attributes. The $context argument controls whether accented characters are stripped first (only when set to 'save', the default), and $fallback_title supplies a replacement when the sanitized result comes back empty. Pair it with sanitize_title_with_dashes() when you want the default filter behavior without going through the 'sanitize_title' hook.
Description
By default, converts accent characters to ASCII characters and further limits the output to alphanumeric characters, underscore (_) and dash (-) through the 'sanitize_title' filter.
If $title is empty and $fallback_title is set, the latter will be used.
Compatibility
- WordPress
- since 1.0.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
$titlestring- The string to be sanitized.
$fallback_titlestringoptional- A title to use if $title is empty. Default empty.Default:
'' $contextstringoptional- The operation for which the string is sanitized.
When set to 'save', the string runs through remove_accents().
Default 'save'.Default:'save'
Return value
string- The sanitized string.
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.
Convert a post title into a URL-safe slug
Build a slug from the title of post 1 and from a title containing accented characters to see remove_accents() at work.
$post_title = get_the_title( 1 );
$accented_title = 'Café con leche';
echo 'From "' . esc_html( $post_title ) . '": ' . esc_html( sanitize_title( $post_title ) ) . '<br>';
echo 'From "' . esc_html( $accented_title ) . '": ' . esc_html( sanitize_title( $accented_title ) );Fall back to a generated slug when the title is empty
Simulate an import routine that hands sanitize_title() an empty title and a fallback based on the post ID, then compare context 'save' with context 'query'.
$empty_title = '';
$post_id = 4;
$fallback_slug = sanitize_title( $empty_title, 'post-' . $post_id );
echo 'Fallback slug: ' . esc_html( $fallback_slug ) . '<br>';
$raw_title = 'Ñandú Ranch';
$save_slug = sanitize_title( $raw_title, '', 'save' );
$query_slug = sanitize_title( $raw_title, '', 'query' );
echo "Context 'save': " . esc_html( $save_slug ) . '<br>';
echo "Context 'query': " . esc_html( $query_slug );Only the default 'save' context runs remove_accents() first, so other contexts can leave non-ASCII characters to be handled purely by the 'sanitize_title' filter chain.
Common problems and fixes · 3
- Why does my fallback title show up with weird characters or capital letters instead of being cleaned up?
- Why do accented letters survive sanitize_title() sometimes?
- Why is my slug different from what sanitize_title_with_dashes() produces on its own?
Why does my fallback title show up with weird characters or capital letters instead of being cleaned up?
Why do accented letters survive sanitize_title() sometimes?
Why is my slug different from what sanitize_title_with_dashes() produces on its own?
Alternatives and related functions
sanitize_title_with_dashes- When you want the default hyphenated slug logic without running it through the filterable 'sanitize_title' hook.
sanitize_key- When sanitizing an internal identifier like an option name or meta key rather than a public-facing slug.
remove_accents- When you only need accented characters converted to ASCII and don't want the rest of the slug filtering.
wp_unique_post_slug- When you need a slug guaranteed not to collide with an existing post, page, or attachment.
Performance profile
How much work a call to sanitize_title() 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
- 17–23
- Plugin surface
- 1 hook
- 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, depending on the branch taken. The body compiles to 23.
Third-party callbacks on 'sanitize_title' run inside this call, and their cost is not bounded by anything here.
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()called directly
Further down the call graph this can also reach option, cache, serialize, query and transient. Those are the worst case, several calls deep and usually down an error path, not what a normal call pays.
What one call costs · 2 distinct outcomes
One number would be a lie: the work depends on which branch runs. These are every distinct cost sanitize_title() can have, taken from its control-flow graph on PHP 8.5.
| When | Instructions | Calls it makes |
|---|---|---|
$context !== "save" | 17–19 | apply_filters() |
$context === "save" | 21–23 | remove_accents(), apply_filters() |
Across PHP versions
Compiles the same on PHP 7.4, 8.1, 8.2, 8.3, 8.4, 8.5 and 8.6-dev: 23 instructions, 17–23 executed per call, 3 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.
Hooks and filters fired · 1
One hook fires while sanitize_title() runs, in this order:
Uses · 2
- remove_accents()Converts all accent characters to ASCII characters.
- apply_filters()Calls the callback functions that have been added to a filter hook.
Used by · 50
- WP_Admin_Bar::add_node()Adds a node to the menu.
- WP_Customize_Manager::import_theme_starter_content()Imports theme starter content into the customized state.
- WP_Customize_Manager::prepare_starter_content_attachments()Prepares starter content attachments.
- WP_Customize_Nav_Menu_Setting::filter_wp_get_nav_menu_object()Filters the wp_get_nav_menu_object() result to supply the previewed menu object.
- WP_Customize_Nav_Menu_Setting::filter_wp_get_nav_menus()Filters the wp_get_nav_menus() result to ensure the inserted menu object is included, and the deleted one is removed.
- WP_Customize_Nav_Menus::insert_auto_draft_post()Adds a new `auto-draft` post.
- WP_Font_Collection::__construct()WP_Font_Collection constructor.
- WP_Font_Collection::get_sanitization_schema()Retrieves the font collection sanitization schema.
- WP_Plugins_List_Table::single_row()Generates the markup for a single plugin row.
- WP_REST_Attachments_Controller::insert_attachment()Inserts the attachment post in the database. Does not update the attachment meta.
- WP_REST_Controller::sanitize_slug()Sanitizes the slug value.
- WP_REST_Font_Faces_Controller::prepare_item_for_database()Prepares a single font face post for creation.
Show all 50
- WP_REST_Font_Families_Controller::prepare_item_for_database()Prepares a single font family post for create or update.
- WP_Theme_JSON::compute_spacing_sizes()Generates a set of spacing sizes by starting with a medium size and applying an operator with an increment value to generate the rest of the sizes outward from the medium size. The medium slug is '50' with the rest of the slugs being 10 apart. The generated names use t-shirt sizing.
- _load_remote_block_patterns()Register Core's official patterns from wordpress.org/patterns.
- _load_remote_featured_patterns()Register `Featured` (category) patterns from wordpress.org/patterns.
- _register_remote_theme_patterns()Registers patterns from Pattern Directory provided by a theme's `theme.json` file.
- _wp_ajax_add_hierarchical_term()Handles adding a hierarchical term via AJAX.
- add_menu_page()Adds a top-level menu page.
- build_template_part_block_instance_variations()Returns an array of instance variation objects for the template part block
- dynamic_sidebar()Displays dynamic sidebar.
- get_category_by_path()Retrieves a category based on URL containing the category slug.
- get_sample_permalink()Returns a sample permalink based on the post name.
- is_active_sidebar()Determines whether a sidebar contains widgets.
- list_core_update()Lists available core updates.
- make_site_theme()Creates a site theme.
- media_handle_sideload()Handles a side-loaded file in the same way as an uploaded file is handled by media_handle_upload().
- media_handle_upload()Saves a file submitted from a POST request and create an attachment post for it.
- permalink_anchor()Displays the permalink anchor for the current post.
- register_sidebar_widget()Register widget for sidebar with backward compatibility.
- register_taxonomy()Creates or modifies a taxonomy object.
- register_widget_control()Registers widget control callback for customizing options.
- render_block_core_latest_posts()Renders the `core/latest-posts` block on server.
- render_block_core_post_template()Renders the `core/post-template` block on the server.
- sanitize_title_for_query()Sanitizes a title with the 'query' context.
- term_exists()Determines whether a taxonomy term exists.
- update_nag()Returns core update notification message.
- upgrade_100()Execute changes made in WordPress 1.0.
- upgrade_110()Execute changes made in WordPress 1.2.
- upgrade_230()Execute changes made in WordPress 2.3.
- upgrade_330()Execute changes made in WordPress 3.3.
- wp_ajax_add_link_category()Handles adding a link category via AJAX.
- wp_get_custom_css_post()Fetches the `custom_css` post for a given theme.
- wp_insert_post()Inserts or updates a post in the database.
- wp_insert_term()Adds a new term to the database.
- wp_insert_user()Inserts a user into the database.
- wp_install_defaults()Creates the initial content for a newly-installed site.
- wp_install_maybe_enable_pretty_permalinks()Maybe enable pretty permalinks on installation.
- wp_render_layout_support_flag()Renders the layout config to the block wrapper.
- wp_update_custom_css_post()Updates the `custom_css` post for a given theme.
Source code
function sanitize_title( $title, $fallback_title = '', $context = 'save' ) { $raw_title = $title; if ( 'save' === $context ) { $title = remove_accents( $title ); } /** * Filters a sanitized title string. * * @since 1.2.0 * * @param string $title Sanitized title. * @param string $raw_title The title prior to sanitization. * @param string $context The context for which the title is being sanitized. */ $title = apply_filters( 'sanitize_title', $title, $raw_title, $context ); if ( '' === $title || false === $title ) { $title = $fallback_title; } return $title;}Changelog
Introduced in 1.0.0. 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 7.1.0 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.