WordPress.org

Making WordPress.org

Changeset 6268


Ignore:
Timestamp:
12/13/17 22:42:47 (5 weeks ago)
Author:
iandunn
Message:

WordCamp Post Types: Add ability for attendees to "favorite" sessions.

This contains the code for emailing the saved sessions to yourself, but the UI for that is temporarily disabled pending a discussion with the Systems team about potential abuse mitigations.

See #2733
Props egmanekki

Location:
sites/trunk/wordcamp.org/public_html/wp-content/plugins/wc-post-types
Files:
2 added
3 edited

Legend:

Unmodified
Added
Removed
  • sites/trunk/wordcamp.org/public_html/wp-content/plugins/wc-post-types/css/shortcodes.css

    r3602 r6268  
    22 * [schedule] 
    33 */ 
     4 .wcb-favourite-session { 
     5    background: #e0f8ff; 
     6} 
     7 
     8.wcpt-schedule td { 
     9    vertical-align: top; 
     10} 
     11 
     12.wcpt-schedule div.wcb-session-favourite-icon { 
     13    float: right; 
     14    width: 35px; 
     15    text-align: center; 
     16} 
     17 
     18.wcpt-schedule .dashicons { 
     19    position: relative; 
     20    box-sizing: content-box; 
     21    width: 25px; 
     22    height: 25px; 
     23    overflow: hidden; 
     24    white-space: nowrap; 
     25    font-size: 16px; 
     26    line-height: 1; 
     27    cursor: pointer; 
     28} 
     29 
     30.wcpt-schedule .dashicons:before { 
     31    margin-right: 0px; 
     32} 
     33 
     34.wcpt-schedule .dashicons:after { 
     35    display: block; 
     36    font-size: 9px; 
     37    color: #999; 
     38    text-align: right; 
     39} 
     40 
     41 
     42div.wcb-session-favourite-icon a.fav-session-button { 
     43    color: #e8e8e8; 
     44    text-decoration: none; 
     45} 
     46 
     47 
     48div.wcb-session-favourite-icon a.fav-session-button:hover, 
     49#content a.fav-session-button:hover { 
     50    color: #fff689; 
     51    text-decoration: none; 
     52} 
     53 
     54 
     55td.wcb-favourite-session a.fav-session-button { 
     56    color: #fff689; 
     57} 
     58 
     59.fav-session-email-wait-spinner { 
     60    display: none; 
     61    border: 2px solid #f3f3f3; 
     62    border-radius: 50%; 
     63    border-top: 2px solid #777; 
     64    width: 16px; 
     65    height: 16px; 
     66    margin: 10px auto; 
     67    -webkit-animation: spin 2s linear infinite; 
     68    animation: spin 2s linear infinite; 
     69} 
     70 
     71@-webkit-keyframes spin { 
     72    0% { -webkit-transform: rotate( 0deg ); } 
     73    100% { -webkit-transform: rotate( 360deg ); } 
     74} 
     75 
     76@keyframes spin { 
     77    0% { transform: rotate( 0deg ); } 
     78    100% { transform: rotate( 360deg ); } 
     79} 
     80 
     81 
     82/* 
     83 * CSS slide for email form for favourite sessions 
     84 */ 
     85.fav-session-email-form-hide { 
     86    overflow: hidden; 
     87    max-height: 0; 
     88    padding-top: 0; 
     89    padding-bottom: 0; 
     90    margin-top: 0; 
     91    margin-bottom: 0; 
     92    -moz-transition-duration: 0.5s; 
     93    -webkit-transition-duration: 0.5s; 
     94    -o-transition-duration: 0.5s; 
     95    transition-duration: 0.5s; 
     96    -moz-transition-timing-function: cubic-bezier( 0, 1, 0.5, 1 ); 
     97    -webkit-transition-timing-function: cubic-bezier( 0, 1, 0.5, 1 ); 
     98    -o-transition-timing-function: cubic-bezier( 0, 1, 0.5, 1 ); 
     99    transition-timing-function: cubic-bezier( 0, 1, 0.5, 1 ); 
     100} 
     101 
     102.fav-session-email-form-show { 
     103    -moz-transition-duration: 0.5s; 
     104    -webkit-transition-duration: 0.5s; 
     105    -o-transition-duration: 0.5s; 
     106    transition-duration: 0.5s; 
     107    -moz-transition-timing-function: ease-in; 
     108    -webkit-transition-timing-function: ease-in; 
     109    -o-transition-timing-function: ease-in; 
     110    transition-timing-function: ease-in; 
     111    max-height: 1000px; 
     112    overflow: hidden; 
     113} 
     114 
     115.show-email-form { 
     116    display: none; 
     117    position: fixed; 
     118    bottom: 20px; 
     119    right: 100px; 
     120    padding: 5px 8px 1px 7px; 
     121    border: 1px solid #a1a1a1; 
     122    background: #dddddd; 
     123    border-radius: 6px; 
     124    color: #a1a1a1; 
     125    z-index: 9999; 
     126} 
     127 
     128.email-form { 
     129    position: fixed; 
     130    bottom: 50px; 
     131    right: 100px; 
     132    width: 200px; 
     133    background: #dcdcdc; 
     134    font-size: 12px; 
     135    z-index: 9999; 
     136    border-radius: 6px; 
     137} 
     138 
     139#fav-session-email-form { 
     140    margin: 10px; 
     141} 
     142 
     143#fav-sessions-email-address { 
     144    width: 100%; 
     145    margin-bottom: 5px; 
     146    padding: 1px 5px; 
     147} 
     148 
     149.fav-session-email-result { 
     150    display: none; 
     151    margin: 10px; 
     152} 
     153 
     154.fav-sessions-form { 
     155    display: none; 
     156} 
     157 
     158.show-email-form, 
     159.entry-content a.show-email-form { 
     160    color: #a1a1a1; 
     161    text-decoration: none; 
     162} 
     163 
     164.show-email-form:hover, 
     165.entry-content a.show-email-form:hover, 
     166#content a.show-email-form:hover { 
     167    color: #555; 
     168    text-decoration: none; 
     169} 
     170 
     171.show-email-form .dashicons-star-filled { 
     172    font-size: 14px; 
     173    padding-top: 2px; 
     174    width: 14px; 
     175} 
     176 
    4177@media screen and ( max-width: 700px ) { 
    5178    .wcpt-schedule { 
     
    73246        color: #21759b; 
    74247    } 
     248 
     249    .show-email-form, 
     250    .email-form { 
     251        right: 20px; 
     252    } 
     253 
    75254} 
    76255 
  • sites/trunk/wordcamp.org/public_html/wp-content/plugins/wc-post-types/inc/rest-api.php

    r5533 r6268  
    77 
    88namespace WordCamp\Post_Types\REST_API; 
     9use WP_Rest_Server; 
     10 
    911defined( 'WPINC' ) || die(); 
     12 
     13require_once( 'favorite-schedule-shortcode.php' ); 
    1014 
    1115/** 
     
    112116} 
    113117 
     118 
    114119add_action( 'rest_api_init', __NAMESPACE__ . '\register_additional_rest_fields' ); 
     120 
     121 
     122/** 
     123 * Register route for sending schedule of favourite sessions via e-mail. 
     124 * 
     125 * This can be disabled in email_fav_sessions_disabled() from favorite-schedule-shortcode.php. 
     126 * 
     127 * @return void 
     128 */ 
     129function register_fav_sessions_email(){ 
     130    register_rest_route( 
     131        'wc-post-types/v1',     // REST namespace + API version 
     132        '/email-fav-sessions/', // URL slug 
     133        array( 
     134            'methods'  => WP_REST_Server::CREATABLE, 
     135            'callback' => 'send_favourite_sessions_email', 
     136            'args'     => array( 
     137                'email-address' => array( 
     138                    'required' => true, 
     139                    'validate_callback' => function( $value, $request, $param ) { 
     140                        return is_email( $value ); 
     141                    }, 
     142                    'sanitize_callback' => function( $value, $request, $param ) { 
     143                        return sanitize_email( $value ); 
     144                    }, 
     145                ), 
     146 
     147                'session-list' => array( 
     148                    'required' => true, 
     149                    'validate_callback' => function( $value, $request, $param ) { 
     150                        $session_ids = explode( ',', $value ); 
     151                        $session_count = count( $session_ids ); 
     152                        for ( $i = 0; $i < $session_count; $i++ ) { 
     153                            if ( ! is_numeric( $session_ids[ $i ] ) ) { 
     154                                return false; 
     155                            } 
     156                        } 
     157                        return true; 
     158                    }, 
     159                    'sanitize_callback' => function( $value, $request, $param ) { 
     160                        $session_ids = explode( ',', $value ); 
     161                        return implode( ',', array_filter( $session_ids, 'is_numeric' ) ); 
     162                    }, 
     163                ), 
     164            ) 
     165        ) 
     166    ); 
     167} 
     168add_action( 'rest_api_init', __NAMESPACE__ . '\register_fav_sessions_email' ); 
    115169 
    116170/** 
  • sites/trunk/wordcamp.org/public_html/wp-content/plugins/wc-post-types/wc-post-types.php

    r6227 r6268  
    66 
    77require( 'inc/back-compat.php' ); 
     8require_once( 'inc/favorite-schedule-shortcode.php' ); 
    89 
    910class WordCamp_Post_Types_Plugin { 
     
    514515     */ 
    515516    function shortcode_schedule( $attr, $content ) { 
    516         $attr = shortcode_atts( array( 
    517             'date'         => null, 
    518             'tracks'       => 'all', 
    519             'speaker_link' => 'anchor', // anchor|wporg|permalink|none 
    520             'session_link' => 'permalink', // permalink|anchor|none 
    521         ), $attr ); 
    522  
    523         foreach ( array( 'tracks', 'speaker_link', 'session_link' ) as $key_for_case_sensitive_value ) { 
    524             $attr[ $key_for_case_sensitive_value ] = strtolower( $attr[ $key_for_case_sensitive_value ] ); 
    525         } 
    526  
    527         if ( ! in_array( $attr['speaker_link'], array( 'anchor', 'wporg', 'permalink', 'none' ) ) ) 
    528             $attr['speaker_link'] = 'anchor'; 
    529  
    530         if ( ! in_array( $attr['session_link'], array( 'permalink', 'anchor', 'none' ) ) ) 
    531             $attr['session_link'] = 'permalink'; 
    532  
    533         $columns = array(); 
    534         $tracks = array(); 
    535  
    536         $query_args = array( 
    537             'post_type'      => 'wcb_session', 
    538             'posts_per_page' => -1, 
    539             'meta_query'     => array( 
    540                 'relation'   => 'AND', 
    541                 array( 
    542                     'key'     => '_wcpt_session_time', 
    543                     'compare' => 'EXISTS', 
    544                 ), 
    545             ), 
    546         ); 
    547  
    548         if ( 'all' == $attr['tracks'] ) { 
    549             // Include all tracks. 
    550             $tracks = get_terms( 'wcb_track' ); 
    551         } else { 
    552             // Loop through given tracks and look for terms. 
    553             $terms = array_map( 'trim', explode( ',', $attr['tracks'] ) ); 
    554             foreach ( $terms as $term_slug ) { 
    555                 $term = get_term_by( 'slug', $term_slug, 'wcb_track' ); 
    556                 if ( $term ) 
    557                     $tracks[ $term->term_id ] = $term; 
    558             } 
    559  
    560             // If tracks were provided, restrict the lookup in WP_Query. 
    561             if ( ! empty( $tracks ) ) { 
    562                 $query_args['tax_query'][] = array( 
    563                     'taxonomy' => 'wcb_track', 
    564                     'field'    => 'id', 
    565                     'terms'    => array_values( wp_list_pluck( $tracks, 'term_id' ) ), 
    566                 ); 
    567             } 
    568         } 
    569  
    570         if ( $attr['date'] && strtotime( $attr['date'] ) ) { 
    571             $query_args['meta_query'][] = array( 
    572                 'key'   => '_wcpt_session_time', 
    573                 'value' => array( 
    574                     strtotime( $attr['date'] ), 
    575                     strtotime( $attr['date'] . ' +1 day' ), 
    576                 ), 
    577                 'compare' => 'BETWEEN', 
    578                 'type'    => 'NUMERIC', 
    579             ); 
    580         } 
    581  
    582         // Use tracks to form the columns. 
    583         if ( $tracks ) { 
    584             foreach ( $tracks as $track ) 
    585                 $columns[ $track->term_id ] = $track->term_id; 
    586         } else { 
    587             $columns[ 0 ] = 0; 
    588         } 
    589  
    590         unset( $tracks ); 
    591  
    592         // Loop through all sessions and assign them into the formatted 
    593         // $sessions array: $sessions[ $time ][ $track ] = $session_id 
    594         // Use 0 as the track ID if no tracks exist 
    595  
    596         $sessions = array(); 
    597         $sessions_query = new WP_Query( $query_args ); 
    598         foreach ( $sessions_query->posts as $session ) { 
    599             $time = absint( get_post_meta( $session->ID, '_wcpt_session_time', true ) ); 
    600             $tracks = get_the_terms( $session->ID, 'wcb_track' ); 
    601  
    602             if ( ! isset( $sessions[ $time ] ) ) 
    603                 $sessions[ $time ] = array(); 
    604  
    605             if ( empty( $tracks ) ) { 
    606                 $sessions[ $time ][ 0 ] = $session->ID; 
    607             } else { 
    608                 foreach ( $tracks as $track ) 
    609                     $sessions[ $time ][ $track->term_id ] = $session->ID; 
    610             } 
    611         } 
    612  
    613         // Sort all sessions by their key (timestamp). 
    614         ksort( $sessions ); 
    615  
    616         // Remove empty columns unless tracks have been explicitly specified 
    617         if ( 'all' == $attr['tracks'] ) { 
    618             $used_terms = array(); 
    619  
    620             foreach ( $sessions as $time => $entry ) 
    621                 if ( is_array( $entry ) ) 
    622                     foreach ( $entry as $term_id => $session_id ) 
    623                         $used_terms[ $term_id ] = $term_id; 
    624  
    625             $columns = array_intersect( $columns, $used_terms ); 
    626             unset( $used_terms ); 
    627         } 
    628  
    629         $html = '<table class="wcpt-schedule" border="0">'; 
     517        $this->enqueue_schedule_shortcode_dependencies(); 
     518 
     519        $attr                        = preprocess_schedule_attributes( $attr ); 
     520        $tracks                      = get_schedule_tracks( $attr['tracks'] ); 
     521        $tracks_explicitly_specified = 'all' !== $attr['tracks']; 
     522        $sessions                    = get_schedule_sessions( $attr['date'], $tracks_explicitly_specified, $tracks ); 
     523        $columns                     = get_schedule_columns( $tracks, $sessions, $tracks_explicitly_specified ); 
     524 
     525        $html  = '<table class="wcpt-schedule" border="0">'; 
    630526        $html .= '<thead>'; 
    631527        $html .= '<tr>'; 
     
    718614                $classes[] = 'wcb-session-' . $session->post_name; 
    719615 
     616                // Favourite session star-icon. 
     617                $content = '<div class="wcb-session-favourite-icon">'; 
     618                $content .= '<a class="fav-session-button"><span class="dashicons dashicons-star-filled"></span></a></div>'; 
     619                $content .= '<div class="wcb-session-cell-content">'; 
     620 
    720621                // Determine the session title 
    721622                if ( 'permalink' == $attr['session_link'] && 'session' == $session_type ) 
     
    726627                    $session_title_html = sprintf( '<span class="wcpt-session-title">%s</span>', $session_title ); 
    727628 
    728                 $content = $session_title_html; 
     629                $content .= $session_title_html; 
    729630 
    730631                $speakers_names = array(); 
     
    748649                if ( count( $speakers_names ) ) 
    749650                    $content .= sprintf( ' <span class="wcpt-session-speakers">%s</span>', implode( ', ', $speakers_names ) ); 
     651 
     652                // End of cell-content. 
     653                $content .= '</div>'; 
    750654 
    751655                $columns_clone = $columns; 
     
    766670                } 
    767671 
    768                 $columns_html .= sprintf( '<td colspan="%d" class="%s" data-track-title="%s">%s</td>', $colspan, esc_attr( implode( ' ', $classes ) ), $session_track_titles, $content ); 
     672                $columns_html .= sprintf( '<td colspan="%d" class="%s" data-track-title="%s" data-session-id="%s">%s</td>', $colspan, esc_attr( implode( ' ', $classes ) ), $session_track_titles, esc_attr( $session->ID ), $content ); 
    769673            } 
    770674 
     
    780684        $html .= '</tbody>'; 
    781685        $html .= '</table>'; 
     686        $html .= $this->fav_session_email_form(); 
    782687        return $html; 
    783688    } 
    784689 
    785690    /** 
     691     * Enqueue style and scripts needed for [schedule] shortcode. 
     692     */ 
     693    function enqueue_schedule_shortcode_dependencies() { 
     694        wp_enqueue_style( 'dashicons' ); 
     695 
     696        wp_enqueue_script( 
     697            'favourite-sessions', 
     698            plugin_dir_url( __FILE__ ) . 'js/favourite-sessions.js', 
     699            array( 'jquery' ), 
     700            filemtime( plugin_dir_path( __FILE__ ) . 'js/favourite-sessions.js' ), 
     701            true 
     702        ); 
     703 
     704        wp_localize_script( 
     705            'favourite-sessions', 
     706            'favSessionsPhpObject', 
     707            array( 
     708                'root' => esc_url_raw( rest_url() ), 
     709                'i18n' => array( 
     710                    'reqTimeOut' => esc_html__( 'Sorry, the email request timed out.', 'wordcamporg' ), 
     711                    'otherError' => esc_html__( 'Sorry, the email request failed.',    'wordcamporg' ), 
     712                ), 
     713            ) 
     714        ); 
     715    } 
     716 
     717    /** 
     718     * Return HTML code for email form used to send/share favourite sessions over email. 
     719     * 
     720     * Both form and button/link to show/hide the form can be styled using classes email-form 
     721     * and show-email-form, respectively. 
     722     * 
     723     * @return string HTML code that represents the form to send emails and a link to show and hide it. 
     724     */ 
     725    function fav_session_email_form() { 
     726        static $email_form_count = 0; 
     727 
     728        // Skip email form if it is disabled or it was already added to document. 
     729        if ( email_fav_sessions_disabled() || $email_form_count !== 0 ) { 
     730            return ''; 
     731        } 
     732 
     733        ob_start(); 
     734        ?> 
     735 
     736        <div class="email-form fav-session-email-form-hide"> 
     737            <div id="fav-session-email-form"> 
     738                <?php esc_html_e( 'Send me my favorite sessions:', 'wordcamporg' ); ?> 
     739 
     740                <form id="fav-sessions-form"> 
     741                    <input type="text" name="email_address" id="fav-sessions-email-address" placeholder="my@email.com" /> 
     742                    <input type="submit" value="<?php esc_attr_e( 'Send', 'wordcamporg' ); ?>" /> 
     743                </form> 
     744            </div> 
     745            <div class="fav-session-email-wait-spinner"></div> 
     746            <div class="fav-session-email-result"></div> 
     747        </div> 
     748 
     749        <a class="show-email-form" href="javascript:"> 
     750            <span class="dashicons dashicons-star-filled"></span> 
     751            <span class="dashicons dashicons-email-alt"></span> 
     752        </a> 
     753 
     754        <?php 
     755        $email_form = ob_end_flush(); 
     756 
     757        $email_form_count++; 
     758 
     759        return $email_form; 
     760    } 
     761 
     762    /** 
    786763     * Returns a speaker's WordPress.org profile url (if username set) 
    787764     * 
    788765     * @param $speaker_id int The speaker's post id. 
     766     * 
     767     * @return NULL|string 
    789768     */ 
    790769    function get_speaker_wporg_permalink( $speaker_id ) { 
Note: See TracChangeset for help on using the changeset viewer.