<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[41182] trunk/src/wp-admin: Permalinks: Add buttons for the available structure tags to the admin UI.</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta" style="font-size: 105%">
<dt style="float: left; width: 6em; font-weight: bold">Revision</dt> <dd><a style="font-weight: bold" href="https://core.trac.wordpress.org/changeset/41182">41182</a><script type="application/ld+json">{"@context":"http://schema.org","@type":"EmailMessage","description":"Review this Commit","action":{"@type":"ViewAction","url":"https://core.trac.wordpress.org/changeset/41182","name":"Review Commit"}}</script></dd>
<dt style="float: left; width: 6em; font-weight: bold">Author</dt> <dd>swissspidy</dd>
<dt style="float: left; width: 6em; font-weight: bold">Date</dt> <dd>2017-07-28 17:43:00 +0000 (Fri, 28 Jul 2017)</dd>
</dl>

<pre style='padding-left: 1em; margin: 2em 0; border-left: 2px solid #ccc; line-height: 1.25; font-size: 105%; font-family: sans-serif'>Permalinks: Add buttons for the available structure tags to the admin UI.

Often times, it can be confusing to set a custom permalink structure. One has to double-check the documentation, make 
sure to correctly insert the structure tag, and hope not to break their site.

With this addition, the available structure tags are being displayed as a list of easily clickable buttons that can be 
used to insert tags to the custom structure input field and to remove them again.

Props kpdesign, swissspidy, joedolson, afercia.
Fixes <a href="https://core.trac.wordpress.org/ticket/29872">#29872</a>.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunksrcwpadmincssformscss">trunk/src/wp-admin/css/forms.css</a></li>
<li><a href="#trunksrcwpadminjscommonjs">trunk/src/wp-admin/js/common.js</a></li>
<li><a href="#trunksrcwpadminoptionspermalinkphp">trunk/src/wp-admin/options-permalink.php</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunksrcwpadmincssformscss"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-admin/css/forms.css</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-admin/css/forms.css  2017-07-28 14:24:53 UTC (rev 41181)
+++ trunk/src/wp-admin/css/forms.css    2017-07-28 17:43:00 UTC (rev 41182)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -908,6 +908,11 @@
</span><span class="cx" style="display: block; padding: 0 10px">        vertical-align: middle;
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+.form-table.permalink-structure .available-structure-tags li {
+       float: left;
+       margin-right: 5px;
+}
+
</ins><span class="cx" style="display: block; padding: 0 10px"> /*------------------------------------------------------------------------------
</span><span class="cx" style="display: block; padding: 0 10px">   21.0 - Network Admin
</span><span class="cx" style="display: block; padding: 0 10px"> ------------------------------------------------------------------------------*/
</span></span></pre></div>
<a id="trunksrcwpadminjscommonjs"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-admin/js/common.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-admin/js/common.js   2017-07-28 14:24:53 UTC (rev 41181)
+++ trunk/src/wp-admin/js/common.js     2017-07-28 17:43:00 UTC (rev 41182)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -175,6 +175,101 @@
</span><span class="cx" style="display: block; padding: 0 10px">        panel.addClass('active').show();
</span><span class="cx" style="display: block; padding: 0 10px"> });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+/**
+ * Update custom permalink structure via buttons.
+ */
+
+var permalinkStructureFocused = false,
+    $permalinkStructure       = $( '#permalink_structure' ),
+    $availableStructureTags   = $( '.form-table.permalink-structure .available-structure-tags button' );
+
+// Check if the permalink structure input field has had focus at least once.
+$permalinkStructure.on( 'focus', function( event ) {
+       permalinkStructureFocused = true;
+       $( this ).off( event );
+} );
+
+/**
+ * Enables or disables a structure tag button depending on its usage.
+ *
+ * If the structure is already used in the custom permalink structure,
+ * it will be disabled.
+ *
+ * @param {object} button Button jQuery object.
+ */
+function changeStructureTagButtonState( button ) {
+       if ( -1 !== $permalinkStructure.val().indexOf( button.text().trim() ) ) {
+               button.attr( 'data-label', button.attr( 'aria-label' ) );
+               button.attr( 'aria-label', button.attr( 'data-used' ) );
+               button.attr( 'aria-pressed', true );
+               button.addClass( 'active' );
+       } else if ( button.attr( 'data-label' ) ) {
+               button.attr( 'aria-label', button.attr( 'data-label' ) );
+               button.attr( 'aria-pressed', false );
+               button.removeClass( 'active' );
+       }
+};
+
+// Check initial button state.
+$availableStructureTags.each( function() {
+       changeStructureTagButtonState( $( this ) );
+} );
+
+// Observe permalink structure field and disable buttons of tags that are already present.
+$permalinkStructure.on( 'change', function() {
+       $availableStructureTags.each( function() {
+               changeStructureTagButtonState( $( this ) );
+       } );
+} );
+
+$availableStructureTags.on( 'click', function() {
+       var permalinkStructureValue = $permalinkStructure.val(),
+           selectionStart          = $permalinkStructure[ 0 ].selectionStart,
+           selectionEnd            = $permalinkStructure[ 0 ].selectionEnd,
+           textToAppend            = $( this ).text().trim(),
+           textToAnnounce          = $( this ).attr( 'data-added' );
+
+       // Remove structure tag if already part of the structure.
+       if ( -1 !== permalinkStructureValue.indexOf( textToAppend ) ) {
+               permalinkStructureValue = permalinkStructureValue.replace( textToAppend + '/', '' );
+
+               $permalinkStructure.val( '/' === permalinkStructureValue ? '' : permalinkStructureValue );
+
+               // Announce change to screen readers.
+               $( '#custom_selection_updated' ).text( textToAnnounce );
+
+               // Disable button.
+               changeStructureTagButtonState( $( this ) );
+
+               return;
+       }
+
+       // Input field never had focus, move selection to end of input.
+       if ( ! permalinkStructureFocused && 0 === selectionStart && 0 === selectionEnd ) {
+               selectionStart = selectionEnd = permalinkStructureValue.length;
+       }
+
+       $( '#custom_selection' ).prop( 'checked', true );
+
+       // Prepend and append slashes if necessary.
+       if ( '/' !== permalinkStructureValue.substr( 0, selectionStart ).substr( -1 ) ) {
+               textToAppend = '/' + textToAppend;
+       }
+
+       if ( '/' !== permalinkStructureValue.substr( selectionEnd, 1 ) ) {
+               textToAppend = textToAppend + '/';
+       }
+
+       // Insert structure tag at the specified position.
+       $permalinkStructure.val( permalinkStructureValue.substr( 0, selectionStart ) + textToAppend + permalinkStructureValue.substr( selectionEnd ) );
+
+       // Announce change to screen readers.
+       $( '#custom_selection_updated' ).text( textToAnnounce );
+
+       // Disable button.
+       changeStructureTagButtonState( $( this ) );
+} );
+
</ins><span class="cx" style="display: block; padding: 0 10px"> $document.ready( function() {
</span><span class="cx" style="display: block; padding: 0 10px">        var checks, first, last, checked, sliced, mobileEvent, transitionTimeout, focusedRowActions,
</span><span class="cx" style="display: block; padding: 0 10px">                lastClicked = false,
</span></span></pre></div>
<a id="trunksrcwpadminoptionspermalinkphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-admin/options-permalink.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-admin/options-permalink.php  2017-07-28 14:24:53 UTC (rev 41181)
+++ trunk/src/wp-admin/options-permalink.php    2017-07-28 17:43:00 UTC (rev 41182)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -206,6 +206,69 @@
</span><span class="cx" style="display: block; padding: 0 10px">                <td>
</span><span class="cx" style="display: block; padding: 0 10px">                        <code><?php echo get_option('home') . $blog_prefix; ?></code>
</span><span class="cx" style="display: block; padding: 0 10px">                        <input name="permalink_structure" id="permalink_structure" type="text" value="<?php echo esc_attr($permalink_structure); ?>" class="regular-text code" />
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                        <div class="available-structure-tags hide-if-no-js">
+                               <div id="custom_selection_updated" aria-live="assertive" class="screen-reader-text"></div>
+                               <?php
+                               $available_tags = array(
+                                       /* translators: %s: permalink structure tag */
+                                       'year'     => __( '%s (The year of the post, four digits, for example 2004.)' ),
+                                       /* translators: %s: permalink structure tag */
+                                       'monthnum' => __( '%s (Month of the year, for example 05.)' ),
+                                       /* translators: %s: permalink structure tag */
+                                       'day'      => __( '%s (Day of the month, for example 28.)' ),
+                                       /* translators: %s: permalink structure tag */
+                                       'hour'     => __( '%s (Hour of the day, for example 15.)' ),
+                                       /* translators: %s: permalink structure tag */
+                                       'minute'   => __( '%s (Minute of the hour, for example 43.)' ),
+                                       /* translators: %s: permalink structure tag */
+                                       'second'   => __( '%s (Second of the minute, for example 33.)' ),
+                                       /* translators: %s: permalink structure tag */
+                                       'post_id'  => __( '%s (The unique ID of the post, for example 423.)' ),
+                                       /* translators: %s: permalink structure tag */
+                                       'postname' => __( '%s (The sanitized post title (slug).)' ),
+                                       /* translators: %s: permalink structure tag */
+                                       'category' => __( '%s (Category slug. Nested sub-categories appear as nested directories in the URI.)' ),
+                                       /* translators: %s: permalink structure tag */
+                                       'author'   => __( '%s (A sanitized version of the author name.)' ),
+                               );
+
+                               /**
+                                * Filters the list of available permalink structure tags on the Permalinks settings page.
+                                *
+                                * @since 4.8.0
+                                *
+                                * @param array $available_tags A key => value pair of available permalink structure tags.
+                                */
+                               $available_tags = apply_filters( 'available_permalink_structure_tags', $available_tags );
+
+                               /* translators: %s: permalink structure tag */
+                               $structure_tag_added = __( '%s added to permalink structure' );
+
+                               /* translators: %s: permalink structure tag */
+                               $structure_tag_already_used = __( '%s (already used in permalink structure)' );
+
+                               if ( ! empty( $available_tags ) ) :
+                                       ?>
+                                       <p><?php _e( 'Available tags:' ); ?></p>
+                                       <ul role="list">
+                                               <?php
+                                               foreach ( $available_tags as $tag => $explanation ) {
+                                                       ?>
+                                                       <li>
+                                                               <button type="button"
+                                                                       class="button button-secondary"
+                                                                       aria-label="<?php echo esc_attr( sprintf( $explanation, $tag ) ); ?>"
+                                                                       data-added="<?php echo esc_attr( sprintf( $structure_tag_added, $tag ) ); ?>"
+                                                                       data-used="<?php echo esc_attr( sprintf( $structure_tag_already_used, $tag ) ); ?>">
+                                                                       <?php echo '%' . $tag . '%'; ?>
+                                                               </button>
+                                                       </li>
+                                                       <?php
+                                               }
+                                               ?>
+                                       </ul>
+                               <?php endif; ?>
+                       </div>
</ins><span class="cx" style="display: block; padding: 0 10px">                 </td>
</span><span class="cx" style="display: block; padding: 0 10px">        </tr>
</span><span class="cx" style="display: block; padding: 0 10px"> </table>
</span></span></pre>
</div>
</div>

</body>
</html>