WordPress.org

Make WordPress Core

Welcome to the official blog of the core development team for the WordPress open source project.

Here, we make WordPress core. Follow our progress with general updates, status reports, and the occasional code debate.

We’d love for you to help out.

Looking to file a bug?

It’s easy to create a ticket on our bug tracker.

Want to contribute?

Get started quickly. We have some tickets marked as good first bugs for new contributors. There’s more on our reports page, like patches needing testing.

We also have a detailed handbook for contributors, complete with tutorials.

Weekly meetings

We use Slack for real-time communication. As contributors live all over the world, there are discussions happening at all hours of the day.

We have a project meeting every Wednesday at 20:00 UTC in the #core channel on Slack. (Find out more about Slack.)

You can find meeting agendas on this blog. You’re welcome to join us or listen in.

Recent Updates Toggle Comment Threads | Keyboard Shortcuts

  • Grant Palin 2:38 am on May 5, 2016 Permalink |
    Tags: ,   

    Week in Core, April 26 – May 3 2016 

    Welcome back the latest issue of Week in Core, covering changes [37314-37354]. Here are the highlights:

    • 40 commits
    • 33 contributors
    • 78 tickets created
    • 8 tickets reopened
    • 70 tickets closed

    Ticket numbers based on trac timeline for the period above.

    Code Changes

    Administration

    • improve the Star Ratings hiding empty elements for assistive technologies. [37330] #36725
    • This patch assigns the background color to body instead of the html element. [37321] #35314

    Build/Test Tools

    • Include npm prune in the before_script command. npm prune removes extraneous packages so the cache contains only current modules. [37340] #36490
    • Document WP_UnitTestCase->go_to() [37319] #36679

    Comments

    • date_query should be a property on WP_Comment_Query objects, nstead of a local variable. [37354] #36741
    • Realign parameter documentation in the DocBlocks for comment_author_email_link() and get_comment_author_email_link(). Also adds a missing return description for get_comment_author_email_link(). [37349] #36571
    • Adjust comment_author_email_link() and get_comment_author_email_link() to each accept a new optional fourth parameter, $comment, which enables overriding the $comment global. Adds tests. [37348] #36571
    • Display the comment counts in wp_dashboard_right_now() in the rare initial condition when there are 0 approved comments and only pending comments, so the AJAX count update could work. [37335] #35519
    • Pass $comment to comment_text() in Walker_Comment::comment() instead of using a function which can skip the cache. [37325] #35433

    Customize

    • Handle filtering sidebars_widgets when the underlying option is non-existent. See #36389. Fixes #36660. [37352] #36389, #36660
    • Pass WP_Customize_Setting instance as second argument to customize_value_{$id_base} filter. [37350] #36452
    • Allow Esc key to collapse the currently-expanded panel, section (or control). [37347] #22237
    • Ensure settings modified during an open save request remain dirty when save request completes. [37346] #32941
    • Increase the target size of the expand/collapse button in the customizer. [37341] #36093
    • Don’t auto-close the customizer when a new theme is activated. [37339] #35320
    • Remove format placeholders from widget templates and selectors, fixing a jQuery selector syntax error and the broken highlight/shift-click behaviors. [37322] #36473

    Database

    Docs

    • Improve the class DocBlock for WP_Widget to clarify which methods “should” vs “must” be overridden by extending sub-classes. [37343] #36703
    • Remove inline @see tags from function, class, and method references in inline docs. [37342] #32246
    • Add backtick escaping for two inline code samples in docs. [37338] #32246
    • Standardize on using :: for Class::method() references in WP_Customize_Control inline docs. [37337] #32246
    • Document the @return value of wp_add_trashed_suffix_to_post_name_for_post(). [37334] #36728

    Links

    • Rename the $link_id parameter in get_link_to_edit() to $link to better reflect that it can accept a link ID or object. [37353] #36736
    • Clarify documentation for the $link_id parameter to mention that it accepts either an integer or object. [37351] #36736

    Plugins

    • In plugin_basename() normalize the file path before unresolving symlinks. [37332] #29154
    • In uninstall_plugin() pass the plugin file to wp_register_plugin_realpath(). [37331] #36709

    Posts

    • Allow get_page_uri() to be called without a $page argument. [37345] #26284

    Query

    Tests

    • Ensure that image sizes are indeed removed when errors are raised before assertions in Tests_Media. [37328] #36588
    • Ensure that the GD absrtraction is used for GD unit tests for Images. [37327] #36588
    • Remove debug cruft left over from [34816]. [37344] #17078
    • Reduce unnecessary count in create_many() in multisite user tests. [37318] #36566

    Themes

    Users

    Widgets

    • Provide PHP 5.2 fallback for spl_object_hash() if disabled in logic for registering and unregistering pre-instantiated widgets. [37333] #28216
    • Allow WP_Widget subclass instances (objects) to be registered/unregistered in addition to WP_Widget subclass names (strings). [37329] #35990, #28216
    • When the Inactive Widgets section is hidden also hide the “Clear Inactive Widgets” button description text. [37323] #35592

    Props

    Thanks to @afercia, @andy, @boonebgorges, @celloexpressions, @chandrapatel, @DrewAPicture, @ericlewis, @flixos90, @flyingdr, @Frank-Klein, @jdgrimes, @jeremyfelt, @jsternberg, @kjbenk, @martinkrcho, @mdwheele, @michaelarestad, @netweb, @ocean90, @PeterRKnight, @pollett, @purcebr, @r-a-y, @rachelbaker, @SergeyBiryukov, @Shelob9, @tloureiro, @voldemortensen, @vortfu, @websupporter, @welcher, @westonruter, and @wonderboymusic for their contributions!

     
  • Weston Ruter 10:52 pm on May 4, 2016 Permalink |
    Tags: ,   

    Improving Setting Validation in the Customizer 

    In #34893 and the accompanying Customize Setting Validation feature plugin I’ve suggested improvements to the Customizer setting validation model. More can be read about the proposal in that ticket description and plugin readme, but the short of it is that settings in the Customizer generally undergo clean-up sanitization but lack a robust system for pass/fail validation. Here is a video demo depicting what I think validation should look like in the Customizer:

    Normally the Customizer just sanitizes values by attempting to coerce them and clean them up into something that can be safely used (e.g. stripping tags). As for validation, and while I believe this is relatively unusual to encounter, you can also do strict validation of a setting by blocking it from being saved: this is done by returning null from WP_Customize_Setting::sanitize() (often via  WP_Customize_Setting::$sanitize_callback). This is the behavior for setting the background_color: if the value is not a valid hex code, it will not save. The problem here is that there is no feedback to the user that the save was blocked. If user tries to enter “blue” as a color instead of a hex code, they will not get informed that this is invalid: it will be as if they never tried to save any change at all. Incidentally, this is also the case for widgets, where the WP_Widget::update() normally just sanitizes the instance arrays, though it can return false to block an update, with likewise no indication that the update was blocked.

    Additionally, in the current validation system, if you have made 10 changes in your Customizer session (transaction), but half of them get blocked from saving due to being invalid, then you have an only partially-saved Customizer state. This is a really bad experience for sites that make heavy use of the Customizer beyond just using it to tweak some colors.

    So to summarize the suggested improvements to validation in the customizer:

    1. All modified settings should be validated up-front before any of them are saved.
    2. If any setting is invalid, the Customizer save request should be rejected: a save thus becomes transactional with all the settings left dirty to try saving again.
    3. Validation error messages should be displayed to the user, prompting them to fix their mistake and try again.

    All of the above is implemented in the Customize Setting Validation feature plugin, and I’d love your feedback on it. One thing in particular I need feedback on is how specifically a setting should go about performing validation on the server. As noted above, the WP_Customize_Setting::sanitize() method can currently do both sanitization (returning a cleaned-up value) and validation (returning null to block saving if value is beyond repair). In the current feature plugin, I’m proposing:

    1. Continue to use the same sanitize methods/callbacks/filters.
    2. Introduce a new $strict param to indicate that validation is being performed.
    3. Allow these functions to fail validation by returning WP_Error instances with information about what failed in addition to null as they can today.

    How the changes would look for WP_Customize_Setting::sanitize():

    /**
     * Sanitize an input.
     *
     * @since 3.4.0
     * @since 4.6.0 Added `$strict` param to indicate validation is being performed.
     *
     * @param string|array $value  The value to sanitize.
     * @param bool         $strict Whether validation is being performed.
     * @return string|array|null|WP_Error Null or WP_Error if an input isn't valid, otherwise the sanitized value.
     */
    public function sanitize( $value, $strict = false )
    

    And for the customize_sanitize_{$id} filter:

    /**
     * Filter a Customize setting value.
     *
     * @since 3.4.0
     * @since 4.6.0 Added `$strict` param to indicate validation is being performed.
     *
     * @param mixed                $value  Value of the setting.
     * @param bool                 $strict Whether validation is being performed.
     * @param WP_Customize_Setting $this   WP_Customize_Setting instance.
     */
    return apply_filters( "customize_sanitize_{$this->id}", $value, $this, $strict );
    

    This should be nicely backwards-compatible, and allow for the sanitize/validate logic to be kept in the same function since they are very closely related. But that raises some questions:

    1. Should there be a separate WP_Customize_Setting::validate() method as well that by default calls WP_Customize_Setting::sanitize() with the $strict param set to true?
    2. Should validation only be applied when saving the setting while mere sanitization is required for previewing a value change?

    On the second point here, my thought is that it may often be the desire for looser cleanup sanitization to be applied to a value during data entry. Consider a blob of text displayed on the page which forbids the use of markup. As I do data entry I may like to see what I am entering being displayed in the preview with the tags stripped (normal behavior today) whereas when I try saving I can be alerted that saving the value with markup is not allowed. This would provide the user with feedback as to why the markup is mysteriously not appearing in the preview. (As for providing this validation feedback while the user entering data, this should be done via JS, or the validation state be determined by performing validation in an update-transaction request for transactions.)

    I’ll also note that REST API supports both sanitization and validation for request args, but these are handled in two separate callbacks. The way it works is that any registered sanitize_callbacks are applied first, followed by setting of default values, and then the validate_callbacks are run. See WP_REST_Server::dispatch(). This works fine, but I think we could have more flexibility if the sanitization and validation logic could be in the same method. Perhaps you want to run sanitization before validation (sanitize by stripping tags and validate to ensure the value is not empty), or be more strict by running validation before sanitization (reject any text that contains markup entirely).

    So, for you all who develop settings in the Customizer, what are your thoughts on how validation should behave, and how validation should relate to sanitization in the context of the Customizer? What do you think of the API changes I’ve proposed?

     

     
    • Aristeides Stathopoulos 12:14 am on May 5, 2016 Permalink | Log in to Reply

      I like it!

      I wanted to do something similar for a “dimension” control in the Kirki plugin and ended up doing it via JS (demo on https://youtu.be/2cM6WPKNdfs, JS validation function on https://github.com/aristath/kirki/blob/2.3.2/assets/js/functions/validate-css-value.js) but I like your approach a lot better than mine… and we definitely need it.

      Should there be a separate WP_Customize_Setting::validate() method as well that by default calls WP_Customize_Setting::sanitize() with the $strict param set to true?

      I believe that would be best, yes. validation and sanitization are different concepts, they should have different functions, even if internally they’re the same thing. It’s a simple thing to do, but will save us a lot of trouble down the road in support and explaining things to people. We should make it easier to understand, and “use the validate method to validate the function” is a lot better than “add a 2nd argument to the sanitization function function and set it to true if you want to validate instead of sanitize”.

      Should validation only be applied when saving the setting while mere sanitization is required for previewing a value change?

      Shouldn’t that be the other way around? Or is my migraine playing tricks on me?
      IMO we should have sanitization on save, and validation to allow/disallow saving, and also to trigger/skip triggering the preview refresh/postMessage.

      • Weston Ruter 12:50 am on May 5, 2016 Permalink | Log in to Reply

        @aristath:

        Shouldn’t that be the other way around? Or is my migraine playing tricks on me?
        IMO we should have sanitization on save, and validation to allow/disallow saving, and also to trigger/skip triggering the preview refresh/postMessage.

        Maybe what I wrote isn’t very clear. I meant to say that in both the case of previewing a setting change and saving a setting, the sanitization should be applied. I was suggesting that the validation (strict sanitization) would be an additional check that is done only on save when persisting the value to the database.

        But it sounds like you’re saying that validation should be done every time in addition to sanitization. Is that right? It would be a challenge to block previewing changes to such values since at the moment the sanitize callback is normally only run after a refresh has been requested, and for postMessage previews there is normally no server-side communication at all, so PHP sanitization/validation logic would be involved, and it would be up to JS to implement the setting.validate() method to catch those issues.

        For settings with the refresh transport, there would be a possibility to use PHP validation to block previewing of invalid settings only if transactions is implemented. How I think transactions will work is every time you make a change to a setting, the Customizer would first do an Ajax request to push the new changed setting into the current transaction post. Once the value has been saved into the post and the update-transaction Ajax request returns, then a refresh can be done so that the preview can re-render with the new value stored in the transaction. It’s here with the update-transaction request that we could call the PHP setting validation function and the response could include any failure information, and then prevent the preview from refreshing. Does that make sense?

    • Aristeides Stathopoulos 1:25 am on May 5, 2016 Permalink | Log in to Reply

      it sounds like you’re saying that validation should be done every time in addition to sanitization. Is that right?

      Correct. Just a thought though, it has its pros and cons…

      As for blocking refreshes etc, I agree that it’s going to be hard via PHP, so perhaps we should consider implementing something in the JS side of the Customizer API too?

      We can add a validate method on the PHP side, and we could also just extend the controls in JS and add a validation method there too. This way it’s up to the developer how they’re going to implement it.
      If they need realtime validation and blocking refreshes for example when a value is invalid as I did, then using the JS method makes more sense.
      If they need something simpler or just don’t need to block the preview refresh they can use the PHP method.

      The transactions concept makes sense… but that would only work on settings with `transport` set to `refresh`, right? From what I’ve seen people are slowly trying to get away from that and are trying to implement `postMessage` more and more.
      So again, we’d need a way to make it work no matter what they’re using as `transport`.

      • Weston Ruter 3:40 am on May 5, 2016 Permalink | Log in to Reply

        @aristath:

        As for blocking refreshes etc, I agree that it’s going to be hard via PHP, so perhaps we should consider implementing something in the JS side of the Customizer API too?

        This can be done today, although I don’t think I’ve ever seen it done in the wild. Consider:

        
        wp.customize('blogname').validate = function( value ) {
            if ( /<\/?\w/.test( value ) ) {
                console.warn( 'Markup not allowed in site title.' ); 
                value = null; 
            } 
            return value;
        };

        This has the effect of blocking the user from being able to supply an illegal value. The console.warn() could be replaced with a call to update some validation message instead, or we could improve core to allow these validate functions to even return an Error object for parity with the PHP pattern I showed above.

        The transactions concept makes sense… but that would only work on settings with `transport` set to `refresh`, right? From what I’ve seen people are slowly trying to get away from that and are trying to implement `postMessage` more and more.

        To prevent invalid setting values from being sent to the preview, yes. That is unless they implement a JS-based validate as well, as I showed with the blogname above.

        I’m thinking more now that validation should be done with sanitization in all cases now, instead of just when saving.

      • Weston Ruter 7:22 am on May 5, 2016 Permalink | Log in to Reply

        @aristath: Please give a try to the latest version of Customize Settings Validation (on GitHub) and try it with the JS Widgets. Then add a Text widget and you should see some helpful validation messages appear when you try entering markup into the title field. Here’s the corresponding logic that handles that: https://github.com/xwp/wp-js-widgets/blob/dce6d507ebade7b645220a9c843bb2b02198ef9a/js/widgets/customize-widget-text.js#L90-L98

    • NateWr 9:24 am on May 5, 2016 Permalink | Log in to Reply

      Sounds great.

      So looking at the code, it looks like each control needs to have a dummy element inside it’s template with the class `.customize-setting-validation-message`:

      https://github.com/xwp/wp-customize-setting-validation/blob/master/js/customize-setting-validation.js#L104

      Do you have any thoughts on how this could be used for controls that manage multiple settings?

  • Hugo Baeta 9:48 pm on May 4, 2016 Permalink |
    Tags: , cross-posting, design chat   

    x-post from make/design:

    Weekly Design Chat revival + call for topics

     
  • Konstantin Obenland 7:43 pm on May 4, 2016 Permalink |
    Tags: ,   

    Shiny Updates Chat Summary 5/3/16 

    This is a summary of the shiny updates chat from May 3. (Slack log)

    Attendees: @ocean90, @swissspidy, @ethitter, @adamsilverstein, @mapk, @obenland

    Topics:

    • Accomplished work since last week
    • Remaining work
      @obenland will work on the Shiny Updates landing page for feature projects and fix a bug that were discovered during the most recent user test. @mapk offered to conduct another user test focused on the new interactions with some learnings from the previous one. Goal is to identify any hiccups or behaviors that are unexpected to users. @swissspidy wants to continue working on update-core.php and see if we can get it into shape for 4.6.
    • Most recent user tests
      We briefly talked about the most recent user test (linked above). It showed a variety of bugs that @obenland initially assumed were based on being in subviews of the plugin list. After the meeting it turned out that the test site ran an outdated version of WordPress that didn’t include some of the date that Shiny Update needs to work. It was a good demonstration of progressive enhancement here though, as all actions still worked, they just weren’t shiny. More user tests to come, to make sure that users agree with the new interactions.
    • Schedule for 4.6 inclusion
      Next up is writing the merge proposal that was requested to be published around 6/1, definitely before 6/8.

    Next meeting is on Tuesday May 10, 19:00 UTC.

     
    • Scott Fennell 7:55 pm on May 4, 2016 Permalink | Log in to Reply

      Hello! I have a question about the shiny updates work — and thanks for the work, by the way.

      I have written a plugin for my own personal use (not a .org plugin) which allows me to use the core update class for updating plugins/themes that are hosted in a private bitbucket account. It works by flitering the plugin/theme data at `pre_set_site_transient_update_plugins` and `pre_set_site_transient_update_themes`.

      I was wondering if the shiny updates work could jeopardize either of those filters. Would you be able to comment on this concern?

      Aside: My plugin is pretty similar to a more well-known project called GitHub Updater.

      • Konstantin Obenland 8:03 pm on May 4, 2016 Permalink | Log in to Reply

        Hi Scott, thanks for your feedback!

        Shiny Updates doesn’t use these filters, it’s more focused on the UI of installing/updating/deleting plugins and themes. I’d encourage you though to download and activate the plugin to test how it interacts with your plugin just to make sure (and maybe let us know if you encounter any bugs or weird behavior).

    • Andy Fragen 8:03 pm on May 4, 2016 Permalink | Log in to Reply

      Hey Scott! Aside from some styling changes that will likely need to be made, the functionality of GHU and Shiny Updates work great together.

  • Weston Ruter 6:51 pm on May 4, 2016 Permalink |
    Tags: ,   

    Customize Office Hours Recap (May 2, 2016) 

    Early this week, @celloexpressions led a bug scrub for the Customize component which can be read in the chat logs. We did a bug scrub for the tickets milestoned for 4.6. Some highlights:

    • Transactions (#30937) is a high priority due to it resolving several other tickets. I (@westonruter) will try to make headway this week. Tickets impacted by this include (among others, since this a low-level architectural change for the Customizer):
      • #30028: Load Customizer preview iframe with natural URL
      • #20714: Theme customizer: Impossible to preview a search results page
      • #23225: Customizer is Incompatible with jQuery UI Tabs.
      • #31517: Customizer: show a notice after attempting to navigate to external links in live previews
      • #34142: Links with preventDefault() don’t have action prevented in Customizer
      • #28227: Customizer: Error message instead of blank screen
      • #31641: Theme Preview using “Customize.php” error
      • #22037: Customizer: Live preview fetches page but does not display
    • We discussed improvements to the Customizer setting validation model (#34893) and how they relate to transactions. I’ll be writing a separate Make Core post to get feedback on it.
    • Global notification area and control-level notification areas were discussed. The global notification area (#35210) would be used for general Customizer notices/errors, such as fatal errors during save (#31582), whereas the notification are proposed for the in the setting validation model improvements (#34893) could be used for control-level notifications, like an error to uploading an image to a media control (#29932). Work is needed on the global notification area API and UI. Ideally the same API could be used at the control level, where there could be a wp.customize.notifications collection but also a wp.customize.control(...).notifications collection, both of which would be instances of the same NotificationCollection. Help wanted.
    • The customize_value_{$id_base} filter now has the $setting object passed as the second param (#36452). The related ticket to add more actions/filters for implementing value and preview interfaces without subclassing WP_Customize_Setting (#29316) has been punted.
    • A new “Edit Menu” button for the Custom Menu widget in Customizer (#32683) will get a new patch from @celloexpressions.
    • Simplification of the Customizer image control action buttons (#36175) needs some design/UX feedback, and letting the image placeholder be clickable (#34323) was also discussed and also needs feedback.
    • Cleaning up the Customizer media control CSS (#30618) will get another patch from @celloexpressions this week.

    We will be doing weekly meeting (office hours, triage, bug scrubs) at 20:00UTC on Mondays. See upcoming meetings for the next time.

     
  • Rachel Baker 4:07 pm on May 4, 2016 Permalink |
    Tags: , ,   

    Comments Component Bug Scrub – May 9, 2016 

    A bug scrub focused on open tickets in the Comments component will be held in the #core channel on Slack at May 9, 2016 19:00 UTC.

    Meeting Goals

    1. Give attention and feedback to the tickets gathering dust in the Awaiting Review milestone
    2. Reduce the number of tickets in the Awaiting Review milestone to 20 (currently at 37)
    3. Have an open floor for anyone to request feedback for any Comments component ticket

    If you have a ticket you want included in the open floor feedback leave a comment below. I promise to “read the comments”.

     
  • Dominik Schilling (ocean90) 8:00 am on May 4, 2016 Permalink |
    Tags: , ,   

    Weekly Dev Chat Agenda for May 4 — Two Weeks Later 

    Agenda for the weekly dev meeting on May 4 2016 at 20:00 UTC:

    • Update on WordPress 4.5.2
    • Triage of tickets with the “early” keyword
    • Call for designers/reviving the chats
    • Feature Project Updates (Please prepare your status update in advance.)
      • Decision time for: #36753 Use system fonts for a faster, more native-feeling admin (Font Natively)
    • Component Updates (Please prepare your status update in advance.)
    • Discussion: How to name new functions? get_sites/networks() vs wp_get_sites/networks()
    • Open Discussion

    If you have anything to propose to add to the agenda, please leave a comment below.

    See you in the chat!

     
  • Jeremy Felt 6:45 am on May 4, 2016 Permalink |
    Tags: , ,   

    Multisite Office Hours Recap (May 3, 2016) 

    Multisite office hours are held every Tuesday at 16:00 UTC in #core-multisite. The next will be Tuesday 16:00 UTC. A more casual bug scrub is on Thursday 20:00 UTC.

    The weekly agenda for the 4.6 cycle is to (a) address blockers and share status on bigger initiatives, then (b) walk through a few multisite focused tickets on Trac.

    Today’s chat log

    Attendees: @ocean90, @flixos90, @spacedmonkey, @rachelbaker, @jeremyfelt, @johnjamesjacoby, @mikelking

    Tickets Covered

    There was some great conversation around a handful of tickets that took the hour.

    • #35791, WP_Site_Query has been continuing to make good progress. Existing core unit tests pass with the latest patch. These primarily test wp_get_sites(). Tasks for the next couple weeks include writing more new unit tests for WP_Site_Query() itself, testing the patches, and gathering additional feedback. The target commit date is May 12th. Please leave feedback on the ticket! 🗒
    • #32504, WP_Network_Query is also looking like a possibility for the 4.6 cycle. Additional feedback on supported arguments and use cases for WP_Network_Query is more than welcome at this point.
    • Which brings us to naming. 🤓 We need to determine if get_sites() is appropriate or if we should stick with wp_get_sites(). The only trouble with the current form (wp_get_sites()) is that an array of arrays is returned rather than an array of objects. Introducing get_sites() would allow us to deprecate wp_get_sites() and follow previous work like get_posts(), get_users(), get_comments(). The same question exists for networks and get_networks(). A related ticket there is #29415.
    • And more naming. #36717 introduces magic getters so that id will be available on WP_Network and WP_Site objects, site_id will be available for the main site on a WP_Network object, and network_id will be available on a WP_Site object. The changes seem sane, there are probably a few additional details to sort out.

    And a couple tickets left over from last week that should be mentioned to continue progress:

    • #15800 remains super close. @johnjamesjacoby is going to adjust the patch and we’ll see if it can go in this week.
    • #34941 would enjoy some review. This wraps a large chunk of the multisite bootstrap process, so the more eyes the better. 😅
     
  • Eric Andrew Lewis 2:12 pm on May 3, 2016 Permalink |
    Tags: , ,   

    A data schema for meta 

    register_meta() is a tiny function, which lets you register a sanitization and authorization callback for post meta, term meta, user meta or comment meta.

    We’re going to expand the utility of this function to describe the data type of the field. This will be useful for the REST API as well as the Fields API.

    This discussion has started in #35658, but I’d like to share the latest thoughts for general feedback.

    Imagine a “movie” custom post type which has a “star-rating” post meta field, which should accept the value 1, 2, 3, 4 and 5. REST API clients like the iOS app would want to know this information, so they can offer appropriate UI for their users. Ditto for the Fields API.

    Here are some loose thoughts on what that API might look like.

    Here is a post meta field for “mood” that accepts any string. The value would fit in a single row. There would only be one row per post, as it is not “repeatable.” Repeatable might be a default.

    <?php 
    register_meta( 'post', 'mood', array( 'schema' => array( 
    		'type' => 'string',
    		'repeatable' => false
    	)
    ) );
    

    Here is a field that consists of an array of URLs. The value would fit in a single row, perhaps in JSON format, i.e. ['some.url/','some.other/url'], and is limited to one row per post.

    <?php 
    register_meta( 'post', 'related_content', array(
    	'schema' => array( 
    		'type' => 'array',
    		'items' => array(
    			'type' => 'url',
    		),
    		'repeatable' => false
    	)
    ) );
    

    Here is a field that consists of an album as it relates to an artist and includes a number of properties. The value would fit in a single row, and multiple rows can exist for a single artist.

    <?php 
    register_meta( 'post', 'album', array(
    	'object_subtype' => 'artist',
    	'schema' => array( 
    		'type' => 'object',
    		'properties' => array(
    			'name' => array(
    				'type' => 'string'
    			),
    			'cover' => array(
    				'type' => 'wp-image'
    			),
    			'genre' => array(
    				'type' => 'string',
    				'options' => array( 'Rock', 'R&B', 'Shoegaze' ),
    			),
    			'release-date' => array(
    				'type' => 'date'
    			)
    		)
    		'repeatable' => true
    	)
    ) );

    What do you think?

     
    • Mark Howells-Mead 2:34 pm on May 3, 2016 Permalink | Log in to Reply

      That’s a good idea. However, PHP is type-less, so appropriate checks will need to be added when registering/writing/reading the field and its value.

      • Eric Andrew Lewis 3:00 pm on May 3, 2016 Permalink | Log in to Reply

        We’ll definitely validate the schema input upon registration to make sure it conforms to what we expect.

        Our first desire here is to expose the data types for the REST and Fields API. You bring up a good point: should we use the schema as a means for validating input from for example add_post_meta()? Curious what other folks think about this.

        • Scott Kingsley Clark 3:01 pm on May 3, 2016 Permalink | Log in to Reply

          add_post_meta suddenly returning WP_Error may be problematic, if we go that route. Not many people even check for add_post_meta / update_post_meta returns as it is though, to validate they even inserted/saved properly.

          I think whatever it is should be opt-in though.

    • Darren Ethier (nerrad) 2:57 pm on May 3, 2016 Permalink | Log in to Reply

      I like the idea, but I think to be properly implemented I think it’d be better that instead of some arbitrary string that describes the “type” you instead pass in a data type class name that describes the type and how its validated etc. This allows for MUCH more flexibility when it comes to plugins adding their own validation for how types etc get handled. There could be an interface that WP defines that all data-type objects should implement.

      Something like:

      interface WP_Data_Type {
      	/**
      	 * Name for the type ('object', 'string', 'stars') etc.
      	 * @return string
      	 */
      	public function name();
      
      	/**
      	 * How the datatype should be sanitized for the database.
      	 * @return mixed
      	 */
      	public function sanitize_for_db( $value );
      
      	/**
      	 * How the datatype should be sanitized for display.
      	 * @return mixed
      	 */
      	public function sanitize_for_display( $value );
      
      	/**
      	 * Is the value for the datatype valid?
      	 * @return bool
      	 */
      	public function validate( $value );
      }
      
      class WP_Integer_Data_Type implements WP_Data_Type {
      
      	public function name() {
      		return 'integer';
      	}
      
      	public function sanitize_for_db( $value ) {
      		return (int) $value;
      	}
      
      	public function sanitize_for_display( $value ) {
      		return (int) $value;
      	}
      
      	public function validate( $value ) {
      		return is_int( $value );
      	}
      }
      

      So WP Core could have some default data types that map from strings like ‘integer’, or ‘string’ etc. But plugins could implement their OWN special types that Core does not have like `My_Plugin_Stars_Data_Type` and core can use that for handling. One change that would need to be needed in the schema though is to have the plugin provide a `fallback_type` that is used if the plugin is inactive and core is not able to find the corresponding class for the name defined in `type`. So something like:

      register_meta( 'post', 'favorite-number', array( 'schema' => array(
      	'type' => 'My_Plugin_Stars_Data_type',
      	'fallback_type' => 'integer',
      	'repeatable' => false
      )
      ) );
      
      • Scott Kingsley Clark 3:06 pm on May 3, 2016 Permalink | Log in to Reply

        The method of storage provides for further expansion as full blown class objects, so this is just an interim solution until we can get Fields API into core.

      • Darren Ethier (nerrad) 3:41 pm on May 3, 2016 Permalink | Log in to Reply

        I totally glossed over the link to the related discussion in trac and that this is also based on the rest api schema for types. I still think my idea has merit but its kinda late to the party 🙂

    • Scott Kingsley Clark 3:03 pm on May 3, 2016 Permalink | Log in to Reply

      (sorry, moved my comment into the proper comment thread)

    • chatmandesign 3:24 pm on May 3, 2016 Permalink | Log in to Reply

      HELL YES!

    • Felix Arntz 5:36 pm on May 3, 2016 Permalink | Log in to Reply

      When I look at the third example, the value is an object with some properties. Does this also support an associative array? This doesn’t really matter for JS/JSON, but it does in PHP. Basically have `type` set to `array`, but at the same time support something like the `properties` key in the third example (although of course in an array it’s technically not a property).

    • davidperez 9:19 pm on May 3, 2016 Permalink | Log in to Reply

      Yes please! It’s a needed feature for meta simplicity…

    • Daniel Bachhuber 9:47 pm on May 3, 2016 Permalink | Log in to Reply

      Generally, I’m very supportive of adding more structured metadata around data in WordPress. I’m also not a huge fan of P2 discussion threads (because P2 kinda sucks), so keep that in mind if I forget to reply to a comment / don’t get an email notification about a comment.

      I think we should follow JSON Schema unless we make a deliberate, and intentional, reason not to. Following JSON Schema gives us access to all of the validation libraries already written, clients that can interpret it, etc. etc. Not following JSON Schema invents even more work for us, makes WP incompatible with existing tools that use JSON Schema, means we have to create a translation layer between this and the WP REST API, etc. etc. The mock code provided appears to mostly follow JSON Schema with a few unintentional (?) departures.

      More specifically, type should always be one of a fixed set of values. The wp-image type would be more correctly expressed as type=>integer,format=>wp-image. Or, we could define our own relation attribute.

      The options attribute has an equivalent in JSON Schema: enum

      Lastly, repeatable appears to be functionally equivalent to type=>array,items=>.... I suppose we could include it as a utility attribute, but doing so adds complexity.

      • Daniel Bachhuber 9:54 pm on May 3, 2016 Permalink | Log in to Reply

        Also worth mentioning: the problem of defining an application’s data models is one I’m sure many other CMSes, frameworks, etc. have worked on. It would be really good to apply their learnings and (try to) avoid their mistakes.

      • Weston Ruter 3:23 am on May 5, 2016 Permalink | Log in to Reply

        @danielbachhuber I agree. The definitions of non-scalar meta here are very similar to what is required of a schema to define what a widget instance looks like (#35574). While I don’t have a lot of experience with JSON Schema and some of the data structures seem somewhat complicated to describe data accurately, using JSON Schema as the standard format across WordPress and not just in the REST API makes a lot of sense to me.

    • chrishoward 2:42 am on May 4, 2016 Permalink | Log in to Reply

      Al Ay Lew Yah!! This is so desperately needed.

      Fields, as a bare minimum, need slug, label, creator, displayable and type. And then field meta to provide more detail.

      The creator is a way for a developer to uniquely identify their fields.. e.g. acf, woo-commerce, custom, etc…

      I develop plugins that allow users display content however they like and from from any sources. But when it comes to custom fields, all I’m able to present them with is a dropdown of field slug names (because WP mixes fields and other meta in the one).

      There’s little way to identify valid content ones as opposed to system ones. e.g. ACF creates both for each field. So an option to indicate if it’s a display field is valuable too.

      Furthermore, as Eric notes, there’s no way of knowing anything about how the field should be formatted. So 34.5 be an id in a library system, a single point numeric, a currency to two decimal places, or a

      Likewise, a date. What is this? 12/12/12 Is it a date? Is it maths – 12 divided by 12 divided by 12? Or is it some serial id system like model #, part #, year #?

      • chrishoward 2:45 am on May 4, 2016 Permalink | Log in to Reply

        oops! Don’t click reply til you mean it! 😛 UX fail. Need to add an edit option to these comments.

        Sorry for the missing format example where I just said “or a”. I meant to say a number like stocks or percentages that might be 3 or 4 decimals.

    • Ahmad Awais 3:06 am on May 4, 2016 Permalink | Log in to Reply

      Thus can be very helpful. I agree with Daniel as well that JSON schema might help us putting up a standard in olace that a number of libraries already use.

    • Julien 6:51 am on May 4, 2016 Permalink | Log in to Reply

      I’ll follow @Daniel Bachhuber. Also I have a question not directly related to this: why WordPress core is not embracing OOP development for their end-user API? Back from the first WCEU, a speaker asked the audience who has learnt to code thanks to WordPress and nearly 3/4 of the audience raise their hands. Would it be nice if WordPress could teach them gradually how to use classes and objects in place of nested arrays of nested arrays? WordPress is moving on its side while the main PHP community is standardizing its libraries in order to be compatible to any PHP projects and also re-usable.

    • Mike Schinkel 7:18 am on May 4, 2016 Permalink | Log in to Reply

      Are you seriously considering storing complex data in a single meta field as not just an edge case where you are storing a JOSN blog for convenience?

      IMO this is a really bad idea because it means you cannot use SQL to query the data. Let me beg the team to consider storing complex data like this. It is a format that really stood the test of time and many different websites, and it can handle any level of complexity. It can also support a generic mention of converting too and from a JSON blob:

      https://bitbucket.org/newclarity/sunrise-1#markdown-header-post-meta-storage-format

      ALSO, I would strongly urge against adding nested arrays. It make for brittle code that can easily be mistyped and it makes it impossible to do a generic wp_parse_args() in order to merge in default attributes. If you MUST use nested attributes please consider using nested keys instead with colons to seperate, like so; it is easily to extract the subarrays from these nested keys when you need it but this supports wp_parse_args() much better, and in my experience you really need that:

      
      register_post_meta(  'album', array(
      	'object_subtype' => 'artist',
      	'schema:type' => 'object',
      	'schema:properties:name:type' => 'string',
      	'schema:properties:genre:type' => 'string',
      	'schema:properties:genre:options' => array( 'Rock', 'R&B', 'Shoegaze' ),
      	'schema:properties:release-date:type' => 'date',
      	'schema:repeatable' => true
      ) );
      

      But even that seems over-architected but I am really struggling to understand the example — the semantics of the example are not clear to me — so I can’t give a simplified example.

      But I do feel this area is critical to get right because getting it wrong dooms many people to writing too-complex and rather error prone code.

      • Weston Ruter 3:27 am on May 5, 2016 Permalink | Log in to Reply

        @mikeschinkel Storing complex data in single meta values (usually serialized data) are a fact of life in WordPress. Widgets are perhaps the most standard example of this. They invariably require storage as complex data in single values. I’ve proposed in #35574 that JSON Schema be used to describe widgets so that they can be exposed via the REST API.

        As for JSON Schema the format, since it is a standard(ish) format there should be ample tools to validate that a JSON Schema written is valid, and also to auto-generate a Schema definition based on example data being provided.

        • Mike Schinkel 4:17 am on May 5, 2016 Permalink | Log in to Reply

          Hi Weston,

          Thanks for replying to the comment.

          > _”Storing complex data in single meta values (usually serialized data) are a fact of life in WordPress. Widgets are perhaps the most standard example of this. They invariably require storage as complex data in single values.”_

          I should have taken more care to be clear on that. You are correct, in some cases. WordPress definitely stores PHP serialized data into `wp_options` for things like widgets, active plugins, cron, sidebars, user roles and more. And I absolutely agree that is a best practice.

          WordPress also stores `wp_capabilities` and `session_tokens` in `wp_usermeta`, and while I don’t love that it does it is not horrible unless you start getting 10s or 100s of thousands of users.

          But where WordPress generally does not store serialized data is in `wp_postmeta`, and I think it would be a huge mistake to make it easy for developer to start doing so as it could several impact scalability when it comes to 10s or 100s of thousands of posts, or even millions of posts. Which is not terribly uncommon as more large media companies start to use WordPress for their CMS, unless of course they offload actually serving JSON content to another server, for example.

          > _As for JSON Schema the format, since it is a standard(ish) format there should be ample tools to validate that a JSON Schema written is valid, and also to auto-generate a Schema definition based on example data being provided._

          Nothing I am suggesting would conflict with that goal.

          @e can easily give you exactly what you need without resorting to serialized data in `wp_postmeta` nor `wp_termmeta` (although that would be less problematic.)

          If you want to be able to have a function `get_postmeta($post_id,’album’)` to be able return an object so you can pass to `json_encode()` we can easily write a serializer/deserializer that stores data using meta_keys in the following format:

          _person[name]	 => Mike Schinkel
          _person[gender] => 'male'
          _person[links][twitter] => 'http://twitter.com/mikeschinkel',
          _person[links][2] => 'http://facebook.com/mikeschinkel'
          _person[links][3][linkedin] => 'http://linkedin.com/in/mikeschinkel'
          

          We have used this storage format for years on client projects to numerous to count and it has never once failed us.

          I will be happy to write the serializer/deserializer because I have pretty much already written it.

          • Mike Schinkel 4:21 am on May 5, 2016 Permalink | Log in to Reply

            Arrrgh, I really wish I could edit my posts. Here is the code fixed:

            _person[name]	 => Mike Schinkel
            _person[gender] => 'male'
            _person[links][twitter] => 'http://twitter.com/mikeschinkel',
            _person[links][2] => 'http://facebook.com/mikeschinkel'
            _person[links][3][linkedin] => 'http://linkedin.com/in/mikeschinkel'
            

    • schlessera 9:59 am on May 4, 2016 Permalink | Log in to Reply

      Absolutely agree that different meta values need more structure. However, when looking at the example provided, I’m a bit perplexed. This looks like you’re trying to cram a CMS into the meta fields of the existing CMS. If you want to have separate, complex entities, there’s already CPTs & taxonomies, etc… for that. I don’t understand why you would want to save an album with all of its data within one single meta field… Why not an `album` CPT, and store the ID in the meta?

      • Eric Andrew Lewis 11:38 am on May 4, 2016 Permalink | Log in to Reply

        I considered adding a caveat to that example “Not that you should do this, but you could,” as it would make more sense in your content structure. There is probably a better example to show key-value based entity support.

        • Mike Schinkel 4:23 am on May 5, 2016 Permalink | Log in to Reply

          My experience as a programming trainer is that any code you publish will get copied and widely used in production code.

          So if they should not do it I would heartily recommend that you don’t ever show it. Or you will be horrified later as you see your example code in someone’s plugin, copied verbatim from your example (I know, I’ve been there.)

    • Franz Josef Kaiser 11:08 am on May 4, 2016 Permalink | Log in to Reply

      I am stunned by that proposal. This is maybe the most (backwards compatibility) breaking change in WP history. The current purpose of the function is completely different:

      register_meta( $type, $key, $sanitizeCb, $authCb )

      Summary of current status:

      • Name a meta type – mapped together with key to group and standardize sanitization callbacks on typed (user, post, etc.) fields
      • Name a meta key – mapped to the DB
      • Map a meta key to a type of data object (post, user, etc.)
      • Decide if a meta field is “protected”, meaning if it shows up in the Custom fields meta box, or if the view is handled by some meta box *)
      • Decide who has access (based on capability, role name, other things like other meta data) to a custom fields attached DB operations
      • Give access to meta data that was registered by a plugin and needs to be accessible again when the plugins is not present anymore – via the Custom fields meta box and an intermediate plugin

      To address this:

      We’re going to expand the utility of this function to describe the data type of the field.

      This is what the function currently does. The proposal on the opposite tries to:

      • Describe how many meta values for a single key can exist – Handled by the implementation
      • How the data is structured – Handled by sanitization callback and input views
      • Describe how multiple values, or the serialized input is structured – Again, handled by sanitization callbacks

      There are more serious issues that need to get addressed:

      • Meta fields starting with an underscore/ _ are “protected” per default and therefore hidden from the UI, the Custom Fields metabox. This makes them inaccessible when a plugin is deactivated and custom intermediate plugins need to be written. The is_protected_meta() should throw a _doing_it_wrong() warning and suggest using __return_false for the $auth_callback
      • Meta key names can be anything, even CamelCase. This should get standardized so mistyping is harder. They should get checked by the following Regex: "^[a-z0-9_]+$"
      • Disallow the use of registered post type names as this locks post meta data down and disallows switching them to a new post type – portability
      • Drop conjunctions (with), articles (the) and other filler words from the meta key name. Only allow boolean flags (example: has_*, is_*) as this is unavoidable to cover different context.

      I really, really do not understand why this function should be completely repurposed. What imo is missing is a central registry that validates against the DB to show orphaned meta keys and that can be used to map DB data to business logic. I also think that a central registry would be needed, but proposing to make a cat bark? No, thank you. And if everyone really thinks they do need an adapter or decorator for the Fields and the REST API in core, then please break that out into something completely new.

      • Eric Andrew Lewis 11:56 am on May 4, 2016 Permalink | Log in to Reply

        > This is maybe the most (backwards compatibility) breaking change in WP history

        This would not be a breaking change, sorry if that was unclear. We would support the function being called as it is now, without the schema information.

        > Disallow the use of registered post type names as this locks post meta data down

        This would be good to consider, as other APIs in WordPress break when using reserved terms.

  • Ryan McCue 8:46 am on May 3, 2016 Permalink |
    Tags: rewrite-rules   

    Proposal: Next Generation Rewrites 

    Hi everyone! Today I’d like to propose a new feature project for WordPress: Next Generation Rewrites. After proposing this at the last feature projects meeting, it’s time to flesh out the details of what this project would be.

    The aim of the project is to modernise the rewriting and routing system for the modern CMS and platform era of WordPress.

    (This project was previously proposed in a ticket on Trac, however the project is larger than a single Trac ticket and needs a larger discussion.)

    Overview

    If you’ve worked with custom development on WordPress, you’ve probably registered at least one rewrite rule. Rewrites are the key to what WordPress calls “pretty permalinks”, which are URLs designed for humans rather than the server. They look like /2016/04/19/, or /about/requirements/, rather than index.php?p=42.

    As a developer, you can register your own rewrite rules as well. For example, bbPress registers URLs like /forums/topic/jjj-is-awesome/ and WooCommerce has URLs like /product/gs3/. WordPress then “re-writes” these to the internal query variables (“query vars”), which are eventually passed into the main WP Query.

    The rewrite system was initially designed to implement pretty permalinks, but has been used and abused for so much more since then. With modern plugins and web apps built on top of WordPress, it’s not uncommon to have pages that don’t need a main query, or need a specialised system of querying. As an example of this, the REST API infrastructure added in WordPress 4.4 doesn’t use the main query, as many of the endpoints don’t require querying posts at all.

    While the usage of rewrites has developed, the internals of how URLs are handled internally hasn’t changed. The system is fundamentally still designed for the blog era of WordPress. It also predates a lot of the pieces of WordPress we take for granted, such as transients and object caching.

    Project Proposal

    It’s time to change the rewrite system. Rewrite rules should be changed from a layer on top of WP Query to a fully-fledged system all of their own. To do this, I’m proposing three initial steps:

    • Decouple rewrites from the query system
    • Refactor and rework the internals to make them testable
    • Rethink rewrite storage and remove flushing

    These steps would take place under the umbrella of a new feature project, Next Generation Rewrites. This feature project would coordinate the project and people working on it across the various parts of core it touches (primarily the Rewrite Rules component, but also potentially involving UI and UX discussion and changes; fixing the “visit the Permalinks page and save to fix your site” issue, for example). This would also coordinate the team across multiple release cycles as we slowly but surely make progress. It’s important to make progress while keeping rewrites stable, as they’re a critical part of WordPress that we cannot break.

    Decoupling Rewrites from Querying

    The first step I’m proposing is to decouple rewrites from querying. Right now, rewrites for anything except querying posts involves jumping through a few hoops. This includes registering temporary query vars, or using global state to track route matching. Separating these two components will make it easier to add non-query-based rewrites, as well as allowing more powerful query rewrites.

    Currently, rewrites are registered using code like the following:

    add_rewrite_rule( '/regex/', 'index.php?var=value' );

    These rewrite rules map a regular expression to a query string, which is later parsed into an array internally. You can achieve more complex routing via regular expressions by using a special syntax in the rewrite string:

    add_rewrite_rule( '/topic/(.+)', 'index.php?topic=$matches[1]' );

    Note that while this looks like a PHP variable, it’s actually a static string that gets replaced after the regular expression. This can lead to confusion with developers who are new to the syntax, and it also can make doing more complex rewrites hard. These typically involve temporary query vars, as well as quite a bit of processing.

    Instead, I want to introduce a new WP_Rewrite_Rule object to replace the current rewrite string. This object would contain a method called get_query_vars that receives the $matches variable and returns the query vars to set. This would look something like this:

    class MyRule extends WP_Rewrite_Rule {
        public function get_query_vars( $matches ) {
            return array(
                'post_type' => 'topic',
                'meta_query' => array(
                    array(
                        'key' => '_topic_name',
                        'value' => $matches[1],
                    ),
                ),
            );
        }
    }
    add_rewrite_rule( '/topic/(.+)', new MyRule() );

    (The exact format of the object is yet to be decided; we’ve also started discussing the possibility of passing a request object into this callback as well.)

    Using an object for this allows us to have multiple callbacks for different stages of the routing process, and starts to simplify some of the internal code in WP_Rewrite. For example, the routing code around pages that allows URLs like /parent/child/sub-child/ for child pages can be simplified and moved out of the main routing code. This also helps make the code more testable, which dovetails nicely with the third goal.

    Refactor rewrite internals

    Step 2 of changing rewrites is to make the rewrite system fully testable. Currently, a bunch of global state is mixed into the internals of rewrite matching, and the rewrite methods tend to be monolithic. @ericlewis has previously begun work on this in #18877, and this can be continued and rolled into the Next Generation Rewrites project.

    Ideally, this should happen at the same time or before the first step to allow easy checking of regressions. This is relatively boring work that won’t affect many developers, but it’s important we do it. The rewrite system is a critical part of WordPress, and it’s crucially important that it’s testable and verifiable.

    Rethink rewrite storage

    Once the first two steps are in place, we should begin reconsidering how rewrites are stored. Currently, rewrites are stored in the database in the rewrite_rules option. The option is less of an option (it’s not really configuration), and more of a caching technique. This is somewhat of a relic, as rewrites predate object caching and transients in WordPress, both of which are better techniques to handle caching in modern WordPress.

    Removing this option and changing it to use a proper caching subsystem in WordPress should fix multiple problems, including the need to flush rewrites. This should improve the UX for end users, as we should be able to remove the “links on your site don’t work, so go to the Permalinks page and save” trick (which only really requires visiting the page, not saving).

    The need to cache rewrites at all can also be reconsidered; many of the rewrite rules are simply entries in an array, and are not expensive to generate on-the-fly, while removing the caching so can make for an easier to use and more dynamic system. More expensive rules can be cached by the code generating the rule, rather than via the monolithic rewrite cache.

    This has the potential to improve the user experience and fix a class of issues, but it also has the potential to ruin performance, depending on how other code is using it. It’s important to tread carefully as we attempt to improve this, and ensure we remain compatible and performant. Introducing a two-tiered system is one approach we can consider, with the ability for plugins to opt-in to a newer, dynamic system to avoid problems with flushing.

    Why a Feature Project?

    I’m proposing Rewrites Next Generation as a feature project for several reasons. The concept and implementation are both large and complex, moreso than simply operating in an informal matter on Trac tickets. The impact of this project is also large, affecting many plugin and theme developers, as well as potential improvements to UX. Gaining feedback from all interested stakeholders is important, as this is a crucial part of WordPress.

    Getting Started

    The steps I’ve listed here are only a selection of the issues with rewrites. The rewrite system hasn’t been massively changed since its inception, so there are plenty of parts that could be changed to better suit the modern era of WordPress development. The issues here are simply the three most important that I’ve found, but I want to hear your feedback too.

    Let’s talk rewrites. I’m proposing a weekly meeting for Rewrites Next Generation, at Wednesday, 23:00 UTC with the first meeting at May 4th 23:00 UTC. If you’re interested in rewrites, or have had problems with them in the past, let’s talk and work out what we need to do to improve rewrites. (This is a non-permanent meeting to set the scope of the project; we’ll refine meeting frequency and timing at a later date.)

    After this initial discussion, we can settle on concrete goals and a timeline for the initial stages of the project. A proof-of-concept patch and ticket are available on Trac, however alternative approaches should be considered after this discussion. The short-term goal is to begin landing these improvements in trunk, with the goal of having our first changes in WordPress 4.6, which is a quick but achievable timeline.

    This project has the potential to make a large impact on developers and users, and it’s important that everyone has their say. I hope you’ll join me for the first meeting, and join in the fun of contributing to a key part of WordPress!

    Thanks for reading. <3

     
    • Omaar Osmaan 9:05 am on May 3, 2016 Permalink | Log in to Reply

      So excited for this!

    • Ryan Hellyer 9:28 am on May 3, 2016 Permalink | Log in to Reply

      A simpler system for adding new rewrite rules would be nice. The current system is unintuitive IMHO.

    • Liam Gladdy 9:47 am on May 3, 2016 Permalink | Log in to Reply

      Everything about this makes me happy! The initial meeting time doesn’t work well for me in the UK, but i’ll catch up the next day!

    • andreasnrb 11:21 am on May 3, 2016 Permalink | Log in to Reply

      Really interesting. The meeting time suggestion is really bad. Does not work very well for anyone in Europe really.

    • Takayuki Miyauchi 11:41 am on May 3, 2016 Permalink | Log in to Reply

      +1
      add_rewrite_rule( '/topic/(.+)', new MyRule() ); looks nice!

    • jagnew 1:15 pm on May 3, 2016 Permalink | Log in to Reply

      This would be great, I’ve actually been building a plugin to handle routing etc. based around what current PHP frameworks do these days. If its of any use (still writing the tests and docs for it): https://github.com/jasonagnew/WP-Router

      Example of using it:

      get('id') == 1)
              {
                  return 'No';
              }
      
              return $this->next($request);
          }
      }
      
      class Route_Test {
      
          protected $router;
      
          public function __construct()
          {
              global $wp_router;
      
              $this->router  = $wp_router;
      
              $this->register_routes();
          }
      
          public function register_protected_routes()
          {
              $this->router->get( array(
                  'as'   => 'getTest',
                  'uri'  => 'test/{id}',
                  'uses' => array( $this, 'get' )
              ) );
          }
      
          protected function register_routes()
          {
              $this->router->group( array(
                  'prefix' => '/protected',
                  'middlewares' => array( 'Middleware_One' ),
                  'uses' => array( $this, 'register_protected_routes' )
              ) );
      
              $this->router->post( array(
                  'as'   => 'postTest',
                  'uri'  => '/test/{id}',
                  'uses' => array( $this, 'post' ),
                  'prefix' => ''
              ) );
      
              $this->router->put( array(
                  'as'   => 'putTest',
                  'uri'  => '/test/{id}',
                  'uses' => array( $this, 'put' )
              ) );
          }
      
          public function get($id, WP_Request $request)
          {
              $all = $request->all();
      
              return new WP_JSON_Response($all);
          }
      
          public function post($id)
          {
              return 'POST: The ID is ' . $id;
          }
      
          public function put($id)
          {
              return 'PUT: The ID is ' . $id;
          }
      
      }
      
      new Route_Test();
      
    • Joost de Valk 2:22 pm on May 3, 2016 Permalink | Log in to Reply

      Love it. Would love to contribute but that meeting time is tough indeed.

      I’d want to add another thing to the mix: if we change rewrites, we also should consider creating a `get_current_url()` type function.

      I would also be very much in favor of caching URLs *very* aggressively, to the point of even giving them their own table. Right now, `get_permalink()` is one of the slowest things on many a page load…

    • Michael Ecklund 3:10 pm on May 3, 2016 Permalink | Log in to Reply

      Sounds interesting. Would definitely like to see improvement in this area for sure. Agreed with @joostdevalk.

    • Jacob Santos 5:07 pm on May 3, 2016 Permalink | Log in to Reply

      Composition over inheritance. It is easier to go to inheritance if composition is used first. Would help if used interfaces.

      I realize the least experienced don’t understand proper interface standards. I also realize there is a good argument for dynamic programming techniques.

      Since WordPress standardizes on neither, my preference would be proper OOP using interfaces to define a specification and Composition to tie the objects together.

      Whether the specification is defined as implicit with dynamic programming or explicit with interfaces, it would better serve then piling on the current OO mess that exists in WordPress currently.

    • Ryan McCue 12:41 am on May 4, 2016 Permalink | Log in to Reply

      Apologies on the meeting time for the Europeans, but there’s unfortunately no times that work well for everyone. Any earlier would push the boundary of whether I can make it (in Australia).

      I’ll consider having a secondary meeting for EU as well. 🙂

    • Ahmad Awais 2:57 am on May 4, 2016 Permalink | Log in to Reply

      Great stuff. Looking forward to it. Would love to contribute. WP most def needs a refresh to its routing sys.

    • schlessera 6:11 am on May 4, 2016 Permalink | Log in to Reply

      I agree with all of the issues you’re describing above. I cringe whenever I have to deal with rewrites, because in the end, it is an overly complex and fragile solution to a not-so-complex problem.

      I want to ask, though, if we are to go through the troubles of “rewriting” this part of the system and deal with all the BC headaches, why not go the whole nine yards? Instead of replacing the archaic special case system with a more modern special case system, why not create a modern general purpose system, and implement the existing rewrites as one special case of that general purpose system?

      You’ve probably guessed already that I’m talking about a full-blown routing system.

      If we define an interface (or an abstract base class if we absolutely must ignore best practices for the sake of “conformance”) called `WP_Route`, we can easily have one special case `WP_Rewrite_Rule_Route` that provides a completely BC way of implementing the current behaviour. But it allows us to have alternative routing behaviour that does not easily fit into the “rewriting” mechanism, too.

      So, the optimizations you’re talking about above are still a good idea, and should all be integrated into the `WP_Rewrite_Rule_Route`. But please don’t assume that we all just use “rewrites” for our routing purposes, when we have the opportunity to make an important change here. Assuming that all routing requests need to return query vars to pass to `WP_Query` is such an assumption. What if I want to have an URL that let’s me query custom external data? Why should this need to go through `WP_Query`?

      Most of what I’m talking about is already possible with the existing system, but it always feels dirty. I would love for WordPress to embrace a generalized approach (that can still default to special case implementations), so that I don’t constantly face situations where it feels like I’m working against the system.

    • schlessera 9:31 am on May 4, 2016 Permalink | Log in to Reply

      I thought some more about how a more generalized approach could look. I have to admit, though, that I’m not familiar with all of the intricacies and nuances that might come into play, so forgive me if anything I write here is just not possible.

      I imagine having WordPress pass the request to the routing system (let’s call it `WP_Router`). `WP_Router` will then do a minimum of parsing to be able to decide what specific routing action implementation it needs to call. Possible names of the interface would be `WP_Route` or `WP_Controller` (or anything along these lines). I’ll go with `WP_Controller` for the rest of the post to clearly differentiate it from `WP_Router`.

      The specific `WP_Controller` implementation is responsible for the main query. So, whatever `WP_Controller` you’re using, your widgets and navigation and so on should not be impacted.

      The `WP_Controller` does not return query vars or something in-between, it returns a completed “View” (the rendered content or archive, for example, or alternatively a standardized object).

      For the current default WP behaviour, we could have a `WP_Rewriting_Controller`, that collects the known rewriting rules, parses them for query vars, hands them over to `WP_Query` and returns the completed `View`.

      This would force us to have the individual elements that interact for such a request be decoupled from the overall WP lifecycle (which should mostly be the case, as far as I know).

      For any other `WP_Controller` implementation, you can freely choose what elements you need. You can, for example, completely forego `WP_Query`. The only contract that WP has with a `WP_Controller` is that it gets the request, and returns the response.

      It should be possible to build this entire system to be 100% BC, apart for the few plugins that directly mess with some data outside of the API. They will probably have plenty of time to adapt, though, as this is a bigger change anyway.

    • jeffmcneill 10:30 am on May 4, 2016 Permalink | Log in to Reply

      Not sure, but the whole issue of redirections might be something that this could include. The Redirection plugin recently was updated (after a few years) and it is a mainstay for managing the renaming of urls. Whenever there is a renaming of pages and reorganization of a site there are many of these redirection entries made to keep the 301 going properly. Not sure if a page-level thing like this should be dealt with at the same time as the much larger site-level redirection thing, but they do eventually lead to the same thing: a resolved url for page(s).

c
compose new post
j
next post/next comment
k
previous post/previous comment
r
reply
e
edit
o
show/hide comments
t
go to top
l
go to login
h
show/hide help
shift + esc
cancel
Skip to toolbar