Design Decisions

This page lists a number of important design decisions that come up frequently, and attempts to explain and cross-reference the reasoning behind them.

Absolute versus relative URLs

WordPress stores absolute URLs in the database. Relative URLs are not used for a variety of reasons. Dynamically generated websites need permanent URLs (permalinks), so absolute URIs make more sense. WordPress has a variety of functions to call a site domain and various folders in plugins and themes so that relative URLs are not necessary. When moving domains, there are search and replace tools for switching domains in the database.

Top ↑

Why relative URLs are not good

Content is migratory. That is to say that the content, which is in the database, might not always be displayed within the context of “your site”. Content can be displayed in a variety of places. For example, an RSS feedRSS Feed RSS is an acronym for Real Simple Syndication which is a type of web feed which allows users to access updates to online content in a standardized, computer-readable format. This is the feed. of your content can be pulled into Google Reader and displayed there. Or users can use feed readers of their own. Or the content can be pulled from your site using microformats and displayed somewhere else. A user will never know where the content is going to be. Therefore an absolute URLURL A specific web address of a website or web page on the Internet, such as a website’s URL is necessary within that content to ensure that it always points to a specific point, regardless of where it’s displayed.

Permalinks are malleable. The content of a post can be displayed on, on,, and so on. A relative URL would not be valid unless it is “root-relative”, meaning that it started with a / character, to refer to the root of the site. Even then, if a site is moved from one subdirectory to another, the root-relative URL would still need to change, and changing the content in the database to adjust would be necessary.

Moving is easier with absolute URLs. For example, assume a user is moving from to Doing a search and replace in the database for "" and replacing that is very easy and unlikely to be problematic. One might say that a root-relative URL would not need to change at all in such a case, and this is true, but what if the content needs to be moved from to The root-relative URLs still need to change in such a case, and now there isn’t a simple to find string, such as "" to search and replace on.

Also, within the content of posts themselves, absolute URLs are easier to manage.

It has been suggested that if WordPress were to be able to do all of this over, we may have instead opted for relative URLs. This is true, and making adjustments to our current approach – or reconsidering it in its entirety – does remain a distinct possibility in the future. See #17048.

Top ↑

No support for forwarding headers for HTTPS or IP addresses

Many load balancers and proxy servers forward HTTPHTTP HTTP is an acronym for Hyper Text Transfer Protocol. HTTP is the underlying protocol used by the World Wide Web and this protocol defines how messages are formatted and transmitted, and what actions Web servers and browsers should take in response to various commands. headers for HTTPSHTTPS HTTPS is an acronym for Hyper Text Transfer Protocol Secure. HTTPS is the secure version of HTTP, the protocol over which data is sent between your browser and the website that you are connected to. The 'S' at the end of HTTPS stands for 'Secure'. It means all communications between your browser and the website are encrypted. This is especially helpful for protecting sensitive data like banking information., IP addresses, and more. These typically take the form of HTTP_X_FORWARDED_FOR (X-Forwarded-For), for remote IP addresses, and HTTP_X_FORWARDED_PROTO (X-Forwarded-Proto), for whether traffic is going over the HTTPS protocol. Occasionally other information needs to be forwarded, like the server port.

If WordPress blindly listened to these headers – especially for protocols – there is a risk of infinite redirects and general breakage. To make matters worse, these are not formal standards, and are rather freeform. As a result, many web server and  configurations do this differently. For example, one configuration might prepend “HTTP_”, resulting in HTTP_HTTPS. What should be done instead is a server should either pass properly mapped headers to PHPPHP The web scripting language in which WordPress is primarily architected. WordPress requires PHP 5.6.20 or higher, or some code can do the mapping in wp-config.php. For example:

if (
) {
	$_SERVER['HTTPS'] = 'on';

See also: #9235, #15009, #15733, #19337, #24394, etc.

Top ↑

Adding new oEmbed providers

We have a certain standard for oEmbed providers in coreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress.. In order to add a new one to the existing allow-list, they must:

  • be well-established, popular, and mainstream services,
  • properly and fully implement the oEmbed specification,
  • and clearly be a trusted provider.

Security is important with oEmbed, because it is dealing with raw, unfiltered HTMLHTML HyperText Markup Language. The semantic scripting language primarily used for outputting content in web browsers., which is inherently dangerous due to arbitrary JavaScriptJavaScript JavaScript or JS is an object-oriented computer programming language commonly used to create interactive effects within web browsers. WordPress makes extensive use of JS for a better user experience. While PHP is executed on the server, JS executes within a user’s browser. and object embedding. It is therefore paramount that the provider can be trusted. But trust is more than about security — the service must also be “built to last.” If a provider ever stops supporting oEmbed, sites start to lose content they previously trusted would stay embedded permanently.  Or, if a dead startup’s domain expires or is acquired, it could be an easy vector for malware. Nascent services are just too fragile to be added for core.

With regards to establishment and popularity, there are a number of things that can be considered, such as:

  • Is the service is popular enough for core developers to have heard of it before? Is it “mainstream?”
  • If similar services are already supported, how does this service compare in terms of size, features, and backing?
  • Does this service have an established social media presence?
  • Is its oEmbed endpoint clearly established and properly documented? (Sometimes, they are just a developer’s pet project that may not be supported.)
  • Does the oEmbed endpoint work with WordPress’ oEmbed auto-discovery? If not, could it be made to work with additional HTML tags or attributes being added to the allow-list?
  • Does the service make an effort to build relationships with developers, such as through robust APIs?
  • How old is the service?
  • Does it have a well-established Wikipedia article? (Seriously.)
  • Has anyone written a WordPress pluginPlugin A plugin is a piece of software containing a group of functions that can be added to a WordPress website. They can extend functionality or add new features to your WordPress websites. WordPress plugins are written in the PHP programming language and integrate seamlessly with WordPress. These can be free in the Plugin Directory or can be cost-based plugin from a third-party that leverages the service in some way, whether adding it as an oEmbed provider, creating a shortcodeShortcode A shortcode is a placeholder used within a WordPress post, page, or widget to insert a form or function generated by a plugin in a specific location on your site., or leveraging other APIs of the service? Do these plugins have any noticeable adoption or traction that would indicate usage and demand?
  • Is the provider frequently proposed?

Individually, these are all very anecdotal. But when considered holistically, it paints a pretty decent picture.

Top ↑

Unfiltered HTML for editors, administrators; multisite

Users with Administrator or Editor roles are allowed to publish unfiltered HTML in post titles, post content, and comments. WordPress is, after all, a publishing tool, and people need to be able to include whatever markup they need to communicate. Users with lesser privileges are not allowed to post unfiltered content.

If you are running security tests against WordPress, use a lesser privileged user so that all content is filtered. You may report security issues to The community site where WordPress code is created and shared by the users. This is where you can download the source code for WordPress core, plugins and themes as well as the central location for community conversations and organization. For more, see Reporting Security Vulnerabilities.

If you are concerned about an Administrator putting XSS into content and stealing cookies, note that all cookies are marked for HTTP only delivery and are divided into privileged cookies used for adminadmin (and super admin) pages and lesser-privileged cookies used for public-facing pages. Content is never displayed unfiltered in the admin. Regardless, an Administrator has wide-ranging super powers among which unfiltered HTML is a lesser one.

In WordPress multisitemultisite Used to describe a WordPress installation with a network of multiple blogs, grouped by sites. This installation type has shared users tables, and creates separate database tables for each blog (wp_posts becomes wp_0_posts). See also network, blog, site, only super administrators can publish unfiltered HTML, as all other users are considered untrusted.

To disable unfiltered HTML for all users, including administrators and super administrators, you can add define( 'DISALLOW_UNFILTERED_HTML', true ); to wp-config.php.

Top ↑

Only owner-writeable is supported on upgrade, not group writeable

See #10205.

Top ↑

Some esoteric MySQL settings are not supported

WordPress does not support MySQLMySQL MySQL is a relational database management system. A database is a structured collection of data where content, configuration and other options are stored. strict mode or autocommit = 0. #8857, #16821, #16429.

Last updated: