Making WordPress.org

Ticket #1866: 1866.diff

File 1866.diff, 9.9 KB (added by iandunn, 6 years ago)
  • handbook.php

     
    1414require_once dirname( __FILE__ ) . '/inc/email-post-changes.php';
    1515require_once dirname( __FILE__ ) . '/inc/walker.php';
    1616require_once dirname( __FILE__ ) . '/inc/watchlist.php';
     17require_once dirname( __FILE__ ) . '/inc/feedback.php';
    1718
    1819/**
    1920 * Initialize our handbooks
     
    4647        }
    4748
    4849        static public function enqueue_scripts() {
    49                 wp_enqueue_script( 'wporg-handbook', plugins_url( '/scripts/handbook.js', __FILE__ ), array( 'jquery' ), '20150930' );
     50                wp_enqueue_script( 'wporg-handbook', plugins_url( '/scripts/handbook.js', __FILE__ ), array( 'jquery', 'wp-api-fetch', 'utils'), '20190915' );
    5051        }
    5152
    5253}
  • inc/feedback.php

     
     1<?php
     2
     3/**
     4 * Class providing a mechanism for users to submit feedback on posts.
     5 *
     6 * @package handbook
     7 */
     8class WPorg_Handbook_Feedback {
     9        /**
     10         * Initialize the Feedback module.
     11         */
     12        static function init() {
     13                add_action( 'rest_api_init',   array( __CLASS__, 'register_rest_endpoints' ) );
     14                add_action( 'wp_print_styles', array( __CLASS__, 'print_styles' ) );
     15                add_filter( 'the_content',     array( __CLASS__, 'render_form' ) );
     16        }
     17
     18        /**
     19         * Register REST API endpoints.
     20         */
     21        static public function register_rest_endpoints() {
     22                register_rest_route(
     23                        'wporg-handbook/v1',
     24                        'submit-feedback' ,
     25                        array(
     26                                'methods'  => array( 'PUT' ),
     27                                'callback' => array( __CLASS__, 'handle_form_submission' ),
     28                        ) );
     29        }
     30
     31        /**
     32         * Email feedback to the site admin.
     33         *
     34         * @param WP_REST_Request $request
     35         *
     36         * @return string|WP_Error
     37         */
     38        static public function handle_form_submission( $request ) {
     39                $admin_email = get_option( 'admin_email' );
     40
     41                // Removing tags for formatting purposes, but still need to practice late-escaping for security purposes.
     42                $page_id          = absint( $request->get_param( 'pageID' ) );
     43                $page_title       = strip_tags( get_the_title( $page_id ) );
     44                $feedback         = strip_tags( $request->get_param( 'message' ) );
     45                $valid_submission = $page_id && ! empty( $feedback );
     46
     47                $response = new WP_Error(
     48                        'email_failed',
     49                        sprintf(
     50                                __( "I'm sorry, but your feedback could not be submitted, please send an email to %s instead.", 'wporg' ),
     51                                $admin_email
     52                        )
     53                );
     54
     55                if ( ! $valid_submission ) {
     56                        return $response;
     57                }
     58
     59                $message = sprintf(
     60                        // translators: %s is a post title.
     61                        __( 'Somebody reported that "%s" did not help them, and suggested the following changes:', 'wporg' ) . "\n\n" .
     62                        '----' . "\n\n" .
     63                        '%s'   . "\n\n" .
     64                        '----' . "\n\n" .
     65                        __( 'If you think those would be helpful changes, please edit the page to reflect them.', 'wporg' ) . "\n\n" .
     66                        '%s',
     67                        esc_html( $page_title ),
     68                        esc_html( $feedback ),
     69                        esc_url_raw( get_edit_post_link( $page_id, 'raw' ) )
     70                );
     71
     72                $mail_sent = wp_mail(
     73                        $admin_email,
     74                        // translators: %s is a post title.
     75                        sprintf( __( 'Feedback on "%s"', 'wporg' ), esc_html( $page_title ) ),
     76                        $message
     77                );
     78
     79                if ( $mail_sent ) {
     80                        $response = __( 'Thanks for your feedback!', 'wporg' );
     81                }
     82
     83                return $response;
     84        }
     85
     86        /**
     87         * Print the styles needed for the feedback markup.
     88         */
     89        static public function print_styles() {
     90                wp_enqueue_style( 'dashicons' );
     91
     92                ?>
     93
     94                <!-- handbook/feedback -->
     95                <style>
     96                        .handbook-feedback {
     97                        }
     98
     99                        .feedback-vote {
     100                                background-color: #B4B9BE;
     101                        }
     102
     103                        .feedback-vote-helpful.has-voted {
     104                                background-color: #46B450;
     105                        }
     106
     107                        .feedback-vote-unhelpful.has-voted {
     108                                background-color: #DC3232;
     109                        }
     110
     111                        #feedback-message-container {
     112                                margin-top: 10px;
     113                        }
     114
     115                        #feedback-message-container input[type="submit"] {
     116                                margin-top: 10px;
     117                        }
     118
     119                        .handbook-spinner {
     120                                background: url( <?php echo esc_url( admin_url( 'images/spinner.gif' ) ); ?> ) no-repeat;
     121                                background-size: 20px 20px;
     122                                display: inline-block;
     123                                vertical-align: middle;
     124                                opacity: 0.7;
     125                                filter: alpha( opacity=70 );
     126                                width: 20px;
     127                                height: 20px;
     128                                margin: 0 0 0 5px;
     129                        }
     130
     131                        .dashicons.feedback-success {
     132                                color: #46B450;
     133                        }
     134
     135                        .dashicons.feedback-error {
     136                                color: #DC3232;
     137                        }
     138                </style>
     139
     140                <?php
     141        }
     142
     143        /**
     144         * Append the feedback form to the post's content.
     145         *
     146         * @param string $content
     147         *
     148         * @return string
     149         */
     150        static public function render_form( $content ) {
     151                if ( 'handbook' !== get_post_type() ) {
     152                        return $content;
     153                }
     154
     155                /*
     156                 * Prevent this function from being called multiple times, because shortcodes in the page content apply
     157                 * `the_content`, etc.
     158                 */
     159                remove_filter( 'the_content', array( __CLASS__, 'render_form' ) );
     160
     161                ob_start();
     162
     163                ?>
     164
     165                <div class="handbook-feedback callout callout-info">
     166                        <?php esc_html_e( 'Did this page help you?', 'wporg' ); ?>
     167
     168                        <button class="feedback-vote feedback-vote-helpful">
     169                                <span class="dashicons dashicons-thumbs-up">
     170                                        <span class="screen-reader-text">
     171                                                <?php esc_html_e( 'Yes', 'wporg' ); ?>
     172                                        </span>
     173                                </span>
     174                        </button>
     175
     176                        <button class="feedback-vote feedback-vote-unhelpful">
     177                                <span class="dashicons dashicons-thumbs-down">
     178                                        <span class="screen-reader-text">
     179                                                <?php esc_html_e( 'No', 'wporg' ); ?>
     180                                        </span>
     181                                </span>
     182                        </button>
     183
     184                        <div id="feedback-message-container" style="display: none;">
     185                                <input id="handbook-page-id" type="hidden" value="<?php echo absint( get_the_ID() ); ?>" />
     186
     187                                <label for="feedback-message">
     188                                        <?php esc_html_e( 'How could it have been more helpful?', 'wporg' ); ?>
     189                                </label>
     190                                <textarea id="feedback-message" name="feedback-message"></textarea>
     191
     192                                <input id="submit-feedback" type="submit" value="Send Feedback">
     193                        </div>
     194                </div>
     195
     196                <script id="tmpl-handbook-feedback-spinner" type="text/template">
     197                        <?php esc_html_e( 'Sending feedback...', 'wporg' ); ?>
     198                        <span class="handbook-spinner"></span>
     199                </script>
     200
     201                <script id="tmpl-handbook-feedback-submission-result" type="text/template">
     202                        <span class="dashicons dashicons-{{data.icon}} feedback-{{data.status}}"></span>
     203
     204                        {{data.message}}
     205                </script>
     206
     207                <?php
     208
     209                return $content . ob_get_clean();
     210        }
     211}
     212
     213WPorg_Handbook_Feedback::init();
  • scripts/handbook.js

    Property changes on: inc/feedback.php
    ___________________________________________________________________
    Added: svn:eol-style
    ## -0,0 +1 ##
    +native
    \ No newline at end of property
     
     1var wp = wp || {};
     2wp.handbook = wp.handbook || {};
     3
    14/**
    25 * Enables toggling visibility of all the chapters in the Handbook Chapter widget.
    36 *
     
    3235        }
    3336});
    3437
     38
     39jQuery( document ).ready( function() {
     40        'use strict';
     41
     42        var app = wp.handbook.feedback = {
     43                /**
     44                 * Main entry point
     45                 */
     46                init: function () {
     47                        app.container        = document.getElementsByClassName( 'handbook-feedback' )[ 0 ];
     48                        app.voteUp           = app.container.getElementsByClassName( 'feedback-vote-helpful' )[ 0 ];
     49                        app.voteDown         = app.container.getElementsByClassName( 'feedback-vote-unhelpful' )[ 0 ];
     50                        app.messageContainer = document.getElementById( 'feedback-message-container' );
     51
     52                        app.voteUp.addEventListener(   'click', app.vote );
     53                        app.voteDown.addEventListener( 'click', app.vote );
     54                        document.getElementById( 'submit-feedback' ).addEventListener( 'click', app.submitFeedback );
     55                },
     56
     57                /**
     58                 * Handle the event when a user clicks on a vote up/down button.
     59                 *
     60                 * @param {object} event
     61                 */
     62                vote: function( event ) {
     63                        var targetClass = event.target.className,
     64                            // The class will be different depending on if they click on the button or the Dashicon inside the button.
     65                            wasHelpful = -1 !== targetClass.indexOf( 'vote-helpful' ) || -1 !== targetClass.indexOf( 'thumbs-up' );
     66
     67
     68                        if ( wasHelpful ) {
     69                                app.voteUp.classList.add( 'has-voted' );
     70                                app.voteDown.classList.remove( 'has-voted' );
     71                                app.messageContainer.style.display = 'none';
     72
     73                                // There's nothing else to do right now, but in the future we could track votes for stats, etc.
     74                                return;
     75                        }
     76
     77                        app.voteUp.classList.remove( 'has-voted' );
     78                        app.voteDown.classList.add( 'has-voted' );
     79                        app.messageContainer.style.display = 'block';
     80                        app.messageContainer.scrollIntoView( { behavior : "smooth", block : "end", inline : "nearest" } );
     81                },
     82
     83                /**
     84                 * Handle the event when a user clicks on a Submit Feedback button.
     85                 *
     86                 * @param {object} event
     87                 */
     88                submitFeedback: function( event ) {
     89                        var template     = wp.template( 'handbook-feedback-spinner' ),
     90                            templateData = {},
     91                                fetchOptions = {
     92                                        path: 'wporg-handbook/v1/submit-feedback',
     93                                        method: 'PUT',
     94                                        data: {
     95                                                pageID:  document.getElementById( 'handbook-page-id' ).value,
     96                                                message: document.getElementById( 'feedback-message' ).value,
     97                                        }
     98                                };
     99
     100                        app.messageContainer.innerHTML = template();
     101
     102                        wp.apiFetch( fetchOptions ).then( function( message ) {
     103                                templateData.status  = 'success';
     104                                templateData.icon    = 'yes-alt';
     105                                templateData.message = message;
     106
     107                        } ).catch( function( error ) {
     108                                templateData.status  = 'error';
     109                                templateData.icon    = 'warning';
     110                                templateData.message = error.message;
     111
     112                        } ).finally( function() {
     113                                template = wp.template( 'handbook-feedback-submission-result' );
     114                                app.messageContainer.innerHTML = template( templateData );
     115                        } );
     116                },
     117        };
     118
     119        /*
     120         * We have to wait until after the `ready.o2` event fires, because otherwise o2 will wipe out any registered
     121         * event handlers for elements inside the post content.
     122         *
     123         * See https://github.com/Automattic/o2/issues/175.
     124         */
     125        jQuery( document ).on( 'ready.o2', function() {
     126                app.init();
     127        } );
     128} );