Index: content-reference.php
===================================================================
--- content-reference.php (revision 1045)
+++ content-reference.php (working copy)
@@ -45,15 +45,13 @@
*/ ?>
Index: content-wp-parser-hook.php
===================================================================
--- content-wp-parser-hook.php (revision 1045)
+++ content-wp-parser-hook.php (working copy)
@@ -43,15 +43,13 @@
*/ ?>
Index: functions.php
===================================================================
--- functions.php (revision 1045)
+++ functions.php (working copy)
@@ -46,6 +46,11 @@
require __DIR__ . '/inc/user-content-voting.php';
/**
+ * Explanations for functions. hooks, classes, and methods.
+ */
+require( __DIR__ . '/inc/explanations.php' );
+
+/**
* Handbooks.
*/
require __DIR__ . '/inc/handbooks.php';
@@ -79,9 +84,12 @@
add_action( 'after_switch_theme', __NAMESPACE__ . '\\add_roles' );
add_action( 'pre_get_posts', __NAMESPACE__ . '\\pre_get_posts' );
add_action( 'wp_enqueue_scripts', __NAMESPACE__ . '\\theme_scripts_styles' );
+ add_action( 'admin_enqueue_scripts', __NAMESPACE__ . '\\admin_enqueue_scripts' );
+
add_filter( 'post_type_link', __NAMESPACE__ . '\\method_permalink', 10, 2 );
add_filter( 'term_link', __NAMESPACE__ . '\\taxonomy_permalink', 10, 3 );
add_filter( 'the_posts', __NAMESPACE__ . '\\rerun_empty_exact_search', 10, 2 );
+
add_theme_support( 'automatic-feed-links' );
add_theme_support( 'post-thumbnails' );
@@ -423,3 +431,27 @@
wp_enqueue_script( 'wporg-developer-skip-link-focus-fix', get_template_directory_uri() . '/js/skip-link-focus-fix.js', array(), '20130115', true );
wp_enqueue_script( 'wporg-developer-search', get_template_directory_uri() . '/js/search.js', array(), '20141029', true );
}
+
+/**
+ * Enqueue scripts and styles for use in the admin.
+ */
+function admin_enqueue_scripts() {
+ // Only enqueue 'wporg-parsed-content' script and styles on Code Reference post type screens.
+ if ( in_array( get_current_screen()->id, array(
+ 'wp-parser-function', 'wp-parser-class', 'wp-parser-hook', 'wp-parser-method', 'wporg_explanations', 'edit-wporg_explanations',
+ ) ) ) {
+ wp_enqueue_style( 'wporg-admin', get_template_directory_uri() . '/stylesheets/admin.css', array(), '20141213' );
+ wp_enqueue_script( 'wporg-admin', get_template_directory_uri() . '/js/admin.js', array( 'wp-util' ), '20141213', true );
+
+ wp_localize_script( 'wporg-admin', 'wporg', array(
+ 'ajaxURL' => admin_url( 'admin-ajax.php' ),
+ 'searchText' => __( 'Searching ...', 'wporg' ),
+ 'editContentLabel' => __( 'Edit Content', 'wporg' ),
+ 'statusLabel' => array(
+ 'draft' => __( 'Drafted', 'wporg' ),
+ 'pending' => __( 'Pending Review' ),
+ 'publish' => __( 'Published', 'wporg' ),
+ ),
+ ) );
+ }
+}
Index: inc/explanations.php
===================================================================
--- inc/explanations.php (revision 0)
+++ inc/explanations.php (working copy)
@@ -0,0 +1,289 @@
+post_types = array( 'wp-parser-function', 'wp-parser-class', 'wp-parser-hook', 'wp-parser-method' );
+
+ // Setup.
+ add_action( 'init', array( $this, 'register_post_type' ), 0 );
+ add_action( 'init', array( $this, 'remove_editor_support' ), 100 );
+ add_action( 'edit_form_after_title', array( $this, 'post_to_expl_controls' ) );
+ add_action( 'edit_form_top', array( $this, 'expl_to_post_controls' ) );
+
+ // AJAX.
+ add_action( 'wp_ajax_new_explanation', array( $this, 'new_explanation' ) );
+ add_action( 'wp_ajax_un_publish', array( $this, 'un_publish_explanation' ) );
+ }
+
+ /**
+ * Register the Explanations post type.
+ *
+ * @access public
+ */
+ public function register_post_type() {
+ register_post_type( $this->exp_post_type, array(
+ 'labels' => array(
+ 'name' => __( 'Explanations', 'wporg' ),
+ 'singular_name' => __( 'Explanation', 'wporg' ),
+ 'all_items' => __( 'Explanations', 'wporg' ),
+ 'edit_item' => __( 'Edit Explanation', 'wporg' ),
+ 'view_item' => __( 'View Explanation', 'wporg' ),
+ 'search_items' => __( 'Search Explanations', 'wporg' ),
+ 'not_found' => __( 'No Explanations found', 'wporg' ),
+ 'not_found_in_trash' => __( 'No Explanations found in trash', 'wporg' ),
+ ),
+ 'public' => false,
+ 'hierarchical' => false,
+ 'show_ui' => false,
+ 'show_in_nav_menus' => false,
+ 'supports' => array( 'editor', 'revisions' ),
+ 'rewrite' => false,
+ 'query_var' => false,
+ ) );
+ }
+
+ /**
+ * Remove 'editor' support for the function, hook, class, and method post types.
+ *
+ * @access public
+ */
+ public function remove_editor_support() {
+ foreach ( $this->post_types as $type ) {
+ remove_post_type_support( $type, 'editor' );
+ }
+ }
+
+ /**
+ * Output the Post-to-Explanation controls in the post editor for functions,
+ * hooks, classes, and methods.
+ *
+ * @access public
+ *
+ * @param WP_Post $post Current post object.
+ */
+ public function post_to_expl_controls( $post ) {
+ if ( ! in_array( $post->post_type, $this->post_types ) ) {
+ return;
+ }
+
+ $explanation = DevHub\get_explanation( $post );
+ $date_format = get_option( 'date_format' ) . ', ' . get_option( 'time_format' );
+ ?>
+
+ exp_post_type !== $post->post_type ) {
+ return;
+ }
+
+ $parent = is_a( $post, 'WP_Post' ) ? $post->post_parent : get_post( $post )->post_parent;
+
+ if ( 0 !== $parent ) :
+ $prefix = '' . __( 'Associated with: ', 'wporg' ) . '';
+ ?>
+
+ get_status_label( $explanation->ID );
+ ?>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ post_status ) {
+ case 'draft' :
+ $label = '' . __( 'Drafted', 'wporg' ) . '
';
+ break;
+ case 'pending' :
+ $label = '' . __( 'Pending Review' ) . '
';
+ break;
+ case 'publish' :
+ $label = '' . __( 'Published' ) . '
';
+ break;
+ default :
+ $label = '' . __( 'None' ) . '
';
+ }
+ return $label;
+ }
+
+ /**
+ * AJAX handler for creating and associating a new explanation.
+ *
+ * @access public
+ */
+ public function new_explanation() {
+ check_ajax_referer( 'create-expl', 'nonce' );
+
+ $post_id = empty( $_REQUEST['post_id'] ) ? 0 : absint( $_REQUEST['post_id'] );
+
+ if ( DevHub\get_explanation( $post_id ) ) {
+ wp_send_json_error( new WP_Error( 'post_exists', __( 'Explanation already exists.', 'wporg' ) ) );
+ } else {
+ $title = get_post( $post_id )->post_title;
+
+ $explanation = wp_insert_post( array(
+ 'post_type' => 'wporg_explanations',
+ 'post_title' => "Explanation: $title",
+ 'ping_status' => false,
+ 'post_parent' => $post_id,
+ ) );
+
+ if ( ! is_wp_error( $explanation ) && 0 !== $explanation ) {
+ wp_send_json_success( array(
+ 'post_id' => $explanation
+ ) );
+ } else {
+ wp_send_json_error(
+ new WP_Error( 'post_error', __( 'Explanation could not be created.', 'wporg' ) )
+ );
+ }
+
+ }
+ }
+
+ /**
+ * AJAX handler for un-publishing an explanation.
+ *
+ * @access public
+ */
+ public function un_publish_explanation() {
+ check_ajax_referer( 'unpublish-expl', 'nonce' );
+
+ $post_id = empty( $_REQUEST['post_id'] ) ? 0 : absint( $_REQUEST['post_id'] );
+
+ if ( $explanation = \DevHub\get_explanation( $post_id ) ) {
+ $update = wp_update_post( array(
+ 'ID' => $explanation->ID,
+ 'post_status' => 'draft'
+ ) );
+
+ if ( ! is_wp_error( $update ) && 0 !== $update ) {
+ wp_send_json_success( array( 'post_id' => $update ) );
+ } else {
+ wp_send_json_error(
+ new WP_Error( 'unpublish_error', __( 'Explanation could not be un-published.', 'wporg' ) )
+ );
+ }
+ }
+ }
+}
+
+$init = new WPORG_Explanations();
Property changes on: inc/explanations.php
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: inc/parsed-content.php
===================================================================
--- inc/parsed-content.php (revision 1045)
+++ inc/parsed-content.php (working copy)
@@ -33,9 +33,6 @@
add_action( 'add_meta_boxes', array( $this, 'add_meta_boxes' ) );
add_action( 'save_post', array( $this, 'save_post' ) );
- // Script and styles.
- add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
-
// AJAX.
add_action( 'wp_ajax_wporg_attach_ticket', array( $this, 'attach_ticket' ) );
add_action( 'wp_ajax_wporg_detach_ticket', array( $this, 'detach_ticket' ) );
@@ -69,7 +66,7 @@
$ticket = get_post_meta( $post->ID, 'wporg_ticket_number', true );
$ticket_label = get_post_meta( $post->ID, 'wporg_ticket_title', true );
$ticket_info = get_post_meta( $post->ID, 'wporg_parsed_ticket_info', true );
- $content = get_post_meta( $post->ID, 'wporg_parsed_content', true );
+ $content = $post->post_content;
if ( $ticket ) {
$src = "https://core.trac.wordpress.org/ticket/{$ticket}";
@@ -98,12 +95,12 @@
- false,
'tinymce' => false,
'quicktags' => true,
'textarea_rows' => 10,
- 'textarea_name' => 'wporg_parsed_content',
+ 'textarea_name' => 'content',
) ); ?>
|
@@ -156,24 +153,6 @@
}
/**
- * Enqueue JS and CSS on the edit screens for all four post types.
- *
- * @access public
- */
- public function admin_enqueue_scripts() {
- // Only enqueue 'wporg-parsed-content' script and styles on Code Reference post type screens.
- if ( in_array( get_current_screen()->id, $this->post_types ) ) {
- wp_enqueue_style( 'wporg-parsed-content', get_template_directory_uri() . '/stylesheets/admin.css', array(), '20140826' );
- wp_enqueue_script( 'wporg-parsed-content', get_template_directory_uri() . '/js/parsed-content.js', array( 'jquery', 'utils' ), '20140826', true );
-
- wp_localize_script( 'wporg-parsed-content', 'wporg', array(
- 'ajaxURL' => admin_url( 'admin-ajax.php' ),
- 'searchText' => __( 'Searching ...', 'wporg' ),
- ) );
- }
- }
-
- /**
* AJAX handler for fetching the title of a Core Trac ticket and 'attaching' it to the post.
*
* @access public
Index: inc/template-tags.php
===================================================================
--- inc/template-tags.php (revision 1045)
+++ inc/template-tags.php (working copy)
@@ -1096,4 +1096,62 @@
return ( is_singular( $post_types ) || is_post_type_archive( $post_types ) || is_tax( $taxonomies ) );
}
+ /**
+ * Retrieve an explanation for the given post.
+ *
+ * @param int|WP_Post $post Post ID or WP_Post object.
+ * @param bool $published Optional. Whether to only retrieve the explanation if it's published.
+ * Default false.
+ * @return WP_Post|null WP_Post object for the Explanation, null otherwise.
+ */
+ function get_explanation( $post, $published = false ) {
+ if ( ! $post = get_post( $post ) ) {
+ return null;
+ }
+
+ $args = array(
+ 'post_type' => 'wporg_explanations',
+ 'post_parent' => $post->ID,
+ 'no_found_rows' => true,
+ 'posts_per_page' => 1,
+ );
+
+ if ( true === $published ) {
+ $args['post_status'] = 'publish';
+ }
+
+ $explanation = get_children( $args, OBJECT );
+
+ if ( empty( $explanation ) ) {
+ return null;
+ }
+
+ $explanation = reset( $explanation );
+
+ if ( ! $explanation ) {
+ return null;
+ }
+ return $explanation;
+ }
+
+ /**
+ * Retrieve data from an explanation post field.
+ *
+ * Works only for published explanations.
+ *
+ * @see get_post_field()
+ *
+ * @param string $field Post field name.
+ * @param int|WP_Post $post Post ID or object for the function, hook, class, or method post
+ * to retrieve an explanation field for.
+ * @param string $context Optional. How to filter the field. Accepts 'raw', 'edit', 'db',
+ * or 'display'. Default 'display'.
+ * @return string The value of the post field on success, empty string on failure.
+ */
+ function get_explanation_field( $field, $post, $context = 'display' ) {
+ if ( ! $explanation = get_explanation( $post, $published = true ) ) {
+ return '';
+ }
+ return get_post_field( $field, $explanation, $context );
+ }
}
\ No newline at end of file
Index: js/admin.js
===================================================================
--- js/admin.js (revision 1027)
+++ js/admin.js (working copy)
@@ -3,6 +3,12 @@
*/
( function( $ ) {
+
+ /**
+ * Parsed Content handler.
+ *
+ * AJAX handler for "attaching" Trac tickets to enable editing of parsed content.
+ */
var ticketNumber = $( '#wporg_parsed_ticket' ),
attachButton = $( '#wporg_ticket_attach' ),
detachButton = $( '#wporg_ticket_detach' ),
@@ -74,4 +80,90 @@
attachButton.on( 'click', { action: 'attach' }, handleTicket );
detachButton.on( 'click', { action: 'detach' }, handleTicket );
+ //
+ // Explanations AJAX handlers.
+ //
+
+ var statusLabel = $( '#status-label' ),
+ createLink = $( '#create-expl' ),
+ unPublishLink = $( '#unpublish-expl' ),
+ rowActions = $( '#expl-row-actions' );
+
+ /**
+ * AJAX handler for creating and associating a new explanation post.
+ *
+ * @param {object} event Event object.
+ */
+ function createExplanation( event ) {
+ event.preventDefault();
+
+ wp.ajax.send( 'new_explanation', {
+ success: createExplSuccess,
+ error: createExplError,
+ data: {
+ nonce: $( this ).data( 'nonce' ),
+ post_id: $( this ).data( 'id' )
+ }
+ } );
+ }
+
+ /**
+ * Success callback for creating a new explanation via AJAX.
+ *
+ * @param {object} data Data response object.
+ */
+ function createExplSuccess( data ) {
+ createLink.hide();
+ rowActions.html( '' + wporg.editContentLabel + '' );
+ statusLabel.text( wporg.statusLabel.draft );
+ }
+
+ /**
+ * Error callback for creating a new explanation via AJAX.
+ *
+ * @param {object} data Data response object.
+ */
+ function createExplError( data ) {}
+
+ /**
+ * Handler for un-publishing an existing Explanation.
+ *
+ * @param {object} event Event object.
+ */
+ function unPublishExplantaion( event ) {
+ event.preventDefault();
+
+ wp.ajax.send( 'un_publish', {
+ success: unPublishSuccess,
+ error: unPublishError,
+ data: {
+ nonce: $( this ).data( 'nonce' ),
+ post_id: $( this ).data( 'id' )
+ }
+ } );
+ }
+
+ /**
+ * Success callback for un-publishing an explanation via AJAX.
+ *
+ * @param {object} data Data response object.
+ */
+ function unPublishSuccess( data ) {
+ if ( statusLabel.hasClass( 'pending' ) || statusLabel.hasClass( 'publish' ) ) {
+ statusLabel.removeClass( 'pending publish' ).text( wporg.statusLabel.draft );
+ }
+ unPublishLink.hide();
+ }
+
+ /**
+ * Error callback for un-publishing an explanation via AJAX.
+ *
+ * @param {object} data Data response object.
+ */
+ function unPublishError( data ) {}
+
+ // Events.
+ $( '#create-expl' ).on( 'click', createExplanation );
+ $( '#unpublish-expl' ).on( 'click', unPublishExplantaion );
+
} )( jQuery );
Index: js/parsed-content.js
===================================================================
--- js/parsed-content.js (revision 1045)
+++ js/parsed-content.js (working copy)
@@ -1,77 +0,0 @@
-/**
- * Admin extras backend JS.
- */
-
-( function( $ ) {
- var ticketNumber = $( '#wporg_parsed_ticket' ),
- attachButton = $( '#wporg_ticket_attach' ),
- detachButton = $( '#wporg_ticket_detach' ),
- ticketInfo = $( '#wporg_ticket_info' ),
- spinner = $( '#ticket_status .spinner' );
-
- var handleTicket = function( event ) {
- event.preventDefault();
-
- var $this = $(this),
- attachAction = 'attach' == event.data.action;
-
- spinner.css( 'display', 'inline-block' );
-
- if ( attachAction ) {
- ticketInfo.text( wporg.searchText );
- }
-
- var data = {
- action: attachAction ? 'wporg_attach_ticket' : 'wporg_detach_ticket',
- ticket: ticketNumber.val(),
- nonce: $this.data( 'nonce' ),
- post_id: $this.data( 'id' )
- };
-
- $.post( wporg.ajaxURL, data, function( resp ) {
- // Refresh the nonce.
- $this.data( 'nonce', resp.new_nonce );
-
- spinner.hide();
-
- // Update the ticket info text
- ticketInfo.html( resp.message ).show();
-
- // Handle the response.
- if ( resp.type && 'success' == resp.type ) {
- // Hide or show the parsed content boxes.
- $( '.wporg_parsed_content' ).each( function() {
- attachAction ? $(this).show() : $(this).hide();
- });
-
- $( '.wporg_parsed_readonly' ).each( function() {
- attachAction ? $(this).hide() : $(this).show();
- });
-
- var otherButton = attachAction ? detachButton : attachButton;
-
- // Toggle the buttons.
- $this.hide();
- otherButton.css( 'display', 'inline-block' );
-
- // Clear the ticket number when detaching.
- if ( ! attachAction ) {
- ticketNumber.val( '' );
- }
-
- // Set or unset the ticket link icon.
- $( '.ticket_info_icon' ).toggleClass( 'dashicons dashicons-external', attachAction );
-
- // Set the ticket number to readonly when a ticket is attached.
- attachAction ? ticketNumber.prop( 'readonly', 'readonly' ) : ticketNumber.removeAttr( 'readonly' );
- } else {
- ticketInfo.text( wporg.retryText );
- }
-
- }, 'json' );
- };
-
- attachButton.on( 'click', { action: 'attach' }, handleTicket );
- detachButton.on( 'click', { action: 'detach' }, handleTicket );
-
-} )( jQuery );
Index: scss/admin.scss
===================================================================
--- scss/admin.scss (revision 1045)
+++ scss/admin.scss (working copy)
@@ -20,3 +20,55 @@
margin-bottom: 10px;
display: block;
}
+
+.post-type-wporg_explanations .add-new-h2 {
+ display: none;
+}
+
+.expl-row-actions {
+ display: block;
+
+ a {
+ display: inline-block;
+
+ &:first-child {
+ padding-right: 6px;
+ padding-left: 0;
+ }
+ &:nth-child(n+2) {
+ padding-left: 8px;
+ border-left: 1px solid #ccc;
+ }
+ }
+}
+
+.status {
+ font-weight: bold;
+
+ &.pending {
+ color: red;
+ }
+
+ &.publish {
+ color: green;
+ }
+}
+
+.post-type-wp-parser-function,
+.post-type-wp-parser-class,
+.post-type-wp-parser-method,
+.post-type-wp-parser-hook {
+ .form-table {
+ th {
+ padding-top: 10px;
+ padding-bottom: 10px;
+ }
+ td {
+ padding: 10px;
+
+ p {
+ margin-top: 0;
+ }
+ }
+ }
+}
Index: stylesheets/admin.css
===================================================================
--- stylesheets/admin.css (revision 1045)
+++ stylesheets/admin.css (working copy)
@@ -19,3 +19,52 @@
margin-bottom: 10px;
display: block;
}
+
+.post-type-wporg_explanations .add-new-h2 {
+ display: none;
+}
+
+.expl-row-actions {
+ display: block;
+}
+.expl-row-actions a {
+ display: inline-block;
+}
+.expl-row-actions a:first-child {
+ padding-right: 6px;
+ padding-left: 0;
+}
+.expl-row-actions a:nth-child(n+2) {
+ padding-left: 8px;
+ border-left: 1px solid #ccc;
+}
+
+.status {
+ font-weight: bold;
+}
+.status.pending {
+ color: red;
+}
+.status.publish {
+ color: green;
+}
+
+.post-type-wp-parser-function .form-table th,
+.post-type-wp-parser-class .form-table th,
+.post-type-wp-parser-method .form-table th,
+.post-type-wp-parser-hook .form-table th {
+ padding-top: 10px;
+ padding-bottom: 10px;
+}
+.post-type-wp-parser-function .form-table td,
+.post-type-wp-parser-class .form-table td,
+.post-type-wp-parser-method .form-table td,
+.post-type-wp-parser-hook .form-table td {
+ padding: 10px;
+}
+.post-type-wp-parser-function .form-table td p,
+.post-type-wp-parser-class .form-table td p,
+.post-type-wp-parser-method .form-table td p,
+.post-type-wp-parser-hook .form-table td p {
+ margin-top: 0;
+}