Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 788 lines (659 sloc) 23.587 kB
8ff4206 @mjangda v1
mjangda authored
1 <?php
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
2
8ff4206 @mjangda v1
mjangda authored
3 /**
4 * Plugin Name: Liveblog
5 * Description: Blogging: at the speed of live.
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
6 * Version: 0.1
7 * Author: WordPress.com VIP, Automattic
8ff4206 @mjangda v1
mjangda authored
8 */
9
10 if ( ! class_exists( 'WPCOM_Liveblog' ) ) :
11
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
12 /**
13 * The main Liveblog class used to setup everything this plugin needs.
14 *
15 * Liveblog currently uses a custom comment-type to circumvent post cache
16 * issues frequently experienced by other live-blog implimentations. It comes
17 * with a simple and effective templating mechanism, complete with all of the
18 * CSS, JS, and AJAX needed to make this a turn-key installation.
19 *
20 * This class is a big container for a bunch of static methods, similar to a
21 * factory but without object inheritance or instantiation.
8413aff @johnjamesjacoby Uploading:
johnjamesjacoby authored
22 *
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
23 * Things yet to be implimented:
24 *
25 * -- PHP and JS Actions/Filters/Triggers
26 * -- Change "Read More" to "View Liveblog"
27 * -- Manual refresh button
28 * -- Allow marking of liveblog as ended
29 * -- Allow comment modifications; need to store modified date as comment_meta
30 * -- Drag-and-drop image uploading support
31 *
32 * @todo more batcache testing
33 */
34 final class WPCOM_Liveblog {
35
36 /** Constants *************************************************************/
8ff4206 @mjangda v1
mjangda authored
37
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
38 const version = 0.1;
39 const key = 'liveblog';
40 const url_endpoint = 'liveblog';
41 const edit_cap = 'publish_posts';
42 const nonce_key = 'liveblog_nonce';
8ff4206 @mjangda v1
mjangda authored
43
ed1991c @nb Shut the auto-update only on consecutive failures
nb authored
44 const refresh_interval = 3; // how often should we refresh
45 const max_consecutive_retries = 100; // max number of failed tries before polling is disabled
46 const delay_threshold = 5; // how many failed tries after which we should increase the refresh interval
47 const delay_multiplier = 2; // by how much should we inscrease the refresh interval
8ff4206 @mjangda v1
mjangda authored
48
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
49 /** Variables *************************************************************/
50
51 private static $post_id = null;
52 private static $entry_query = null;
53 private static $do_not_cache_response = false;
1b8e8d5 @nb Streamline logic for getting recent entries
nb authored
54
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
55 /** Load Methods **********************************************************/
56
57 /**
58 * @uses add_action() to hook methods into WordPress actions
59 * @uses add_filter() to hook methods into WordPress filters
60 */
61 public static function load() {
62 self::includes();
63 self::add_actions();
64 self::add_filters();
65 self::add_admin_actions();
66 }
67
68 /**
69 * Include the necessary files
70 */
71 private static function includes() {
72 require( dirname( __FILE__ ) . '/classes/class-wpcom-liveblog-entry.php' );
73 require( dirname( __FILE__ ) . '/classes/class-wpcom-liveblog-entry-query.php' );
e691fe3 @johnjamesjacoby Include ms.php theme-side for its filesize and available space functi…
johnjamesjacoby authored
74
75 // Manually include ms.php theme-side in multisite environments because
76 // we need its filesize and available space functions.
77 if ( ! is_admin() && is_multisite() ) {
8f5fb3c @johnjamesjacoby Remove preceding slash. ABSPATH is already slashed for us.
johnjamesjacoby authored
78 require_once( ABSPATH . 'wp-admin/includes/ms.php' );
e691fe3 @johnjamesjacoby Include ms.php theme-side for its filesize and available space functi…
johnjamesjacoby authored
79 }
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
80 }
8ff4206 @mjangda v1
mjangda authored
81
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
82 /**
83 * Hook actions in that run on every page-load
84 *
85 * @uses add_action()
86 */
87 private static function add_actions() {
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
88 add_action( 'init', array( __CLASS__, 'init' ) );
8413aff @johnjamesjacoby Uploading:
johnjamesjacoby authored
89 //add_action( 'wp_head', array( __CLASS__, 'wp_head' ) );
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
90 add_action( 'wp_enqueue_scripts', array( __CLASS__, 'enqueue_scripts' ) );
8ff4206 @mjangda v1
mjangda authored
91 add_action( 'wp_ajax_liveblog_insert_entry', array( __CLASS__, 'ajax_insert_entry' ) );
5aee585 @nb Add ajax endpoint for preview
nb authored
92 add_action( 'wp_ajax_liveblog_preview_entry', array( __CLASS__, 'ajax_preview_entry' ) );
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
93 }
8ff4206 @mjangda v1
mjangda authored
94
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
95 /**
96 * Hook filters in that run on every page-load
97 *
98 * @uses add_filter()
99 */
100 private static function add_filters() {
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
101 add_filter( 'template_redirect', array( __CLASS__, 'handle_request' ) );
102 add_filter( 'comment_class', array( __CLASS__, 'add_comment_class' ) );
8ff4206 @mjangda v1
mjangda authored
103 }
104
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
105 /**
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
106 * Hook actions in that run on every admin page-load
107 *
108 * @uses add_action()
109 * @uses is_admin()
110 */
111 private static function add_admin_actions() {
112
113 // Bail if not in admin area
114 if ( ! is_admin() )
115 return;
116
117 add_action( 'add_meta_boxes', array( __CLASS__, 'add_meta_box' ) );
118 add_action( 'save_post', array( __CLASS__, 'save_meta_box' ) );
119 }
120
121 /** Public Methods ********************************************************/
122
123 /**
124 * Liveblog initialization functions.
125 *
126 * This is where Liveblog sets up any additional things it needs to run
127 * inside of WordPress. Where some plugins would register post types or
128 * taxonomies, we modify endpoints and add post type support for Liveblog.
129 *
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
130 * @todo filters for time and interval overrides
131 */
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
132 public static function init() {
133
134 /**
135 * Add a WordPress rewrite-rule enpoint.
136 *
137 * Looks like: /2012/01/01/post-name/liveblog/123456/
138 *
139 * where 123456 is a timestamp
140 */
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
141 add_rewrite_endpoint( self::url_endpoint, EP_PERMALINK );
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
142
143 /**
144 * Add liveblog support to the 'post' post type. This is done here so
145 * we can possibly introduce this to other post types later.
146 */
8ff4206 @mjangda v1
mjangda authored
147 add_post_type_support( 'post', self::key );
148 }
149
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
150 /**
151 * This is where a majority of the magic happens.
152 *
153 * Hooked to template_redirect, this method tries to add anything it can to
154 * the current post output. If nothing needs to be added, we redirect back
155 * to the permalink.
156 *
157 * @return If request has been handled
158 */
159 public static function handle_request() {
160
161 // Bail if not a liveblog post
8ff4206 @mjangda v1
mjangda authored
162 if ( ! self::is_viewing_liveblog_post() )
163 return;
164
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
165 // Set the some useful bits based on the request
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
166 self::$post_id = get_the_ID();
b28b38d @nb Rename the query class to match WP conventions
nb authored
167 self::$entry_query = new WPCOM_Liveblog_Entry_Query( self::$post_id, self::key );
1b8e8d5 @nb Streamline logic for getting recent entries
nb authored
168
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
169 /**
170 * If this is the first time this page is being requested, we know we
171 * need to add all of the liveblog updates to the top of the post.
172 *
173 * Once we've added them, bail.
174 */
1b8e8d5 @nb Streamline logic for getting recent entries
nb authored
175 if ( self::is_initial_page_request() ) {
8ff4206 @mjangda v1
mjangda authored
176 add_filter( 'the_content', array( __CLASS__, 'add_liveblog_to_content' ) );
177 return;
178 }
179
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
180 /**
181 * If this is an ajax request to update the entries, call the method
182 * responsible for updating entries between now and the last time they
183 * were successfully returned.
8413aff @johnjamesjacoby Uploading:
johnjamesjacoby authored
184 *
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
185 * Once we've added them, bail.
186 */
1b8e8d5 @nb Streamline logic for getting recent entries
nb authored
187 if ( self::is_entries_ajax_request() ) {
7c3d06f @nb Rename the entries AJAX handler to match the other
nb authored
188 self::ajax_entries_between();
1b8e8d5 @nb Streamline logic for getting recent entries
nb authored
189 return;
190 }
191
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
192 // We haven't needed to do anything, so redirect back to the permalink
1b8e8d5 @nb Streamline logic for getting recent entries
nb authored
193 wp_safe_redirect( get_permalink() );
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
194 exit();
8ff4206 @mjangda v1
mjangda authored
195 }
1b8e8d5 @nb Streamline logic for getting recent entries
nb authored
196
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
197 /**
198 * Look for any new Liveblog entries, and return them via JSON
199 */
200 public static function ajax_entries_between() {
201
202 // Set some defaults
558008c @nb Use the same current timestamp at all places
nb authored
203 $current_timestamp = time();
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
204 $latest_timestamp = 0;
205 $entries_for_json = array();
558008c @nb Use the same current timestamp at all places
nb authored
206
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
207 // Look for entry boundaries
1b8e8d5 @nb Streamline logic for getting recent entries
nb authored
208 list( $start_timestamp, $end_timestamp ) = self::get_timestamps_from_query();
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
209
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
210 // Bail if there is no end timestamp
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
211 if ( empty( $end_timestamp ) ) {
1b8e8d5 @nb Streamline logic for getting recent entries
nb authored
212 wp_safe_redirect( get_permalink() );
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
213 die();
1b8e8d5 @nb Streamline logic for getting recent entries
nb authored
214 }
215
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
216 // Do not cache if it's too soon
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
217 if ( $end_timestamp > $current_timestamp )
6c66757 @nb Do not let the client cache future requests
nb authored
218 self::$do_not_cache_response = true;
219
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
220 // Get liveblog entries within the start and end boundaries
b28b38d @nb Rename the query class to match WP conventions
nb authored
221 $entries = self::$entry_query->get_between_timestamps( $start_timestamp, $end_timestamp );
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
222 if ( empty( $entries ) ) {
223 self::json_return( array(
224 'entries' => array(),
225 'current_timestamp' => $current_timestamp,
226 'latest_timestamp' => null
227 ) );
228 }
d79a82d @nb Gather common entry functionality in a new class
nb authored
229
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
230 /**
231 * Loop through each liveblog entry, set the most recent timestamp, and
232 * put the JSON data for each entry into a neat little array.
233 */
1b8e8d5 @nb Streamline logic for getting recent entries
nb authored
234 foreach( $entries as $entry ) {
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
235 $latest_timestamp = max( $latest_timestamp, $entry->get_timestamp() );
d79a82d @nb Gather common entry functionality in a new class
nb authored
236 $entries_for_json[] = $entry->for_json();
1b8e8d5 @nb Streamline logic for getting recent entries
nb authored
237 }
238
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
239 // Setup our data to return via JSON
1b8e8d5 @nb Streamline logic for getting recent entries
nb authored
240 $result_for_json = array(
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
241 'entries' => $entries_for_json,
558008c @nb Use the same current timestamp at all places
nb authored
242 'current_timestamp' => $current_timestamp,
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
243 'latest_timestamp' => $latest_timestamp,
1b8e8d5 @nb Streamline logic for getting recent entries
nb authored
244 );
245
e977561 @nb Get rid of extra json_return() arguments
nb authored
246 self::json_return( $result_for_json );
1b8e8d5 @nb Streamline logic for getting recent entries
nb authored
247 }
248
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
249 /** Private _is_ Methods **************************************************/
250
251 /**
252 * Are we viewing a liveblog post?
253 *
254 * @uses is_single()
255 * @uses is_liveblog_post()
256 * @return bool
257 */
258 private static function is_viewing_liveblog_post() {
259 return (bool) ( is_single() && self::is_liveblog_post() );
1b8e8d5 @nb Streamline logic for getting recent entries
nb authored
260 }
261
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
262 /**
263 * Is this the initial page request?
264 *
265 * Note that we do not use get_query_var() - it returns '' for all requests,
266 * which is valid for /post-name/liveblog/
267 *
268 * @global WP_Query $wp_query
269 * @return bool
270 */
271 private static function is_initial_page_request() {
8ff4206 @mjangda v1
mjangda authored
272 global $wp_query;
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
273
274 return (bool) ! isset( $wp_query->query_vars[self::key] );
8ff4206 @mjangda v1
mjangda authored
275 }
1b8e8d5 @nb Streamline logic for getting recent entries
nb authored
276
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
277 /**
278 * Is this an ajax request for the entries?
279 *
280 * @uses get_query_var() to check for the url_endpoint
281 * @return bool
282 */
283 private static function is_entries_ajax_request() {
284 return (bool) get_query_var( self::url_endpoint );
285 }
1b8e8d5 @nb Streamline logic for getting recent entries
nb authored
286
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
287 /**
288 * Is a given post_id a liveblog enabled post?
289 *
290 * @global WP_Post $post
291 * @param int $post_id
292 * @return bool
293 */
294 private static function is_liveblog_post( $post_id = null ) {
295 if ( empty( $post_id ) ) {
296 global $post;
297 $post_id = $post->ID;
298 }
299
300 return (bool) get_post_meta( $post_id, self::key, true );
1b8e8d5 @nb Streamline logic for getting recent entries
nb authored
301 }
302
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
303 /**
304 * Get timestamps from the current WP_Query
305 *
306 * Ensures that two timestamps exist, and returns a properly formatted empty
307 * array if not.
308 *
309 * @return array
310 */
311 private static function get_timestamps_from_query() {
312
313 // Look for timestamps and bail if none
314 $stamps = get_query_var( self::url_endpoint );
315 if ( empty( $stamps ) )
1b8e8d5 @nb Streamline logic for getting recent entries
nb authored
316 return array( false, false );
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
317
318 // Get timestamps from the query variable
319 $timestamps = explode( '/', $stamps );
320
321 // Bail if there are not 2 timestamps
322 if ( 2 !== count( $timestamps ) )
323 return array( false, false );
324
325 // Return integer timestamps in an array
326 return array_map( 'intval', $timestamps );
1b8e8d5 @nb Streamline logic for getting recent entries
nb authored
327 }
328
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
329 /**
330 * Inserts, updates, or deletes a liveblog entry
331 *
332 * @todo break update/delete off into separate methods
333 */
334 public static function ajax_insert_entry() {
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
335
336 // Capability and Intention Checks
b58c3a0 @nb Remove leading underscores from function names
nb authored
337 self::ajax_current_user_can_edit_liveblog();
338 self::ajax_check_nonce();
8ff4206 @mjangda v1
mjangda authored
339
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
340 // Check POST data
ec017c4 @nb Kses posts content closer to the place we use it
nb authored
341 $post_id = isset( $_POST['post_id'] ) ? intval( $_POST['post_id'] ) : 0;
342 $replaces_comment_id = isset( $_POST['replaces'] ) ? intval( $_POST['replaces'] ) : 0;
343 $entry_content = isset( $_POST['entry_content'] ) ? $_POST['entry_content'] : '';
8ff4206 @mjangda v1
mjangda authored
344
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
345 if ( empty( $post_id ) )
346 self::send_error( __( 'Sorry, that post is not accepting Liveblog entries.', 'liveblog' ) );
8ff4206 @mjangda v1
mjangda authored
347
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
348 // Get the current user
8ff4206 @mjangda v1
mjangda authored
349 $user = wp_get_current_user();
350
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
351 // Insert new comment
352 $new_comment_id = wp_insert_comment( array(
353 'comment_post_ID' => $post_id,
ec017c4 @nb Kses posts content closer to the place we use it
nb authored
354 'comment_content' => wp_filter_post_kses( $entry_content ),
f157181 @johnjamesjacoby Comment Status:
johnjamesjacoby authored
355 'comment_approved' => self::key,
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
356 'comment_type' => self::key,
357 'user_id' => $user->ID,
8ff4206 @mjangda v1
mjangda authored
358
359 // TODO: Should we be adding this or generating dynamically?
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
360 'comment_author' => $user->display_name,
8ff4206 @mjangda v1
mjangda authored
361 'comment_author_email' => $user->user_email,
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
362 'comment_author_url' => $user->user_url,
363
8ff4206 @mjangda v1
mjangda authored
364 // Borrowed from core as wp_insert_comment does not generate them
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
365 'comment_author_IP' => preg_replace( '/[^0-9a-fA-F:., ]/', '',$_SERVER['REMOTE_ADDR'] ),
366 'comment_agent' => substr( $_SERVER['HTTP_USER_AGENT'], 0, 254 ),
367 ) );
8ff4206 @mjangda v1
mjangda authored
368
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
369 // Bail if comment could not be saved
370 if ( empty( $new_comment_id ) || is_wp_error( $new_comment_id ) )
371 self::send_error( __( 'Error posting entry', 'liveblog' ) );
8ff4206 @mjangda v1
mjangda authored
372
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
373 // Are we replacing an existing comment?
374 if ( !empty( $replaces_comment_id ) ) {
a2f3ce4 @nb Show inserted entry immediately
nb authored
375
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
376 //
a2723d4 @nb Commit entry modifications
nb authored
377 add_comment_meta( $new_comment_id, WPCOM_Liveblog_Entry::replaces_meta_key, $replaces_comment_id );
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
378
379 // Update an existing comment
380 if ( !empty( $entry_content ) ) {
381 wp_update_comment( array(
382 'comment_ID' => $replaces_comment_id,
ec017c4 @nb Kses posts content closer to the place we use it
nb authored
383 'comment_content' => wp_filter_post_kses( $entry_content ),
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
384 ) );
385
386 // Delete this comment
387 } else {
a2723d4 @nb Commit entry modifications
nb authored
388 wp_delete_comment( $replaces_comment_id );
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
389 }
a2723d4 @nb Commit entry modifications
nb authored
390 }
391
a2f3ce4 @nb Show inserted entry immediately
nb authored
392 $entry = WPCOM_Liveblog_Entry::from_comment( get_comment( $new_comment_id ) );
393
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
394 // Do not send latest_timestamp. If we send it the client won't get
395 // older entries. Since we send only the new one, we don't know if there
396 // weren't any entries in between.
397 self::json_return( array(
398 'entries' => array( $entry->for_json() ),
399 'current_timestamp' => time(),
400 'latest_timestamp' => null
401 ) );
8ff4206 @mjangda v1
mjangda authored
402 }
403
5aee585 @nb Add ajax endpoint for preview
nb authored
404 function ajax_preview_entry() {
405 self::ajax_current_user_can_edit_liveblog();
406 self::ajax_check_nonce();
407 $entry_content = isset( $_REQUEST['entry_content'] ) ? $_REQUEST['entry_content'] : '';
408 $entry_content = wp_filter_post_kses( $entry_content );
409 $entry_content = WPCOM_Liveblog_Entry::render_content( $entry_content );
410 self::json_return( array( 'html' => $entry_content ) );
411 }
412
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
413 /** Comment Methods *******************************************************/
8ff4206 @mjangda v1
mjangda authored
414
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
415 /**
416 * Add a liveblog class to each comment, so they can be styled
417 *
418 * @param array $classes
419 * @return string
420 */
421 public static function add_comment_class( $classes ) {
8ff4206 @mjangda v1
mjangda authored
422 $classes[] = 'liveblog-entry';
423 return $classes;
424 }
425
f157181 @johnjamesjacoby Comment Status:
johnjamesjacoby authored
426
427 /**
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
428 * Enqueue the necessary CSS and JS that liveblog needs to function.
429 *
430 * @return If not a liveblog post
431 */
432 public static function enqueue_scripts() {
433
8ff4206 @mjangda v1
mjangda authored
434 if ( ! self::is_viewing_liveblog_post() )
435 return;
436
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
437 wp_enqueue_style( self::key, plugins_url( 'css/liveblog.css', __FILE__ ) );
db742c8 @nb Highlight new posts
nb authored
438 wp_enqueue_script( self::key, plugins_url( 'js/liveblog.js', __FILE__ ), array( 'jquery', 'jquery-color' ), self::version, true );
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
439
8413aff @johnjamesjacoby Uploading:
johnjamesjacoby authored
440 if ( self::current_user_can_edit_liveblog() ) {
a456b55 @nb Add Preview interface
nb authored
441 wp_enqueue_script( 'liveblog-publisher', plugins_url( 'js/liveblog-publisher.js', __FILE__ ), array( self::key, 'jquery-ui-tabs' ), self::version, true );
8413aff @johnjamesjacoby Uploading:
johnjamesjacoby authored
442 wp_enqueue_script( 'liveblog-plupload', plugins_url( 'js/plupload.js', __FILE__ ), array( 'wp-plupload', 'jquery' ) );
c65e58f @nb Make the function name a verb
nb authored
443 self::add_default_plupload_settings();
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
444 }
8ff4206 @mjangda v1
mjangda authored
445
c0c3085 @nb Add spinner for inserting an entry
nb authored
446 if ( wp_script_is( 'jquery.spin', 'registered' ) ) {
447 wp_enqueue_script( 'jquery.spin' );
448 } else {
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
449 wp_enqueue_script( 'spin', plugins_url( 'js/spin.js', __FILE__ ), false, '1.2.4' );
450 wp_enqueue_script( 'jquery.spin', plugins_url( 'js/jquery.spin.js', __FILE__ ), array( 'jquery', 'spin' ) );
c0c3085 @nb Add spinner for inserting an entry
nb authored
451 }
452
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
453 wp_localize_script( self::key, 'liveblog_settings',
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
454 apply_filters( 'liveblog_settings', array(
455 'permalink' => get_permalink(),
456 'post_id' => get_the_ID(),
8ff4206 @mjangda v1
mjangda authored
457
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
458 'key' => self::key,
459 'nonce_key' => self::nonce_key,
460 'latest_entry_timestamp' => self::$entry_query->get_latest_timestamp(),
8ff4206 @mjangda v1
mjangda authored
461
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
462 'refresh_interval' => self::refresh_interval,
ed1991c @nb Shut the auto-update only on consecutive failures
nb authored
463 'max_consecutive_retries'=> self::max_consecutive_retries,
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
464 'delay_threshold' => self::delay_threshold,
465 'delay_multiplier' => self::delay_multiplier,
8ff4206 @mjangda v1
mjangda authored
466
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
467 'ajaxurl' => admin_url( 'admin-ajax.php' ),
468 'entriesurl' => self::get_entries_endpoint_url(),
469
470 // i18n
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
471 'update_nag_singular' => __( '%d new update', 'liveblog' ),
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
472 'update_nag_plural' => __( '%d new updates', 'liveblog' ),
28802ff @nb Delete entry functionality
nb authored
473 'delete_confirmation' => __( 'Do you really want do delete this entry? There is no way back.', 'liveblog' ),
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
474 ) )
475 );
8ff4206 @mjangda v1
mjangda authored
476 }
477
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
478 /**
8413aff @johnjamesjacoby Uploading:
johnjamesjacoby authored
479 * Sets up some default Plupload settings so we can upload meda theme-side
480 *
481 * @global type $wp_scripts
482 */
c65e58f @nb Make the function name a verb
nb authored
483 private static function add_default_plupload_settings() {
8413aff @johnjamesjacoby Uploading:
johnjamesjacoby authored
484 global $wp_scripts;
485
486 $defaults = array(
487 'runtimes' => 'html5,silverlight,flash,html4',
488 'file_data_name' => 'async-upload',
489 'multiple_queues' => true,
490 'max_file_size' => self::max_upload_size() . 'b',
491 'url' => admin_url( 'admin-ajax.php', 'relative' ),
492 'flash_swf_url' => includes_url( 'js/plupload/plupload.flash.swf' ),
493 'silverlight_xap_url' => includes_url( 'js/plupload/plupload.silverlight.xap' ),
494 'filters' => array( array( 'title' => __( 'Allowed Files' ), 'extensions' => '*') ),
495 'multipart' => true,
496 'urlstream_upload' => true,
497 'multipart_params' => array(
498 'action' => 'upload-attachment',
499 '_wpnonce' => wp_create_nonce( 'media-form' )
500 )
501 );
502
503 $settings = array(
504 'defaults' => $defaults,
505 'browser' => array(
506 'mobile' => wp_is_mobile(),
507 'supported' => _device_can_upload(),
508 )
509 );
510
511 $script = 'var _wpPluploadSettings = ' . json_encode( $settings ) . ';';
512 $data = $wp_scripts->get_data( 'wp-plupload', 'data' );
513
514 if ( ! empty( $data ) )
515 $script = "$data\n$script";
516
517 $wp_scripts->add_data( 'wp-plupload', 'data', $script );
518 }
519
520 /**
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
521 * Get the URL of a specific liveblog entry.
522 *
523 * @return string
524 */
525 private static function get_entries_endpoint_url() {
526 return trailingslashit( get_permalink( self::$post_id ) . self::url_endpoint );
527 }
cb778e4 @mjangda Load initial entries server-side rather than via AJAX for SEO benefit
mjangda authored
528
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
529 /** Display Methods *******************************************************/
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
530
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
531 /**
532 * Filter the_content and add the liveblog theme-side UI above the normal
533 * content area.
534 *
535 * @param string $content
536 * @return string
537 */
538 public static function add_liveblog_to_content( $content ) {
cb778e4 @mjangda Load initial entries server-side rather than via AJAX for SEO benefit
mjangda authored
539
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
540 $liveblog_output = '<div id="liveblog-container" class="'. self::$post_id .'">';
541 $liveblog_output .= self::get_editor_output();
542 $liveblog_output .= '<div id="liveblog-update-spinner"></div>';
543 $liveblog_output .= self::get_all_entry_output();
ba2c2ae @mjangda Switch around ids with classes just to be future-safe. Add a new wrap…
mjangda authored
544 $liveblog_output .= '</div>';
8ff4206 @mjangda v1
mjangda authored
545
7205206 @nb Put the post contents before the liveblog
nb authored
546 return $content . $liveblog_output;
8ff4206 @mjangda v1
mjangda authored
547 }
548
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
549 /**
550 * Return the posting area for the end-user to liveblog from
551 *
552 * @return string
553 */
554 private static function get_editor_output() {
b58c3a0 @nb Remove leading underscores from function names
nb authored
555 if ( ! self::current_user_can_edit_liveblog() )
8ff4206 @mjangda v1
mjangda authored
556 return;
557
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
558 // Get the template part
559 return self::get_template_part( 'liveblog-form.php' );
8ff4206 @mjangda v1
mjangda authored
560 }
561
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
562 /**
563 * Get all the liveblog entries for this post
564 */
565 private static function get_all_entry_output() {
8413aff @johnjamesjacoby Uploading:
johnjamesjacoby authored
566
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
567 // Get liveblog entries
568 $entries = (array) self::$entry_query->get_all( array( 'order' => 'ASC' ) );
8ff4206 @mjangda v1
mjangda authored
569
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
570 // Get the template part
571 return self::get_template_part( 'liveblog-loop.php', compact( 'entries' ) );
572 }
573
574 /**
575 * Get the template part in an output buffer and return it
576 *
577 * @param string $template_name
578 * @param array $template_variables
579 *
580 * @todo Rudementary part/child theme file_exists() checks
581 */
582 public static function get_template_part( $template_name, $template_variables = array() ) {
583 ob_start();
584 extract( $template_variables );
585 include( dirname( __FILE__ ) . '/templates/' . $template_name );
586 return ob_get_clean();
8ff4206 @mjangda v1
mjangda authored
587 }
8413aff @johnjamesjacoby Uploading:
johnjamesjacoby authored
588
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
589 /** Admin Methods *********************************************************/
590
591 /**
592 * Register the metabox with the supporting post-type
593 *
594 * @param string $post_type
595 */
596 public static function add_meta_box( $post_type ) {
597
598 // Bail if not supported
599 if ( ! post_type_supports( $post_type, self::key ) )
600 return;
8ff4206 @mjangda v1
mjangda authored
601
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
602 add_meta_box( self::key, __( 'Liveblog', 'liveblog' ), array( __CLASS__, 'display_meta_box' ) );
8ff4206 @mjangda v1
mjangda authored
603 }
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
604
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
605 /**
606 * Output the metabox
607 *
608 * @param WP_Post $post
609 */
610 public static function display_meta_box( $post ) {
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
611 ?>
612
8ff4206 @mjangda v1
mjangda authored
613 <label>
614 <input type="checkbox" name="is-liveblog" id="is-liveblog" value="1" <?php checked( self::is_liveblog_post( $post->ID ) ); ?> />
615 <?php esc_html_e( 'This is a liveblog', 'liveblog' ); ?>
616 </label>
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
617
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
618 <?php
619 wp_nonce_field( self::nonce_key, self::nonce_key, false );
8ff4206 @mjangda v1
mjangda authored
620 }
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
621
622 /**
623 * Save the metabox when the post is saved
624 *
625 * @param type $post_id
626 * @return type
627 */
628 public function save_meta_box( $post_id ) {
629
630 // Bail if no liveblog nonce
631 if ( empty( $_POST[self::nonce_key] ) || ! wp_verify_nonce( $_POST[self::nonce_key], self::nonce_key ) )
8ff4206 @mjangda v1
mjangda authored
632 return;
633
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
634 // Update liveblog beta
635 if ( ! empty( $_POST['is-liveblog'] ) )
8ff4206 @mjangda v1
mjangda authored
636 update_post_meta( $post_id, self::key, 1 );
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
637
638 // Delete liveblog meta
8ff4206 @mjangda v1
mjangda authored
639 else
640 delete_post_meta( $post_id, self::key );
641 }
2ba7f86 @nb Remove trailing whitespace
nb authored
642
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
643 /** Error Methods *********************************************************/
644
645 /**
646 * Can the current user edit liveblog data (non-ajax)
647 *
648 * @return bool
649 */
650 public static function current_user_can_edit_liveblog() {
651 return (bool) current_user_can( apply_filters( 'liveblog_edit_cap', self::edit_cap ) );
8ff4206 @mjangda v1
mjangda authored
652 }
653
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
654 /**
655 * Can the current user edit liveblog data (ajax)
656 *
657 * Sends an error if not
658 */
659 public static function ajax_current_user_can_edit_liveblog() {
b58c3a0 @nb Remove leading underscores from function names
nb authored
660 if ( ! self::current_user_can_edit_liveblog() ) {
d4aa5ad @nb Use double quotes instead of escaping the apostrophe
nb authored
661 self::send_error( __( "Cheatin', uh?", 'liveblog' ) );
8ff4206 @mjangda v1
mjangda authored
662 }
663 }
664
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
665 /**
666 * Check for valid intention, and send an error if there is none
667 *
668 * @param string $action
669 */
670 public static function ajax_check_nonce( $action = self::nonce_key ) {
8ff4206 @mjangda v1
mjangda authored
671 if ( ! isset( $_REQUEST[ self::nonce_key ] ) || ! wp_verify_nonce( $_REQUEST[ self::nonce_key ], $action ) ) {
d81e042 @nb Extract sending errors in its own method
nb authored
672 self::send_error( __( 'Sorry, we could not authenticate you.', 'liveblog' ) );
8ff4206 @mjangda v1
mjangda authored
673 }
674 }
675
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
676 /** Feedback **************************************************************/
677
678 /**
679 * Send an error message
680 * @param type $message
681 */
682 private static function send_error( $message ) {
683 self::status_header_with_message( 500, $message );
684 exit();
685 }
686
687 /**
688 * Encode some data and echo it (possibly without cached headers)
689 *
690 * @param array $data
691 */
692 private static function json_return( $data ) {
20c5b02 @nb Get rid of the intermediate layer completely
nb authored
693 $json_data = json_encode( $data );
8ff4206 @mjangda v1
mjangda authored
694
f2908df @nb Get rid if return functionality in json_return()
nb authored
695 header( 'Content-Type: application/json' );
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
696 if ( self::$do_not_cache_response )
6c66757 @nb Do not let the client cache future requests
nb authored
697 nocache_headers();
20c5b02 @nb Get rid of the intermediate layer completely
nb authored
698
699 echo $json_data;
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
700 exit();
d81e042 @nb Extract sending errors in its own method
nb authored
701 }
702
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
703 /**
704 * Modify the header and description in the global array
705 *
706 * @global array $wp_header_to_desc
707 * @param int $status
708 * @param string $message
709 */
710 private static function status_header_with_message( $status, $message ) {
2532397 @nb Send HTTP errors instead of the success flag
nb authored
711 global $wp_header_to_desc;
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
712
713 $status = absint( $status );
714 $official_message = isset( $wp_header_to_desc[$status] ) ? $wp_header_to_desc[$status] : '';
2532397 @nb Send HTTP errors instead of the success flag
nb authored
715 $wp_header_to_desc[$status] = $message;
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
716
2532397 @nb Send HTTP errors instead of the success flag
nb authored
717 status_header( $status );
cd6d574 @johnjamesjacoby * Code clean up.
johnjamesjacoby authored
718
2532397 @nb Send HTTP errors instead of the success flag
nb authored
719 $wp_header_to_desc[$status] = $official_message;
720 }
8413aff @johnjamesjacoby Uploading:
johnjamesjacoby authored
721
722 /** Plupload Helpers ******************************************************/
723
724 /**
725 * Convert hours to bytes
726 *
727 * @param unknown_type $size
728 * @return unknown
729 */
730 private static function convert_hr_to_bytes( $size ) {
731 $size = strtolower( $size );
732 $bytes = (int) $size;
733
734 if ( strpos( $size, 'k' ) !== false )
735 $bytes = intval( $size ) * 1024;
736 elseif ( strpos( $size, 'm' ) !== false )
737 $bytes = intval( $size ) * 1024 * 1024;
738 elseif ( strpos( $size, 'g' ) !== false )
739 $bytes = intval( $size ) * 1024 * 1024 * 1024;
740
741 return $bytes;
742 }
743
744 /**
745 * Convert bytes to hour
746 *
747 * @param string $bytes
748 * @return string
749 */
750 private static function convert_bytes_to_hr( $bytes ) {
751 $units = array( 0 => 'B', 1 => 'kB', 2 => 'MB', 3 => 'GB' );
752 $log = log( $bytes, 1024 );
753 $power = (int) $log;
754 $size = pow( 1024, $log - $power );
755
756 return $size . $units[$power];
757 }
758
759 /**
760 * Get the maximum upload file size
761 *
762 * @see wp_max_upload_size()
763 * @return string
764 */
765 private static function max_upload_size() {
766 $u_bytes = self::convert_hr_to_bytes( ini_get( 'upload_max_filesize' ) );
767 $p_bytes = self::convert_hr_to_bytes( ini_get( 'post_max_size' ) );
768 $bytes = apply_filters( 'upload_size_limit', min( $u_bytes, $p_bytes ), $u_bytes, $p_bytes );
769
770 return $bytes;
a6429c8 @nb Remove trailing whitespace
nb authored
771 }
8ff4206 @mjangda v1
mjangda authored
772 }
773
0a0ca28 @johnjamesjacoby Weekend updates:
johnjamesjacoby authored
774 /**
775 * Load the one true WPCOM_Liveblog instance
776 *
777 * Loaded late on the 'plugins_loaded' hook to allow any other plugin to sneak
778 * in ahead of it, to add actions, filters, etc...
779 *
780 * @uses WPCOM_Liveblog::load()
781 */
782 function wpcom_liveblog_load() {
783 WPCOM_Liveblog::load();
784 }
785 add_action( 'plugins_loaded', 'wpcom_liveblog_load', 999 );
786
8ff4206 @mjangda v1
mjangda authored
787 endif;
Something went wrong with that request. Please try again.