PHPackages                             samiahmedsiddiqui/custom-permalinks - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. samiahmedsiddiqui/custom-permalinks

ActiveWordpress-plugin[Utility &amp; Helpers](/categories/utility)

samiahmedsiddiqui/custom-permalinks
===================================

Set custom permalinks on a per-post basis in WordPress.

v3.1.2(7mo ago)27926[14 issues](https://github.com/samiahmedsiddiqui/custom-permalinks/issues)[2 PRs](https://github.com/samiahmedsiddiqui/custom-permalinks/pulls)GPL-3.0-or-laterPHPPHP &gt;=7.0CI passing

Since Aug 4Pushed 1mo ago4 watchersCompare

[ Source](https://github.com/samiahmedsiddiqui/custom-permalinks)[ Packagist](https://packagist.org/packages/samiahmedsiddiqui/custom-permalinks)[ Docs](https://www.custompermalinks.com/)[ RSS](/packages/samiahmedsiddiqui-custom-permalinks/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (10)Dependencies (3)Versions (33)Used By (0)

Custom Permalinks
=================

[](#custom-permalinks)

You want to take control of your WordPress site's URLs? The **Custom Permalinks** plugin gives you the power to set unique, custom URLs for any post, page, tag, or category. This means you can design your site's structure exactly how you envision it, rather than being limited by WordPress's default settings. When you set a custom permalink, the original post URL will be automatically redirected to your new, customized URL.

Key Features
------------

[](#key-features)

- **Individual Permalink Control**: Assign unique URLs to any post, page, tag, or category.
- **Site Structure Control**: Gain ultimate control over how your site's URLs are organized.
- **Post Type Permalink Structures (v3.0.0+)**: Define custom permalink structures for each public Post Type using predefined tags, automatically generating URLs upon content creation. You can still manually edit any permalink. If left empty, default settings will apply.

Getting Started: Plugin Settings
--------------------------------

[](#getting-started-plugin-settings)

You can configure Custom Permalinks by navigating to **Settings &gt; Custom Permalinks** in your WordPress Dashboard.

### Available Tags for Permalink Structures

[](#available-tags-for-permalink-structures)

When setting up your custom permalink structures, you can use a variety of tags that will dynamically populate the URL. Here's a breakdown of what's available:

Tag NameDescription`%year%`The year of the post in four digits, eg: 2025`%monthnum%`Month the post was published, in two digits, eg: 01`%day%`Day the post was published in two digits, eg: 02`%hour%`Hour of the day, the post was published, eg: 15`%minute%`Minute of the hour, the post was published, eg: 43`%second%`Second of the minute, the post was published, eg: 33`%post_id%`The unique ID of the post, eg: 123`%category%`A clean version of the category name (its slug). Nested sub-categories will appear as nested directories in the URL.`%author%`A sanitized version of the post author’s name.`%postname%`A clean version of the post or page title (its slug). For example, "This Is A Great Post!" becomes `this-is-a-great-post` in the URL.`%parent_postname%`Similar to `%postname%`, but uses the immediate parent page's slug if a parent is selected.`%parents_postnames%`Similar to `%postname%`, but includes all parent page slugs if parents are selected.`%title%`The title of the post, converted to a slug. For example, "This Is A Great Post!" becomes `this-is-a-great-post`. Unlike `%postname%` which is set once, `%title%` automatically updates in the permalink if the post title changes (unless the post is published or the permalink is manually edited).`%ctax_TAXONOMY_NAME%`A clean version of a custom taxonomy term's **slug**. Replace `TAXONOMY_NAME` with the actual taxonomy name. You can also provide a default slug when no term is selected using `??` (e.g., `%ctax_type??sales%`).`%ctax_TAXONOMY_NAME_name%`The custom taxonomy term's **name** (instead of its slug). Replace `TAXONOMY_NAME` with the actual taxonomy name. Supports a default value using `??` when no term is selected (e.g., `%ctax_type_name??Sales%`).`%ctax_parent_TAXONOMY_NAME%`Similar to `%ctax_TAXONOMY_NAME%`, but includes the immediate parent term's slug in the URL if a parent is selected.`%ctax_parent_TAXONOMY_NAME_name%`Similar to `%ctax_TAXONOMY_NAME_name%`, but includes the immediate parent term's **name** if a parent is selected.`%ctax_parents_TAXONOMY_NAME%`Similar to `%ctax_TAXONOMY_NAME%`, but includes all parent term slugs in the URL if parents are selected.`%ctax_parents_TAXONOMY_NAME_name%`Similar to `%ctax_TAXONOMY_NAME_name%`, but includes all parent term **names** if parents are selected.`%custom_permalinks_TAG_NAME%`Developers have the flexibility to define their own custom tags(replace `_TAG_NAME` with your desired name). To ensure these tags resolve to the correct permalinks, simply apply the `custom_permalinks_post_permalink_tag` filter.**Important Note:** For new posts, Custom Permalinks will keep updating the permalink while the post is in draft mode, assuming a structure is defined in the plugin settings. Once the post is published or its permalink is manually updated, the plugin will stop automatic updates for that specific post.

Advanced Customization and Filters
----------------------------------

[](#advanced-customization-and-filters)

Custom Permalinks offers developers a robust set of filters and actions to precisely control its behavior. This section outlines how to leverage these features for tasks like generating permalinks programmatically and fine-tuning URL structures.

---

### Setting a Custom Value in Your Post Type Permalink

[](#setting-a-custom-value-in-your-post-type-permalink)

Let's say you have a custom post type named "Press" and you want to include the year and month from an ACF (Advanced Custom Fields) date field directly in its permalink.

If your post type's permalink structure is `about/newsroom/press-releases/%custom_permalinks_year%/%custom_permalinks_month%/%postname%/`, here's how you can achieve that with a custom value:

```
/**
 * Add ACF field year and month in the permalink of the "Press" post type.
 *
 * @param string $custom_tag Custom tag name.
 * @param string $post_type  Post type from where it is called.
 * @param object $post       The post object.
 *
 * @return string Custom tag value which needs to be used.
 */
function custom_permalinks_post_permalink_tag( $custom_tag, $post_type, $post ) {
	$custom_tag_value = $custom_tag;
	if ( 'press' === $post_type &&
		( 'year' === $custom_tag || 'month' === $custom_tag )
	) {
		// Replace the field name 'press_date'.
		$press_date = get_field( 'press_date', $post->ID );
		if ( ! empty( $press_date ) ) {
			$date = new DateTime( $press_date );
		} else {
			$date = new DateTime( $post->post_date );
		}

		if ( 'year' === $custom_tag ) {
			$custom_tag_value = $date->format( 'Y' );
		} else {
			$custom_tag_value = $date->format( 'm' );
		}
	}

	return $custom_tag_value;
}
add_filter( 'custom_permalinks_post_permalink_tag', 'custom_permalinks_post_permalink_tag', 10, 3 );
```

This `custom_permalinks_post_permalink_tag` filter allows you to dynamically insert values into your permalink structure. The example retrieves the `year` and `month` from your ACF date field named `press_date` and inserts them where `%custom_permalinks_year%` and `%custom_permalinks_month%` are defined in your permalink structure. You can integrate this code into your theme's `functions.php` file or a custom plugin to retrieve those values and return them for the respective permalink tags.

---

### Manipulate Permalink Before Saving

[](#manipulate-permalink-before-saving)

Make changes to a permalink string just before it's saved to the database. This is useful for enforcing specific formatting, like ensuring a trailing slash:

```
function custom_permalinks_permalink_before_saving( $permalink, $post_id, $language_code ) {
	// Check for a trailing slash in the permalink.
	if ( '/' !== substr( $permalink, -1 ) ) {
		// If the permalink doesn't have a trailing slash, add one.
		$permalink .= '/';
	}

	return $permalink;
}
add_filter( 'custom_permalink_before_saving', 'custom_permalinks_permalink_before_saving', 10, 3 );
```

---

### Allow Accented Letters in Permalinks

[](#allow-accented-letters-in-permalinks)

Enable the use of accented characters in permalinks:

```
add_filter( 'custom_permalinks_allow_accents', '__return_true' );
```

---

### Allow Uppercase Letters in Permalinks

[](#allow-uppercase-letters-in-permalinks)

Enable the use of uppercase characters in permalinks:

```
add_filter( 'custom_permalinks_allow_caps', '__return_true' );
```

---

### Allow Redundant Hyphens in Permalinks

[](#allow-redundant-hyphens-in-permalinks)

Allow permalinks to contain redundant hyphens (e.g., --):

```
add_filter( 'custom_permalinks_redundant_hyphens', '__return_true' );
```

---

### Generating Custom Permalinks

[](#generating-custom-permalinks)

This section outlines how to generate custom permalinks for your WordPress posts, either individually or for an entire post type. This functionality allows site owners and developers to programmatically create or regenerate permalinks without manual updates.

#### Generate Permalink for a Single Post ID

[](#generate-permalink-for-a-single-post-id)

To generate a custom permalink for a specific post, you can use the following action hook, replacing `$post_id` with the actual ID of your post:

```
do_action( 'custom_permalinks_generate_post_permalink', $post_id );
```

This simple line of code triggers the permalink generation process for the specified post.

#### Generate Permalinks for an Entire Post Type

[](#generate-permalinks-for-an-entire-post-type)

For bulk updates or after structural changes, you might need to regenerate permalinks for all posts within a specific post type. Here's an example demonstrating how to do this for a custom post type called `product`.

```
/**
 * Generates custom permalinks for all posts within a specified post type.
 *
 * @param string $post_type The post type to generate permalinks for.
 */
function custom_permalinks_generate_permalinks_for_post_type( $post_type ) {
	$args = array(
		'post_type'      => $post_type,
		'posts_per_page' => -1, // Get all posts of this type.
		'post_status'    => 'publish', // Only published posts.
		'fields'         => 'ids', // Only retrieve post IDs for efficiency.
	);

	$posts = get_posts( $args );
	if ( $posts ) {
		foreach ( $posts as $post_id ) {
			do_action( 'custom_permalinks_generate_post_permalink', $post_id );
		}
		echo "Permalinks for all '{$post_type}' posts have been regenerated.";
	} else {
		echo "No '{$post_type}' posts found to regenerate permalinks for.";
	}
}

// Example usage: Call the function to regenerate permalinks for the 'product' post type.
custom_permalinks_generate_permalinks_for_post_type( 'product' );
```

This PHP function iterates through all published posts of the specified `$post_type` and applies the `do_action` hook to each, ensuring their permalinks are regenerated. You can integrate this code into your theme's `functions.php` file or a custom plugin, typically running it as a one-time process or via an administrative trigger.

---

### Exclude Post Type from Custom Permalink Form

[](#exclude-post-type-from-custom-permalink-form)

Remove the custom permalink settings form from the edit screen of a specific post type:

```
function custom_permalinks_exclude_post_types( $post_type ) {
	// Replace 'custompost' with the name of the post type you want to exclude.
	if ( 'custompost' === $post_type ) {
		return '__true';
	}

	return '__false';
}
add_filter( 'custom_permalinks_exclude_post_type', 'custom_permalinks_exclude_post_types' );
```

---

### Exclude Specific Posts from Custom Permalink Form

[](#exclude-specific-posts-from-custom-permalink-form)

Remove the custom permalink settings form from individual posts based on criteria like their ID:

```
function custom_permalinks_exclude_posts( $post ) {
	// Replace '1557' with the ID of the post you want to exclude.
	if ( 1557 === $post->ID ) {
		return true;
	}

	return false;
}
add_filter( 'custom_permalinks_exclude_posts', 'custom_permalinks_exclude_posts' );
```

---

### Exclude Permalink from Processing

[](#exclude-permalink-from-processing)

Skip processing for specific permalinks, which can be useful for URLs like XML sitemaps:

```
function custom_permalinks_xml_sitemap_url( $permalink ) {
	if ( false !== strpos( $permalink, 'sitemap.xml' ) ) {
		// Use '__true' to specifically ignore this permalink.
		return '__true';
	}

	// Return null (or nothing) to allow default processing.
	return;
}
add_filter( 'custom_permalinks_request_ignore', 'custom_permalinks_xml_sitemap_url' );
```

---

### Add `PATH_INFO` to `$_SERVER` Variable

[](#add-path_info-to-_server-variable)

Enable `PATH_INFO` to be added to the `$_SERVER` superglobal variable:

```
add_filter( 'custom_permalinks_path_info', '__return_true' );
```

---

### Disable All Redirects

[](#disable-all-redirects)

To prevent Custom Permalinks from performing any redirects:

```
function custom_permalinks_avoid_redirect( $permalink ) {
	// Always return true to disable all redirects.
	return true;
}
add_filter( 'custom_permalinks_avoid_redirect', 'custom_permalinks_avoid_redirect' );
```

---

### Disable Specific Redirects

[](#disable-specific-redirects)

Prevent a particular permalink from being redirected by checking its value:

```
function custom_permalinks_avoid_redirect( $permalink ) {
	// Replace 'testing-hello-world/' with the permalink you want to exclude from redirection.
	if ( 'testing-hello-world/' === $permalink ) {
		return true;
	}
	return false;
}
add_filter( 'custom_permalinks_avoid_redirect', 'custom_permalinks_avoid_redirect' );
```

---

### Disable `like` Query

[](#disable-like-query)

Disable the `like` query functionality, which can impact URL matching in some specific scenarios:

```
add_filter( 'cp_remove_like_query', '__return_false' );
```

*Note: Use `cp_remove_like_query` if URLs don't work after upgrading to v1.2.9.*

**Note:** If you experience issues with URLs after upgrading to v1.2.9, consider using `cp_remove_like_query` instead.

---

### For Assistance:

[](#for-assistance)

- **Premium Users:** If you need assistance implementing these filters, please don't hesitate to reach out to us via our [Premium contact support](https://www.custompermalinks.com/contact-us/).
- **Other Users:** You can also directly reach out to the plugin author via [LinkedIn](https://www.linkedin.com/in/sami-ahmed-siddiqui/).

---

Need Help or Found a Bug?
-------------------------

[](#need-help-or-found-a-bug)

- **Support:** For one-on-one email support, consider purchasing [Custom Permalinks Premium](https://www.custompermalinks.com/#pricing-section). While some basic support may be provided on the WordPress.org forums, email support is prioritized for premium users.
- **Bug Reports:** If you encounter a bug, please report it on [GitHub](https://github.com/samiahmedsiddiqui/custom-permalinks). Make sure to provide complete information to reproduce the issue. GitHub is for bug reports, not general support questions.

If you experience any site-breaking issues after upgrading, please report them on the [WordPress Forum](https://wordpress.org/support/plugin/custom-permalinks/) or [GitHub](https://github.com/samiahmedsiddiqui/custom-permalinks) with detailed information. You can always revert to an older version by downloading it from .

Installation
------------

[](#installation)

You have two ways to install Custom Permalinks:

#### From within WordPress

[](#from-within-wordpress)

1. Go to **Plugins &gt; Add New** in your WordPress dashboard.
2. Search for "Custom Permalinks".
3. Click "Install Now" and then "Activate" the plugin from your Plugins page.

#### Manually via FTP

[](#manually-via-ftp)

1. Download the `custom-permalinks` folder.
2. Upload the `custom-permalinks` folder to your `/wp-content/plugins/` directory.
3. Activate Custom Permalinks through the "Plugins" menu in your WordPress dashboard.

###  Health Score

43

—

FairBetter than 91% of packages

Maintenance67

Regular maintenance activity

Popularity18

Limited adoption so far

Community20

Small or concentrated contributor base

Maturity61

Established project with proven stability

 Bus Factor1

Top contributor holds 98.6% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~68 days

Recently: every ~59 days

Total

31

Last Release

56d ago

Major Versions

v1.7.1 → v2.0.0-alpha2020-09-30

v2.8.0 → v3.0.02025-07-22

PHP version history (4 changes)v1.6.0-betaPHP &gt;5.6

v2.0.0-alphaPHP ^5.4 || ^7.0

v2.5.1PHP ^5.6 || ^7.0

v2.6.0PHP &gt;=7.0

### Community

Maintainers

![](https://www.gravatar.com/avatar/8bbf72b8b174954fa860825e07ab29deab62546dd28ee5354c10c696eefb9871?d=identicon)[samiahmedsiddiqui](/maintainers/samiahmedsiddiqui)

---

Top Contributors

[![samiahmedsiddiqui](https://avatars.githubusercontent.com/u/16156106?v=4)](https://github.com/samiahmedsiddiqui "samiahmedsiddiqui (352 commits)")[![alexclassroom](https://avatars.githubusercontent.com/u/11472643?v=4)](https://github.com/alexclassroom "alexclassroom (1 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (1 commits)")[![k1sul1](https://avatars.githubusercontent.com/u/2719615?v=4)](https://github.com/k1sul1 "k1sul1 (1 commits)")[![leonidukg](https://avatars.githubusercontent.com/u/67500820?v=4)](https://github.com/leonidukg "leonidukg (1 commits)")[![toshotosho](https://avatars.githubusercontent.com/u/2972490?v=4)](https://github.com/toshotosho "toshotosho (1 commits)")

---

Tags

addresscustom-permalinkscustom-post-typelinkpermalinkredirecturlwordpresswordpress-pluginurlwordpressaddresslinkpermalinkcustom-post-typeredirect

###  Code Quality

Code StylePHP\_CodeSniffer

### Embed Badge

![Health badge](/badges/samiahmedsiddiqui-custom-permalinks/health.svg)

```
[![Health](https://phpackages.com/badges/samiahmedsiddiqui-custom-permalinks/health.svg)](https://phpackages.com/packages/samiahmedsiddiqui-custom-permalinks)
```

###  Alternatives

[jbroadway/urlify

A fast PHP slug generator and transliteration library that converts non-ascii characters for use in URLs.

6737.4M62](/packages/jbroadway-urlify)[misd/linkify

Converts URLs and email addresses in text into HTML links

1122.9M10](/packages/misd-linkify)[shivella/laravel-bitly

Laravel package for generating bitly url

75789.0k1](/packages/shivella-laravel-bitly)[voku/urlify

PHP port of URLify.js from the Django project. Transliterates non-ascii characters for use in URLs.

254.1M7](/packages/voku-urlify)[wazum/sluggi

TYPO3 extension for URL slug management with inline editing, auto-sync, locking, access control, and redirects

39488.5k](/packages/wazum-sluggi)[terminal42/contao-url-rewrite

URL Rewrite bundle for Contao Open Source CMS

1595.3k3](/packages/terminal42-contao-url-rewrite)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
