WordPress 3.0: What’s new

UPDATE. WordPress 3.0 was released today, Thursday 17 June 2010. Get it here or upgrade automatically!

The first release candidate of WordPress 3.0 came out on 28 May 2010. The second followed a week after that, and the final release is expected sometime after 14 June 2010.

WordPress 3.0 is a large release. The codebase underwent more changes than in any previous version (about 2700 sets of changes at this moment), and more people than ever before (above 200) contributed changes directly. However, for the most part the changes are not immediately obvious.

Much of what changed is under the surface: A lot of rewriting for the merge with WordPres MU, good features for developers, things to make WP a better tool internally, and many bug fixes. Then, there are several new user features, but some of them are not visible either unless you select to use them or unless your theme explicitly supports them.


Backwards compatibility is good. If op111.net is any indication, of the 25 plugins it uses 24 have been working flawlessly with WordPress 3.0. One (HeadSpace2) caused a small issue recently, because of a JavaScript conflict.

See also “Known Issues”, right below.

Known issues

  • Upgrading to 3.0 may need more than 32MB of memory (because the package is larger now). If you cannot upgrade because of insufficient memory, try adding in your wp-config.php this: define('WP_MEMORY_LIMIT', '256M');
  • Plugins that replace the WordPress database class, and probably also plugins that extend it, need to be updated. This is because of substantial changes that were required for the merge with WordPress MU.
  • Conversion from single-site to multi-site can become problematic if subdirectories—rather than subdomains—are used.
  • See also the Issues, Problems and Resolutions thread at the official WordPress forum.


WordPress MU merge

WordPress MU is a variation of WordPress designed for running multiple sites and weblogs on a single installation. As an application it is not as widely known as WordPress, but there are probably more people using it daily to publish on the web than there are using WordPress. Its users include educational institutions, research centres and publishing companies all over the world, and also services like WordPress.com (which must be the largest user of WordPress MU and for which MU was initially developed).

WordPress 3.0 brings together WordPress and WordPress MU. All MU functionality was merged into WordPress, and MU will now be discontinued. Its current version, 2.9.2, will be the last.

The merge and transition were designed to be invisible to users: Users of WordPress MU 2.9.2 will simply see a notice to update to WordPress 3.0, while users of single-site WordPress won’t see anything related to multi-site functionality unless they define a specific constant in wp-config.php.

WordPress 3.0: Setting up a multi-site network WordPress 3.0: The super admin sets the available themes

Terminology changes

One difference users of single-site WordPress will notice is in terminology. All instances of “blog” in the administration interface were replaced with “site”, to standardize terminology between single-site and multi-site.

The new meanings, which I hope I’m getting right, are as follows:

  • example.com in a single-site installation is now a site (which can of course be a blog).
  • example.com in a multi-site installation is a network of sites and also the main site of the network (and can of course be a blog).
  • demetris.example.com or example.com/demetris in a multi-site installation is one of the sites that make up the network.

Trying WordPress MS

If you want to try the multi-site mode, there are two things you should know:

  • Setting up multi-site is not as easy as the rest of WordPress.
  • You should keep copies of wp-config.php and .htaccess, in case you change your mind later and want to return to the single-site mode.

Setting up WordPress for multi-site use will probably become easier in the future. In this release, however, the aim was different: To merge the two code bases as well as possible, and to make the transition seamless—even invisible—for all, both WordPress users and WordPress MU users. This aim was achieved.

DOCUMENTATION. codex.wordpress.org/Create_a_Network

Update centre

The new update centre displays in one place everything for which there is an update, and lets you update everything—WordPress itself, plugins, and themes—from the same place. It also lets you update themes in bulk, which was not possible before. Notifications of available updates appear in a little bubble next to the menu item from which the updater is accessed: Dashboard › Updates.

WordPress 3.0: Update Centre, selecting updates WordPress 3.0: Update Centre, done! WordPress 3.0: Plugins, bulk updating

The update centre is my favourite new user feature in WordPress 3.0. It makes maintenance easier and it helps keep your website up to date and secure, all from a simple interface that does not betray the complexity of the underlying mechanism. (A bulk updater that works well across all the different environments and setups in which WordPress runs is not a simple matter!)

Custom post types improved and simplified

Custom post types were already possible in WordPress but the functionality was basic. In WordPress 3.0 they come with many improvements and they can have their own UI too!

What are custom post types? Think of the WordPress Posts and Pages that you already know. They are both post types, same in many ways and different in some—mainly in that Pages are arranged hierarchically, while Posts are arranged chronologically—and they exist by default in WordPress. A custom post type is a post type that does not exist by default and that you create.

And why make a custom post type?

Say, for example, that you enjoy publishing recipes but it always nagged you that in WordPress your recipes had to be either Posts or Pages. Now you can create your own post type, “Recipes”, to write about your recipes, and you can add to it exactly the set of features you want: It can have its own UI, e.g. “Edit Recipe” instead of “Edit Post”, and “Add New Recipe” instead of “Add New Post”, it can have or not have features like Excerpts, Featured Images, Comments, etc., and it can also be associated with custom taxonomies.

Custom taxonomies

Like custom post types, custom taxonomies already existed but they are now improved. One of the improvements is that they can be combined with custom post types. So, continuing the above example, if you don’t like using Tags for your Recipes, you can make a new flat taxonomy, say “Ingredients”, and associate it with the post type “Recipes”.

Not excited by all that? Don’t worry! You probably don’t need so much custom. Not everyone does. In fact, I would say that most WordPress sites can be organized perfectly well with what we already had: Posts, Pages, Categories and Tags.

Yet, custom post types and taxonomies open up new possibilities, and it would be interesting to see what applications entertaining minds find for them, especially as the functionality is refined and improved in the future.



New theme

WordPress 3.0 has a new default theme named Twenty Ten (after the year in which it is introduced).

Twenty Ten is a simple theme with a clean and modern design and a number of interesting features, my favourite among which is the array of four widget areas above the footer. In addition, and as is always the case with the default WordPress theme, it implements all the new features of this release; most notably, custom background and header (see below) and custom menus (see below).

WordPress 3.0: Twenty Ten theme, Headers WordPress 3.0: Twenty Ten theme

One thing I particularly like in Twenty Ten is the collection of header images it comes with.

One thing I do not like is its typography, which I find noisy. (Too many combinations—unnecessarily many for such a clean design—of font family, font size, font style, font weight, and font colour). That is easily fixed, however, even with a very basic child theme: Unlike the previous default theme, Kubrick, Twenty Ten supports child themes well.

MORE. The story of the Twenty Ten header images by Matt Mullenweg

Twenty Ten is the only theme bundled with WordPress 3.0, since both Classic and Default (Kubrick) were removed. Both are now at WordPress Extend:

NOTE. When upgrading to 3.0 from an earlier version, Classic and Default are not removed or affected in any way!

Custom menus

The most anticipated of the many “custom” things in this release is probably the new menu creator. It lets you create navigation menus exactly how you want them, and then assign them to predefined menu locations of your theme.

WordPress 3.0: Menu creator WordPress 3.0: Menu creator in action

One thing to note about the custom menus is that they must be supported explicitly by your theme. But you can use them even if your theme does not support them yet: The new Custom Menu widget lets you add any of you custom menus to any of your theme’s sidebars.

Another thing to note is that the custom menus are not always a viable alternative to the methods by which menus were built up to now. Why? Because they are not dynamic. For example, you cannot make an item whose subitems are all existing and future categories; or add a page to the menu and specify that all its current and future subpages be added as subitems.

I imagine theme authors will find ways to deal with that, probably by offering a choice between the two menu systems.

ACCESSIBILITY NOTE. The menu creator is fully functional without JavaScript too.


Custom header and custom background

Two new APIs were introduced that make it easy for theme authors to offer options for custom header images and custom backgrounds. If your theme supports this, you will see the menu items under Appearance. We already saw the Custom Header screen in one of the Twenty Ten screenshots. Here is the Custom Background screen:

WordPress 3.0: Custom Background screen

The tiled image in the screenshot is from ava7 patterns.

DEV. Twenty Ten’s functions.php is a good starting point to see how all this works.

More new things

Selectable username and password during installation

WordPress 3.0: Selectable username and password in installation

Now the installation process lets you choose username and password for the administrator account. That is, you no longer have to use “admin” or the password generated by WordPress. (Of course, you can still use these if you prefer.)

TIP. In earlier versions the admin account can be renamed with a plugin like Admin Renamer Extended.


WordPress 3.0 comes with a new function that themes can use to display a shortlink for the current URL. By default, shortlinks are generated for Posts only (not for Pages or for anything else) and are of the form http://example.com/?p=123. So, for example, the default shortlink for the page you are viewing is:


op111.net uses the shortest possible permalink structure—/%post_id%—, so in this case the default shortlink happens to be longer than the long link, :-D but you get the idea.

Plugins can easily change the default form to anything they like.

DEV. Shortlink functions and their filters are all in link-template.php. Look at the inline documentation of:

  • the_shortlink()
  • wp_get_shortlink()
  • wp_shortlink_header()
  • wp_shortlink_wp_head()

Better security by default

WordPress 2.6 introduced security keys, which help add a bit more security to an installation. WordPress 3.0 adds security keys by default when setting up the configuration file of a new installation:

WordPress 3.0: Setting up wp-config.php, Step 1 WordPress 3.0: Setting up wp-config.php, Step 2, keys and salts

You can change these keys at any time, or add them if you don’t have them, by making new ones yourself or by visiting the Secret Keys Generator at WordPress.org:


(Just copy the whole lot and paste it in your config.php.)

Even more

  • r12523. Check PHP, MySQL versions in update response and notify if reqs are not met. See #11562.
  • r12815. Make login form shake when incorrect info is entered.
  • r13012. Twenty Ten theme initial import. See #9015.
  • r13026. Update keys and salts with random values from api.wordpress.org. See #12159.
  • r13034. Introduce DISALLOW_FILE_EDIT for enabling/disabling theme/plugin editor. See #11306.
  • r13041. r13574. Custom background support. Background color selection. See #12186.
  • r13084. Add setting for no. of comments to Recent Comments dashboard widget. See #11891.
  • r13134. Selectable username/password in installation. See #10396.
  • r13168. r13767. r14237. “Search Engines Blocked” mini-alert when Privacy is on. See #12211.
  • r13233. Show must-use plugins and drop-ins in Plugins screen. See #11861.
  • r13257. r14248. Introduce custom menus. New menu UI. See #11817. See #12713.
  • r13272. Enable threaded comments by default. See #11992.
  • r13276. Add support for non-tag taxonomies to Tag Cloud widget. See #11612.
  • r13403. Header image selector. See #12343.
  • r13424. Reject numeric page slugs (they don’t work) and force suffix. See #11917.
  • r13470. When deleting plugins, check for uninstall routines and warn of data deletion. See #11850.
  • r13516. Better readme.html. See #10835. See it while it’s fresh: http://op111.net/readme.html
  • r13529. Move Upload folder settings to Settings › Media. See #11687.
  • r13541. Display MIME type when file has no extension. See #9924.
  • r13573. Add options to Tools › Export. See #10317.
  • r13587. r13634. Show Network menu only if WP_ALLOW_MULTISITE is true. See #11644. See #11816.
  • r13588. Move Tools › Upgrade to Dashboard › Updates. See #12517.
  • r13602. r13686. New UI for bulk plugin/theme upgrades. See #11232. See #12528.
  • r13636. Don’t paginate comments by default in Settings › Discussion. See #12562.
  • r13744. Remove defunct link update checker from core. See #12437.
  • r13745. Remove empty Options › Misc. Redirect plugin options to Options › General. See #12437.
  • r13750. Change “Blog” to “Site” in Settings screens. (And in any other place in later revisions.)
  • r13824. r13842. r15127. Lighter header/footer for gray color scheme. New logo for header.
    See #12586.
  • r13833. Remove “Turbo” link from admin header. See #11301.
  • r13879. Remove Classic and Default themes. See #10654.
  • r13898. Add link to Updating WordPress (Codex article). See #11280.
  • r13900. Add Password Mismatch feedback to Password Strength Meter. See #12576.
  • r13932. Fix out-of-order comments when nesting depth is reduced. See #8841. Displays child comments on same level as parent when max_depth is reached.
  • r13942. Better default excerpt. Remove multiple white spaces and split safely on UTF-8 strings. See #10376.
  • r13963. Link to new Child Themes Codex article from the Updater. See #12787.
  • r13981. Remove Gears from UI. See #11301.
  • r14010. Update stats provided to api.wordpress.org. See #12672.
  • r14088. Introduce DISALLOW_FILE_MOD for disabling all operations that modify core, theme, or plugin files. See #13000.
  • r14280. Keep “Remember me” checked when user password is incorrect. See #13165.
  • r14324. Change “WordPress Development Blog” to “WordPress Blog” in dashboard widget.
    • r15027. Use “WordPress Blog” (instead of “Development Blog”) in initial blogroll. See #14324.
  • r14487. Improve cross-DST future post publishing behaviour to try and publish at correct time if we have PHP5 timezone support available to help. See #9285.
  • r14491. Bump memory_limit for admins in wp-admin. Should help in imports, upgrades, uploads, etc.
  • r14764. Move importers to WordPress Extend. See #13307.
  • r14836. Contextual Help for Dashboard (and for all admin screens in subsequent revisions). See #13467.
  • r15032. Check capabilities properly when processing bulk edited posts. Hide checkbox on Page edit screen for users without capabilities. (Also in 2.9.x.)

Highlights for developers

The part below this point is for developers, those who like getting their hands dirty, and, of course, the curious.

Multi-site things are mostly omitted here, for two reasons: First, while all are new to WordPress, most existed already in WordPress MU. Second, I know almost nothing about the multi-site functionality.


Backwards compatibility in version 3.0 is in general very good. Areas that may need attention are highlighted in a number of compatibility posts at the WordPress Development Updates blog:


WP_DEBUG and deprecated functions

WP_DEBUG was improved. It now informs of the version as of which a function is deprecated, and it also informs about deprecated arguments. Its definition is included for the first time by default in wp-config.php (set to false, of course), along with the recommendation to enable it when developing.

Why enable WP_DEBUG? Three reasons:

  1. It helps make code better and future-proof
  2. It helps make code faster: Code without errors is faster than code with errors
  3. It helps fellow developers (who won’t have to sift through messages generated by our code when they enable WP_DEBUG to debug their code)

Andrew Nacin has more: Deprecated functions and WP_DEBUG

*_option() and *_transient() functions now expect unslashed data

See the explanation by Ryan Boren, and the relevant ticket:


I believe this new template function will become a favourite of all WordPress developers, theme authors and plugin authors. Just use:


… and you get a comment form that is complete, fully filterable and fully actionable.

DOCUMENTATION. codex.wordpress.org/Template_Tags/comment_form


get_template part() is a new template function that helps avoid repetitive code in themes and makes it easier to modify themes via child themes. Again, usage is simple:


This will bring nav.php in, in the same way that get_header() brings in header.php and get_footer() brings in footer.php.

Of course, the above was already possible with PHP constructs like include and require. What get_template_part() adds to that is granularity and awareness of child themes.

First, it can take a second parameter. E.g.:

get_template_part('nav', 'main');

Here it will first look for nav-main.php and include it if it exists. Otherwise it will include nav.php.

Second, if the active theme is a child theme, get_template_part() looks in the child’s directory first. So, for example, you can add a nav.php template to your child theme, and it will be used instead of the nav.php of the parent.

DOCUMENTATION. codex.wordpress.org/Function_Reference/get_template_part

Hyperminimal themes deprecated

These are themes that rely on the default theme for any of header.php, footer.php, sidebar.php, comments.php, comments-popup.php. This method is now deprecated and may stop working in the future:

Themes and WordPress 3.0: Some important changes by westi (Peter Westwood)

Improved inline documentation

Over the last versions inline documentation has become more or less a requirement for any function, class and file added to WordPress. In addition, supplying documentation where it’s missing, and improving existing documentation, is an ongoing project. So, inline documentation gets better and more useful with every new release. A small example of this ongoing effort:

r12761: phpDoc for the metadata API

The official web interface of the inline documentation was also improved: phpdoc.wordpress.org/trunk

More for developers

3rd-party libraries

New constants

  • r13034. DISALLOW_FILE_EDIT. Banishes theme/plugin editor. (By removing the edit_files, edit_plugins and edit_themes capabilities from all roles.) See #11306.
  • r13737. r14485. WP_DEFAULT_THEME. See #12846.
  • r13587. r13634. WP_ALLOW_MULTISITE. To display Tools › Network menu. See #11644. See #11816.
  • r14088. DISALLOW_FILE_MOD. Disables all operations that modify core/theme/plugin files. See #13000.
  • r15225. ALLOW_SUBDIRECTORY_INSTALL. See #13844. (For conversion to multi-site.)

New action and filter hooks

  • r12790. wp_die_handler. AKA “customizable death”. Filter for wp_die(). See #11892.
  • r13037. r14603. posts_search. Filter. Lets plugins contextually add/remove/modify search section of database query. See #10667.
  • r13073. activate_wp_head. Action in wp-activate.php. See #12166.
  • r13156. r13214. after_setup_theme. Action. Runs after parent/child themes are included. See #12231.
  • r13231. get_avatar_comment_types. Filter for get_avatar(), to allow avatars for custom comment types. See #11880.
  • r13252. template_include. Filter to modify template path before it is included. See #11242. See #12739.
  • r13305. show_advanced_plugins. Filter to hide mu-plugins/drop-ins tabs in Plugins screen. See #11861.
  • r13330. plugin_locale, theme_locale. Filters for load_*_textdomain() functions. See #9686.
  • r13523. tables_to_repair. Filter. See #11707.
  • r13430. pre_insert_term. Filter for wp_insert_term(). See #10943.
  • r13434. comment_duplicate_trigger. Action. Runs when duplicate comment is detected. See #12188.
  • r13549. pre_post_link. Filter for get_permalink() before token replacement occurs. See #12240.
  • r13478. paginate_links. Filter for links in paginate_links(). See #10826.
  • r13479. wp_link_pages_args. Filter for wp_link_pages(). See #12158.
  • r13481. wp_loaded. Action. Runs once WP init has finished. See #12400.
  • r13525. widgets_admin_page. Action at top of widgets.php. See #12190.
  • r13629. before_signup_form, after_signup_form. Actions. See #12199.
  • r13867. right_now_content_table_end, right_now_discussion_table_end. Actions. See #12202.
  • r13891. robots_txt. Filter for robots.txt output. See #11918.
  • r14067. comment_id_fields. Filter for get_comment_id_fields() See #12893.
  • r14382. Actions for the Widgets API. See #12546.
    • register_sidebar
    • wp_register_sidebar_widget
    • wp_unregister_sidebar_widget
    • dynamic_sidebar
    • the_widget
  • r14814. post_updated. Action. Runs when a post is updated. See #12473.
  • r14996. capital_P_dangit. Default filter for the_content(), the_title(), comment_text(). (An addition that will have to be removed or modified, because it causes problems.)

New functions

  • r12487. is_comment_feed(). See #10827.
  • r12598. home_url(). Returns home option in appropriate protocol, HTTP or HTTPS. See #9008.
  • r12609. is_multisite(). See #11644.
  • r12611. is_super_admin(). See #11644.
  • r12659. get_intermediate_image_sizes(). See #10263. For when adding/deleting attachments.
  • r12696. wp_login_form(). Emits complete login form for use in templates. See #11172. CODEX.
  • r12714. is_main_site(). See #11644.
  • r12719. register_post_status(). See #9674.
  • r12796. WP_User::for_blog(), current_user_can_for_blog(). See #11781. To avoid calls to WP_User::_init_caps().
  • r12810. comment_form(). Emits complete comment form for use in templates. See #10910.
  • r12917. get_the_date(). See #11264. Defaults to date_format option. CODEX.
  • r12923. r13023. get_post_permalink(). See #9674. See #12172. Returns permalink for post of custom type.
  • r12946. r14417. get_available_languages(). See #11774. See #13023.
  • r13004. is_textdomain_loaded(). See #10527.
  • r13082. add_plugins_page(). Adds submenu to Plugins page. See #11377.
  • r13146. r13816. r14047. get_template_part(). For themes to bring in template parts. See #12371. See #12248. See #12941.
  • r13177. add_settings_error(). In the Settings API, to register messages for users. See #11474.
  • r13229. wpdb::tables(). To fetch table names on global/blog scope. See #11614. See #12083.
  • r13330. unload_textdomain(). See #9686.
  • r13358. wp_kses_named_entities(). Whitelists valid named entity references. See #12284.
  • r13403. r13928. register_theme_headers(), unregister_theme_headers(). See #12343.
  • r13409. r13806. send_nosniff_header(). Turns off content sniffing in supporting browsers. See #10671. See #12683.
  • r13413. r13526. r14639. r14641. Functions for returning various values to filters:
    • __return_false()
    • __return_true()
    • __return_zero()
    • __return_empty_array()
  • r13438. add_permastruct(), flush_rewrite_rules(). Wrappers for the WP_Rewrite methods. See #10912.
  • r13441. add_editor_style(). Registers stylesheet for visual editor. See #11512.
  • r13454. wpdb::replace(). For replacing queries. See #10864.
  • r13483. get_search_link(). See #10552. Has permastruct support. E.g.: http://example.com/search/foo
  • r13557. the_feed_link(). See #11794.
  • r13576. cache_users(). See #11914.
  • r13608. get_taxonomies(). See #12516.
  • r13635. r13683. wp_get_shortlink(), the_shortlink(), wp_shortlink_wp_head(), wp_shortlink_header(). See #10640.
  • r13658. disabled(). Form helper, companion for selected() and checked(). See #12581.
  • r13718. sanitize_key(). Sanitizes string keys.
  • r13756. apply_filters_ref_array(). See #9886. Like apply_filters(), but args passed are in array.
  • r13819. get_index_template(). So that child themes can override a parent’s index.php. See #12635.
  • r13877. remove_theme_support().
  • r14028. get_the_author_link(). See #12892.
  • r14053. is_post_type_hierarchical(). See #12950.
  • r14067. get_comment_id_fields(). Getter for comment_id_fields(). See #12893.
  • r14360. is_rtl(). See #13206. Defined when locale is loaded, cannot be used too early.
  • r14409. is_child_theme(). See #12998.
  • r14607. wp_reset_postdata(). Restores post global to current post in main query after looping through a separate query. See #12320.
  • r14647. _ex(). Combines _e() and _x(): Translate with context, then echo. See #13395.
  • r14649. wp_check_filetype_and_ext(). To handle MIME/ext image comparisons/corrections for upload/sideload. See #11946.
  • r14711. get_term_feed_link(). Returns feed link for taxomomy term. See #13058.
  • r14760. WP_Importer class. See #13034. phpDoc.
  • r14950. comments_link_feed(). Echoes link to comments of current post properly escaped for XML. See #13555.
  • r15174. get_current_user_id(). See #13785.
  • r15193. register_nav_menu(), register_nav_menus(). For themes to register one or more menus. See #13825.
  • r15203. menu_page_url(). For plugin authors, to get URLs of pages they have added. See #13829.
  • r15220. r14158. post_type_exists(). Checks if post type is registered. See #13747. See #12588.

Improved and modified functions

  • r12514. the_modified_date(). New before/after/echo args. See #11255.
  • r12518. get_comments(). More orderby and select options. See #10668.
  • r12558. WP_Dependencies. New null arg to disable script/CSS version query strings. See #11315. Useful, e.g., when scripts are loaded from an external CDN.
  • r12658. get_terms(). Now include and exclude args can be arrays. See #11076.
  • r12667. wpdb class. Compatibility with WP, MU & MS. See #11644. wp-db.php changelog.
  • r12719. register_post_type(). See #9674. CODEX
  • r13048. get_search_form(), wp_loginout(), wp_register(), get_calendar(). New echo arg. See #11842.
  • r13350. post_class(). New .type-{post_type} class. See #11609.
  • r13417. add_theme_support(). New custom-background, custom-header, nav-menus params. See #11817.
  • r13467. single_(post|cat|tag|month)_title(). Filters standardized on strip_tags() and wptexturize(). See #10900.
  • r13483. get_search_feed_link(), get_search_comments_feed_link(). Updated to use get_search_link() (new, with permastruct support). See #10552.
  • r13486. is_tax(). New term parameter. See #11904.
  • r13673. *_option(), *_transient(). Now consistently expect unslashed data. See #12416.
  • r13695. get_pages(). Now supports custom hierarchical post types. See #12600.
  • r13773. add_endpoint(). Now accepts custom Endpoint Mask. See #12605.
  • r13854. wp_list_categories(). Now aware of custom taxonomies. See #11838.
  • r13952. wp_unique_filename(). Now methods too can be a callback. See #12824.
  • r13978. get_search_query(). Now escapes by default, like the_search_query(). See #12780.
  • r13982. wpautop(). New block-level HTML5 elements. See #12335.
  • r13995. wp_delete_comment(). New force_delete arg. See #12766. See #11470.
  • r14095. wptexturize(). Improved for single quotes. See #4539. (Abbreviated years followed by punctuation or markup.)
  • r14131. wp_list_bookmarks(). Now orberby accepts comma-delimited list of fields. See #12421.
  • r14133. get_posts(), get_pages(). Now include/exclude args can be arrays. See #11076.
  • r14766. stripslashes_deep(). Attempt to make object-safe. See #12860.
  • r14887. is_singular(). Now understands custom post-types. Usage: is_singular('book') or is_singular(array('newspapers', 'books')). See #12588.
  • r15002. r15003. wp_constrain_dimensions(). Tweaks for better fits and consistency. See #13556.
  • r15107. wp_list_categories(). Now filter accepts args. See #13682.
  • r15188. get_page(). Now alias of get_post(). See #13753.

Deprecated functions and their replacements

  • r12526. Set version when function was deprecated for all deprecated functions. See #7493.
  • r12536. Introduce _deprecated_argument() for marking args as deprecated, so that with WP_DEBUG enabled developers can see they need to review and update their code. See #11386.
  • r13185. Add WP_DEBUG define to wp-config-sample.php and suggest plugin/theme developers use it. See #12236.

Following is a not complete list of functions added to the deprecated group in WordPress v3.0:

You don’t need to memorize all that, of course! Simply enable WP_DEBUG, and it will tell you if there is anything you should not be using.

  • r12459. _nc(). Use _nx() for specifying contexts. See #11404.
  • r12585. Deprecate user levels. See #10805. Use Roles and Capabilities instead.
  • r12624. generate_random_password(). Use wp_generate_password(). See #11746.
  • r13093. Move deprecated functions to deprecated.php. See #11388.
    • get_the_attachment_link(). Use wp_get_attachment_link().
    • get_attachment_icon_src(). Use wp_get_attachment_image_src().
    • get_attachment_icon(), get_attachment_innerHTML(). Use wp_get_attachment_image().
    • get_link(). Use get_bookmark().
  • r13096. Deprecate old L10n and sanitization APIs. See #11388.
    • ngettext(). Use _n().
    • ngettext_noop(). Use _n_noop().
    • translate_with_context(). Use _x().
    • sanitize_url(). Use esc_url_raw().
    • js_escape(). Use esc_js().
    • wp_specialchars(). Use esc_html().
    • attribute_escape(). Use esc_attr().
  • r13299. clean_url(). Use esc_url(). See #12309
  • r13300. *_usermeta() family. Use new *_user_meta() functions. See #10837.
  • r13398. automatic_feed_links(). Use add_theme_support('automatic-feed-links'). See #12364.
    • r13399. Restore back compat in automatic_feed_links() to deregister the extra feeds. See #12364.
  • r13464. get_profile(). Use get_the_author_meta(). See #10695. CODEX.
  • r13761. get_usernumposts(). Use count_user_posts(). See #12642.
  • r13805. (add|remove)_option_update_handler(). Use (un)register_setting(). See #11730.
  • r13988. funky_javascript_fix() and callback. See #12520.
  • r13991. trackback_rdf(). See #11139.
  • r14090. set_current_user(). Use wp_set_current_user().
  • r14646. get_bloginfo('text_direction'). Use is_rtl(). See #13206.
  • r15168. r15170. get_most_active_blogs(), get_blog_list(). See #13773.
  • r15220. Replace misnamed is_*() functions with *_exists() ones. See #13747.
    • is_taxonomy(). Use taxonomy_exists().
    • is_term(). Use term_exists().

Performance, optimization

  • r11976. Improve get_page_hierarchy(). See #10853.
  • r12464. Improve do_action() performance. Make $wp_actions an associative array. See #10561.
  • r12657. Switch to passing arrays instead of query strings to functions. See #6647.
  • r13143. Optimize single_(post|tag|cat)_title() to use WP_Query globals if available. Removes extra DB query in single_post_title() in most cases.
  • r13205. Bail early for favicon.ico requests so we don’t load WP twice. See #3426. Reduces server load when certain browsers arbitrarily request /favicon.ico and /favicon.ico does not exist.
  • r13227. Add INDEX on comment_parent to speed up wp_delete_comment() reparenting queries. See #12289.
  • r13576. Improve user listing performance. See #11914.
  • r13647. Add no_found_rows arg to WP_Query::get_posts() to allow forcibly defeating SQL_CALC_FOUND_ROWS. Use no_found_rows for the query in get_boundary_post(). See #12557.
  • r13653. Cache get_lastpostmodified() results. See #12575.
  • r13676. Don’t check for existence of index.php in .htaccess rewrite rules. See #11845.
  • r13676. Use wp_cache_set() instead of wp_cache_add() in Recent Posts and Archives widgets. See #11580.
  • r14139. Use relative paths when including files, to avoid include_path. See #12594.
  • r14665. Don’t update_post_caches() if a persistent object cache is installed. See #12611.


  • r12602. Add multi-site settings code. Here starts the MU merge!
  • r12641. Allow attaching PHP 5.3 closures to filters and actions. See #10493.
  • r12727. Always set default timezone to UTC. Do offsets on top of that to be portable across all environments. See #9588. See #11665. See #11672.
  • r12914. Add phpDoc to all add_*_page() functions. Rename arguments to emphasise that people should be using Capabilities, not User Levels, and named hooks, not __FILE__. See #12101.
  • r12915. Support specific author templates by ID or user_nicename. See #12064.
  • r13032. Look for single-*.php templates. Add single- class to get_body_class(). See #12105.
  • r13167. r13452. r15017. Warn of unexpected output when activating plugins. See #12089. See #13585.
  • r13427. Use is_ssl() instead of $_SERVER['HTTPS'] == 'on' checks (which don’t work on all hosts). See #11885.
  • r13433. Consistently pass unserialized values to hooks in update_site_option(). Change add_option() and add_site_option() to do the same. Plugins using maybe_unserialize() would continue to work as the value would no longer need to be unserialized. See #10788.
  • r13484. Support non-BASIC authentication schemes in HTTP API if server supports them. See #4011. See #12200.
  • r13499. Display PHP start-up errors and warnings. See #12395.
  • r13456. Allow multiple To: recipients in wp_mail(). Improve handling of \r\n in headers and multiple CC/BCC headers. See #10420.
  • r14086. Register inherit as post status. Check parent post status when commenting on attachments.
  • r14111. Introduce edit_theme_options capability.
  • r14276. Introduce template file for front page. Has priority over other templates which apply, falls back to standard template flow for the page/list of posts. See #6801. CODEX.
  • r14406. Add HTML5 elements to KSES. See #12835.
  • r14412. Add protocols to KSES, make protocol list filterable, start esc_url() with same list. See #10914.
  • r15096. Introduce export capability. See #13681.
  • r15239. Missile guidance capabilities.

That’s it, folks!

I wish you enjoy WordPress 3.0 (once it’s officially out!) and you publish even better content with it!

Thanks for reading!


Changes in this document

Fixed link to phpdoc.wordpress.org/trunk.
Link to the story of the Twenty Ten headers.
Link to issues thread at the official forum.
Additions. “Known issue” of insufficient memory for upgrading.
What you need to return from multi-site to single-site (see comment no. 3 by Ron). Fixed link to Ryan Boren on *_(option|transient)() functions and unslashed data.
Additions. Typos. WP/MU/MS terminology explanation corrected (see comment no. 1 by Andrew Nacin).
Additions. Link to Otto on custom post-types.
Improvements, additions, new links. WP/MU/MS terminology explanation to be corrected. Link to improved webif of inline docs. Link to wpdevel compatibility posts.

Comments (6)

  1. Andrew Nacin says:

    This was an incredible write-up and aggregation of so much work over the last few months — thanks!

    Just a note, you did indeed botch the terminology changes. :-) We’ve changed “blog” to “site,” and for regular users of WordPress, that’s the only thing they’d notice. For MU users, things get more complicated. The concept of a “site” in MU is a collection of blogs, but we’re now calling that a “network.”

    When you’re running domain mapping, you’d have multiple MU “sites,” but now in 3.0 you’d be running multiple “networks” on the same installation. Then again, a domain mapping plugin may choose to keep the “network” terminology as covering the entire installation, then introduce “domain” to talk about each domain. But that’s outside the scope of core currently.

  2. demetris says:

    Thank you, Andrew!

    I knew I was too hopeful about my terminology explanation. :-D Added a note for now, and I will fix it later.

  3. Ron says:

    Another note/correction – People who convert their single WP installs into a network can revert back to the original single WP install by restoring their original wp-config.php & .htaccess.

    The only change that is made to the original single WP during the network install is the permalinks.

  4. demetris says:

    Thanks, Ron!

    I wrote that (“you may not be able to…”) on purpose, but I was not happy with it. Changed it now to say that people should make copies of these two files.

  5. demetris says:

    An op111.net reader asked about the HeadSpace2 issue that I mention at the start. I describe the problem, along with what I did to solve it, at the HeadSpace2 bugtracker:


  6. Michel says:

    Amazing write-up, detailed, that was very helpful to me.

    Just wanted to thank you!

Write a comment

Your email address will not be published. Required fields are marked *