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