Skip to content
This repository
Newer
Older
100644 838 lines (696 sloc) 27.064 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.
aa5c82c3 »
2012-12-13 Bump 1.2
7 * Version: 1.2
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
aa5c82c3 »
2012-12-13 Bump 1.2
37 const version = '1.2';
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
1d7244f8 »
2012-09-20 Increase the default refresh interval
44 const refresh_interval = 10; // how often should we refresh
7af87b5d »
2012-12-28 Use shorter refresh interval when debugging
45 const debug_refresh_interval = 2; // how often we refresh in development mode
ed1991cf »
2012-08-15 Shut the auto-update only on consecutive failures
46 const max_consecutive_retries = 100; // max number of failed tries before polling is disabled
47 const delay_threshold = 5; // how many failed tries after which we should increase the refresh interval
48 const delay_multiplier = 2; // by how much should we inscrease the refresh interval
8ff4206e »
2012-06-05 v1
49
0a0ca28b »
2012-07-30 Weekend updates:
50 /** Variables *************************************************************/
51
52 private static $post_id = null;
53 private static $entry_query = null;
54 private static $do_not_cache_response = false;
1b8e8d5e »
2012-07-02 Streamline logic for getting recent entries
55
0a0ca28b »
2012-07-30 Weekend updates:
56 /** Load Methods **********************************************************/
57
58 /**
59 * @uses add_action() to hook methods into WordPress actions
60 * @uses add_filter() to hook methods into WordPress filters
61 */
62 public static function load() {
e5351e53 »
2012-09-06 load_plugin_textdomain so the plugin can be translated.
63 load_plugin_textdomain( 'liveblog', false, dirname( plugin_basename( __FILE__ ) ) . '/languages/' );
64
0a0ca28b »
2012-07-30 Weekend updates:
65 self::includes();
66 self::add_actions();
67 self::add_filters();
68 self::add_admin_actions();
186ea96e »
2012-12-27 Add an image URL handler
69 self::register_embed_handlers();
0a0ca28b »
2012-07-30 Weekend updates:
70 }
71
72 /**
73 * Include the necessary files
74 */
75 private static function includes() {
76 require( dirname( __FILE__ ) . '/classes/class-wpcom-liveblog-entry.php' );
77 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…
78
79 // Manually include ms.php theme-side in multisite environments because
80 // we need its filesize and available space functions.
81 if ( ! is_admin() && is_multisite() ) {
8f5fb3cc »
2012-08-14 Remove preceding slash. ABSPATH is already slashed for us.
82 require_once( ABSPATH . 'wp-admin/includes/ms.php' );
e691fe35 »
2012-08-14 Include ms.php theme-side for its filesize and available space functi…
83 }
02b5fdb7 »
2012-09-01 Add convertor from extend read me to github readme
84
85 if ( defined( 'WP_CLI' ) && WP_CLI ) {
86 require( dirname( __FILE__ ) . '/classes/class-wpcom-liveblog-wp-cli.php' );
87 }
0a0ca28b »
2012-07-30 Weekend updates:
88 }
8ff4206e »
2012-06-05 v1
89
0a0ca28b »
2012-07-30 Weekend updates:
90 /**
91 * Hook actions in that run on every page-load
92 *
93 * @uses add_action()
94 */
95 private static function add_actions() {
cd6d5741 »
2012-07-26 * Code clean up.
96 add_action( 'init', array( __CLASS__, 'init' ) );
7994c3e2 »
2012-09-18 Re-add the rewrite rules on permalink change
97 add_action( 'init', array( __CLASS__, 'add_rewrite_rules' ) );
98 add_action( 'permalink_structure_changed', array( __CLASS__, 'add_rewrite_rules' ) );
4221823e »
2012-09-18 Flush the rewrite rules later
99 // flush the rewrite rules a lot later so that we don't interfere with other plugins using rewrite rules
100 add_action( 'init', array( __CLASS__, 'flush_rewrite_rules' ), 1000 );
cd6d5741 »
2012-07-26 * Code clean up.
101 add_action( 'wp_enqueue_scripts', array( __CLASS__, 'enqueue_scripts' ) );
ea5a8a60 »
2012-12-18 Introduce archiving
102 add_action( 'admin_enqueue_scripts', array( __CLASS__, 'admin_enqueue_scripts' ) );
103 add_action( 'wp_ajax_set_liveblog_state_for_post', array( __CLASS__, 'admin_ajax_set_liveblog_state_for_post' ) );
0a0ca28b »
2012-07-30 Weekend updates:
104 }
8ff4206e »
2012-06-05 v1
105
0a0ca28b »
2012-07-30 Weekend updates:
106 /**
107 * Hook filters in that run on every page-load
108 *
109 * @uses add_filter()
110 */
111 private static function add_filters() {
cd6d5741 »
2012-07-26 * Code clean up.
112 add_filter( 'template_redirect', array( __CLASS__, 'handle_request' ) );
c3dc8bd0 »
2012-09-21 Only apply liveblog-entry CSS class to liveblog comment types.
113 add_filter( 'comment_class', array( __CLASS__, 'add_comment_class' ), 10, 3 );
8ff4206e »
2012-06-05 v1
114 }
115
cd6d5741 »
2012-07-26 * Code clean up.
116 /**
0a0ca28b »
2012-07-30 Weekend updates:
117 * Hook actions in that run on every admin page-load
118 *
119 * @uses add_action()
120 * @uses is_admin()
121 */
122 private static function add_admin_actions() {
123
124 // Bail if not in admin area
125 if ( ! is_admin() )
126 return;
127
128 add_action( 'add_meta_boxes', array( __CLASS__, 'add_meta_box' ) );
129 }
130
186ea96e »
2012-12-27 Add an image URL handler
131 private static function register_embed_handlers() {
132 // register it to run later, because the regex is pretty general and we don't want it to prevent more specific handlers from running
133 wp_embed_register_handler( 'liveblog_image', '/\.(png|jpe?g|gif)(\?.*)?$/', array( 'WPCOM_Liveblog', 'image_embed_handler' ), 99 );
134 }
135
0a0ca28b »
2012-07-30 Weekend updates:
136 /** Public Methods ********************************************************/
137
138 /**
139 * Liveblog initialization functions.
140 *
141 * This is where Liveblog sets up any additional things it needs to run
142 * inside of WordPress. Where some plugins would register post types or
143 * taxonomies, we modify endpoints and add post type support for Liveblog.
cd6d5741 »
2012-07-26 * Code clean up.
144 */
0a0ca28b »
2012-07-30 Weekend updates:
145 public static function init() {
146 /**
147 * Add liveblog support to the 'post' post type. This is done here so
148 * we can possibly introduce this to other post types later.
149 */
8ff4206e »
2012-06-05 v1
150 add_post_type_support( 'post', self::key );
8314495d »
2012-10-23 Add an action after liveblog's init
151 do_action( 'after_liveblog_init' );
8ff4206e »
2012-06-05 v1
152 }
153
7994c3e2 »
2012-09-18 Re-add the rewrite rules on permalink change
154 public function add_rewrite_rules() {
1d5d7f9c »
2012-09-01 Flush the rewrite rules on rules update
155 add_rewrite_endpoint( self::url_endpoint, EP_PERMALINK );
7994c3e2 »
2012-09-18 Re-add the rewrite rules on permalink change
156 }
1d5d7f9c »
2012-09-01 Flush the rewrite rules on rules update
157
7994c3e2 »
2012-09-18 Re-add the rewrite rules on permalink change
158 public static function flush_rewrite_rules() {
1d5d7f9c »
2012-09-01 Flush the rewrite rules on rules update
159 if ( get_option( 'liveblog_rewrites_version' ) != self::rewrites_version ) {
160 flush_rewrite_rules();
161 update_option( 'liveblog_rewrites_version', self::rewrites_version );
162 }
163 }
164
0a0ca28b »
2012-07-30 Weekend updates:
165 /**
166 * This is where a majority of the magic happens.
167 *
168 * Hooked to template_redirect, this method tries to add anything it can to
169 * the current post output. If nothing needs to be added, we redirect back
170 * to the permalink.
171 *
172 * @return If request has been handled
173 */
174 public static function handle_request() {
175
8ff4206e »
2012-06-05 v1
176 if ( ! self::is_viewing_liveblog_post() )
177 return;
178
cd6d5741 »
2012-07-26 * Code clean up.
179 self::$post_id = get_the_ID();
b28b38d5 »
2012-07-19 Rename the query class to match WP conventions
180 self::$entry_query = new WPCOM_Liveblog_Entry_Query( self::$post_id, self::key );
1b8e8d5e »
2012-07-02 Streamline logic for getting recent entries
181
4872b2ad »
2012-08-23 Use front-end AJAX URLs for same-origin requests
182 if ( self::is_initial_page_request() )
8ff4206e »
2012-06-05 v1
183 add_filter( 'the_content', array( __CLASS__, 'add_liveblog_to_content' ) );
4872b2ad »
2012-08-23 Use front-end AJAX URLs for same-origin requests
184 else
185 self::handle_ajax_request();
186 }
187
188 private static function handle_ajax_request() {
189
190 $endpoint_suffix = get_query_var( self::url_endpoint );
191
192 if ( !$endpoint_suffix ) {
193 // we redirect, because if somebody accessed <permalink>/liveblog
194 // they probably did that in the URL bar, not via AJAX
195 wp_safe_redirect( get_permalink() );
196 exit();
8ff4206e »
2012-06-05 v1
197 }
2b0244cf »
2012-09-18 Remove trailing whitespace
198 wp_cache_delete( self::key . '_entries_asc_' . self::$post_id, 'liveblog' );
8ff4206e »
2012-06-05 v1
199
4872b2ad »
2012-08-23 Use front-end AJAX URLs for same-origin requests
200 $suffix_to_method = array(
201 '\d+/\d+' => 'ajax_entries_between',
4c7e77ba »
2012-12-26 Consolidate all CRUD AJAX actions
202 'crud' => 'ajax_crud_entry',
4872b2ad »
2012-08-23 Use front-end AJAX URLs for same-origin requests
203 'preview' => 'ajax_preview_entry',
204 );
205
206 $response_method = 'ajax_unknown';
207
208 foreach( $suffix_to_method as $suffix_re => $method ) {
209 if ( preg_match( "%^$suffix_re/?%", $endpoint_suffix ) ) {
210 $response_method = $method;
211 break;
212 }
1b8e8d5e »
2012-07-02 Streamline logic for getting recent entries
213 }
214
4872b2ad »
2012-08-23 Use front-end AJAX URLs for same-origin requests
215 self::$response_method();
216
8ff4206e »
2012-06-05 v1
217 }
1b8e8d5e »
2012-07-02 Streamline logic for getting recent entries
218
0a0ca28b »
2012-07-30 Weekend updates:
219 /**
220 * Look for any new Liveblog entries, and return them via JSON
221 */
222 public static function ajax_entries_between() {
223
224 // Set some defaults
cd6d5741 »
2012-07-26 * Code clean up.
225 $latest_timestamp = 0;
226 $entries_for_json = array();
558008c4 »
2012-07-04 Use the same current timestamp at all places
227
0a0ca28b »
2012-07-30 Weekend updates:
228 // Look for entry boundaries
1b8e8d5e »
2012-07-02 Streamline logic for getting recent entries
229 list( $start_timestamp, $end_timestamp ) = self::get_timestamps_from_query();
cd6d5741 »
2012-07-26 * Code clean up.
230
0a0ca28b »
2012-07-30 Weekend updates:
231 // Bail if there is no end timestamp
cd6d5741 »
2012-07-26 * Code clean up.
232 if ( empty( $end_timestamp ) ) {
70b347ae »
2012-09-06 Add missing textdomain to translated strings
233 self::send_user_error( __( 'A timestamp is missing. Correct URL: <permalink>/liveblog/<from>/</to>/', 'liveblog' ) );
1b8e8d5e »
2012-07-02 Streamline logic for getting recent entries
234 }
235
0a0ca28b »
2012-07-30 Weekend updates:
236 // Do not cache if it's too soon
bd6c841d »
2012-08-21 Use the Date header to get server-side date
237 if ( $end_timestamp > time() )
6c667576 »
2012-07-04 Do not let the client cache future requests
238 self::$do_not_cache_response = true;
239
0a0ca28b »
2012-07-30 Weekend updates:
240 // Get liveblog entries within the start and end boundaries
b28b38d5 »
2012-07-19 Rename the query class to match WP conventions
241 $entries = self::$entry_query->get_between_timestamps( $start_timestamp, $end_timestamp );
0a0ca28b »
2012-07-30 Weekend updates:
242 if ( empty( $entries ) ) {
7e39692c »
2012-09-25 Introduce some new hooks.
243 do_action( 'liveblog_entry_request_empty' );
244
0a0ca28b »
2012-07-30 Weekend updates:
245 self::json_return( array(
246 'entries' => array(),
247 'latest_timestamp' => null
248 ) );
249 }
d79a82d3 »
2012-07-05 Gather common entry functionality in a new class
250
0a0ca28b »
2012-07-30 Weekend updates:
251 /**
252 * Loop through each liveblog entry, set the most recent timestamp, and
253 * put the JSON data for each entry into a neat little array.
254 */
1b8e8d5e »
2012-07-02 Streamline logic for getting recent entries
255 foreach( $entries as $entry ) {
cd6d5741 »
2012-07-26 * Code clean up.
256 $latest_timestamp = max( $latest_timestamp, $entry->get_timestamp() );
d79a82d3 »
2012-07-05 Gather common entry functionality in a new class
257 $entries_for_json[] = $entry->for_json();
1b8e8d5e »
2012-07-02 Streamline logic for getting recent entries
258 }
259
0a0ca28b »
2012-07-30 Weekend updates:
260 // Setup our data to return via JSON
1b8e8d5e »
2012-07-02 Streamline logic for getting recent entries
261 $result_for_json = array(
cd6d5741 »
2012-07-26 * Code clean up.
262 'entries' => $entries_for_json,
263 'latest_timestamp' => $latest_timestamp,
1b8e8d5e »
2012-07-02 Streamline logic for getting recent entries
264 );
265
7e39692c »
2012-09-25 Introduce some new hooks.
266 do_action( 'liveblog_entry_request', $result_for_json );
267
e9775618 »
2012-07-11 Get rid of extra json_return() arguments
268 self::json_return( $result_for_json );
1b8e8d5e »
2012-07-02 Streamline logic for getting recent entries
269 }
270
0a0ca28b »
2012-07-30 Weekend updates:
271 /** Private _is_ Methods **************************************************/
272
273 /**
274 * Are we viewing a liveblog post?
275 *
276 * @uses is_single()
277 * @uses is_liveblog_post()
278 * @return bool
279 */
280 private static function is_viewing_liveblog_post() {
281 return (bool) ( is_single() && self::is_liveblog_post() );
1b8e8d5e »
2012-07-02 Streamline logic for getting recent entries
282 }
283
0a0ca28b »
2012-07-30 Weekend updates:
284 /**
285 * Is this the initial page request?
286 *
287 * Note that we do not use get_query_var() - it returns '' for all requests,
288 * which is valid for /post-name/liveblog/
289 *
290 * @global WP_Query $wp_query
291 * @return bool
292 */
293 private static function is_initial_page_request() {
8ff4206e »
2012-06-05 v1
294 global $wp_query;
0a0ca28b »
2012-07-30 Weekend updates:
295
296 return (bool) ! isset( $wp_query->query_vars[self::key] );
8ff4206e »
2012-06-05 v1
297 }
1b8e8d5e »
2012-07-02 Streamline logic for getting recent entries
298
0a0ca28b »
2012-07-30 Weekend updates:
299 /**
300 * Is this an ajax request for the entries?
301 *
302 * @uses get_query_var() to check for the url_endpoint
303 * @return bool
304 */
305 private static function is_entries_ajax_request() {
306 return (bool) get_query_var( self::url_endpoint );
307 }
1b8e8d5e »
2012-07-02 Streamline logic for getting recent entries
308
0a0ca28b »
2012-07-30 Weekend updates:
309 /**
310 * Is a given post_id a liveblog enabled post?
311 *
312 * @global WP_Post $post
313 * @param int $post_id
314 * @return bool
315 */
316 private static function is_liveblog_post( $post_id = null ) {
ea5a8a60 »
2012-12-18 Introduce archiving
317 $state = self::get_liveblog_state( $post_id );
8c3cdd8d »
2012-12-20 Remove the Disable button
318 return (bool)$state;
ea5a8a60 »
2012-12-18 Introduce archiving
319 }
320
8c3cdd8d »
2012-12-20 Remove the Disable button
321 /**
322 * One of: 'enable', 'archive', false.
323 */
ea5a8a60 »
2012-12-18 Introduce archiving
324 private static function get_liveblog_state( $post_id = null ) {
0a0ca28b »
2012-07-30 Weekend updates:
325 if ( empty( $post_id ) ) {
326 global $post;
327 $post_id = $post->ID;
328 }
ea5a8a60 »
2012-12-18 Introduce archiving
329 $state = get_post_meta( $post_id, self::key, true );
330 // backwards compatibility with older values
331 if ( 1 == $state ) {
332 $state = 'enable';
333 }
334 return $state;
1b8e8d5e »
2012-07-02 Streamline logic for getting recent entries
335 }
336
0a0ca28b »
2012-07-30 Weekend updates:
337 /**
338 * Get timestamps from the current WP_Query
339 *
340 * Ensures that two timestamps exist, and returns a properly formatted empty
341 * array if not.
342 *
343 * @return array
344 */
345 private static function get_timestamps_from_query() {
346
347 // Look for timestamps and bail if none
25be635c »
2012-09-04 Support for non-pretty permalinks
348 $stamps = rtrim( get_query_var( self::url_endpoint ), '/' );
0a0ca28b »
2012-07-30 Weekend updates:
349 if ( empty( $stamps ) )
1b8e8d5e »
2012-07-02 Streamline logic for getting recent entries
350 return array( false, false );
0a0ca28b »
2012-07-30 Weekend updates:
351
352 // Get timestamps from the query variable
353 $timestamps = explode( '/', $stamps );
354
355 // Bail if there are not 2 timestamps
356 if ( 2 !== count( $timestamps ) )
357 return array( false, false );
358
359 // Return integer timestamps in an array
360 return array_map( 'intval', $timestamps );
1b8e8d5e »
2012-07-02 Streamline logic for getting recent entries
361 }
362
4c7e77ba »
2012-12-26 Consolidate all CRUD AJAX actions
363 public static function ajax_crud_entry() {
b58c3a07 »
2012-07-04 Remove leading underscores from function names
364 self::ajax_current_user_can_edit_liveblog();
365 self::ajax_check_nonce();
8ff4206e »
2012-06-05 v1
366
4c7e77ba »
2012-12-26 Consolidate all CRUD AJAX actions
367 $args = array();
8ff4206e »
2012-06-05 v1
368
4c7e77ba »
2012-12-26 Consolidate all CRUD AJAX actions
369 $crud_action = isset( $_POST['crud_action'] ) ? $_POST['crud_action'] : 0;
8ff4206e »
2012-06-05 v1
370
4c7e77ba »
2012-12-26 Consolidate all CRUD AJAX actions
371 if ( !in_array( $crud_action, array( 'insert', 'update', 'delete' ) ) ) {
372 self::send_user_error( sprintf( __( 'Invalid entry crud_action: %s', 'liveblog' ), $crud_action ) );
a2723d4f »
2012-07-23 Commit entry modifications
373 }
374
4c7e77ba »
2012-12-26 Consolidate all CRUD AJAX actions
375 $args['post_id'] = isset( $_POST['post_id'] ) ? intval( $_POST['post_id'] ) : 0;
376 $args['content'] = isset( $_POST['content'] ) ? $_POST['content'] : '';
377 $args['entry_id'] = isset( $_POST['entry_id'] ) ? intval( $_POST['entry_id'] ) : 0;
e92599ed »
2012-12-26 Switch the delete endpoint to use the new method
378
4c7e77ba »
2012-12-26 Consolidate all CRUD AJAX actions
379 $args['user'] = wp_get_current_user();
e92599ed »
2012-12-26 Switch the delete endpoint to use the new method
380
4c7e77ba »
2012-12-26 Consolidate all CRUD AJAX actions
381 $entry = call_user_func( array( 'WPCOM_Liveblog_Entry', $crud_action ), $args );
e92599ed »
2012-12-26 Switch the delete endpoint to use the new method
382
383 if ( is_wp_error( $entry ) ) {
384 self::send_server_error( $entry->get_error_message() );
385 }
386
387 // Do not send latest_timestamp. If we send it the client won't get
388 // older entries. Since we send only the new one, we don't know if there
389 // weren't any entries in between.
390 self::json_return( array(
391 'entries' => array( $entry->for_json() ),
392 'latest_timestamp' => null
393 ) );
394 }
395
5aee5858 »
2012-08-15 Add ajax endpoint for preview
396 function ajax_preview_entry() {
397 $entry_content = isset( $_REQUEST['entry_content'] ) ? $_REQUEST['entry_content'] : '';
54605198 »
2012-10-16 Fix preview which was returning slashed data.
398 $entry_content = stripslashes( wp_filter_post_kses( $entry_content ) );
5aee5858 »
2012-08-15 Add ajax endpoint for preview
399 $entry_content = WPCOM_Liveblog_Entry::render_content( $entry_content );
7e39692c »
2012-09-25 Introduce some new hooks.
400
401 do_action( 'liveblog_preview_entry', $entry_content );
402
5aee5858 »
2012-08-15 Add ajax endpoint for preview
403 self::json_return( array( 'html' => $entry_content ) );
404 }
405
4872b2ad »
2012-08-23 Use front-end AJAX URLs for same-origin requests
406 public function ajax_unknown() {
407 self::send_user_error( __( 'Unknown liveblog action', 'liveblog' ) );
408 }
409
410
0a0ca28b »
2012-07-30 Weekend updates:
411 /** Comment Methods *******************************************************/
8ff4206e »
2012-06-05 v1
412
0a0ca28b »
2012-07-30 Weekend updates:
413 /**
414 * Add a liveblog class to each comment, so they can be styled
415 *
416 * @param array $classes
417 * @return string
418 */
c3dc8bd0 »
2012-09-21 Only apply liveblog-entry CSS class to liveblog comment types.
419 public static function add_comment_class( $classes, $class, $comment_id ) {
420 if ( self::key == get_comment_type( $comment_id ) )
421 $classes[] = 'liveblog-entry';
8ff4206e »
2012-06-05 v1
422 return $classes;
423 }
424
ea5a8a60 »
2012-12-18 Introduce archiving
425 public static function admin_enqueue_scripts() {
426 wp_enqueue_style( self::key, plugins_url( 'css/liveblog-admin.css', __FILE__ ) );
281438dd »
2012-12-20 Use actual information for AJAX action
427 wp_enqueue_script( 'liveblog-admin', plugins_url( 'js/liveblog-admin.js', __FILE__ ) );
428 wp_localize_script( 'liveblog-admin', 'liveblog_admin_settings', array(
429 'nonce_key' => self::nonce_key,
430 'nonce' => wp_create_nonce( self::nonce_key ),
f4e54ce6 »
2012-12-20 Translate JS error messages
431 'error_message_template' => __( 'Error {error-code}: {error-message}', 'liveblog' ),
281438dd »
2012-12-20 Use actual information for AJAX action
432 ) );
ea5a8a60 »
2012-12-18 Introduce archiving
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(),
ea5a8a60 »
2012-12-18 Introduce archiving
465 'state' => self::get_liveblog_state(),
8ff4206e »
2012-06-05 v1
466
cd6d5741 »
2012-07-26 * Code clean up.
467 'key' => self::key,
468 'nonce_key' => self::nonce_key,
469 'latest_entry_timestamp' => self::$entry_query->get_latest_timestamp(),
8ff4206e »
2012-06-05 v1
470
7af87b5d »
2012-12-28 Use shorter refresh interval when debugging
471 'refresh_interval' => WP_DEBUG? self::debug_refresh_interval : self::refresh_interval,
ed1991cf »
2012-08-15 Shut the auto-update only on consecutive failures
472 'max_consecutive_retries'=> self::max_consecutive_retries,
cd6d5741 »
2012-07-26 * Code clean up.
473 'delay_threshold' => self::delay_threshold,
474 'delay_multiplier' => self::delay_multiplier,
8ff4206e »
2012-06-05 v1
475
ea5a8a60 »
2012-12-18 Introduce archiving
476 'endpoint_url' => self::get_entries_endpoint_url(),
cd6d5741 »
2012-07-26 * Code clean up.
477
478 // i18n
0a0ca28b »
2012-07-30 Weekend updates:
479 'update_nag_singular' => __( '%d new update', 'liveblog' ),
cd6d5741 »
2012-07-26 * Code clean up.
480 'update_nag_plural' => __( '%d new updates', 'liveblog' ),
28802ffe »
2012-08-01 Delete entry functionality
481 'delete_confirmation' => __( 'Do you really want do delete this entry? There is no way back.', 'liveblog' ),
f4e54ce6 »
2012-12-20 Translate JS error messages
482 'error_message_template' => __( 'Error {error-code}: {error-message}', 'liveblog' ),
cd6d5741 »
2012-07-26 * Code clean up.
483 ) )
484 );
8ff4206e »
2012-06-05 v1
485 }
486
0a0ca28b »
2012-07-30 Weekend updates:
487 /**
8413aff2 »
2012-07-31 Uploading:
488 * Sets up some default Plupload settings so we can upload meda theme-side
489 *
490 * @global type $wp_scripts
491 */
c65e58f3 »
2012-08-12 Make the function name a verb
492 private static function add_default_plupload_settings() {
8413aff2 »
2012-07-31 Uploading:
493 global $wp_scripts;
494
495 $defaults = array(
496 'runtimes' => 'html5,silverlight,flash,html4',
497 'file_data_name' => 'async-upload',
498 'multiple_queues' => true,
499 'max_file_size' => self::max_upload_size() . 'b',
500 'url' => admin_url( 'admin-ajax.php', 'relative' ),
501 'flash_swf_url' => includes_url( 'js/plupload/plupload.flash.swf' ),
502 'silverlight_xap_url' => includes_url( 'js/plupload/plupload.silverlight.xap' ),
70b347ae »
2012-09-06 Add missing textdomain to translated strings
503 'filters' => array( array( 'title' => __( 'Allowed Files', 'liveblog' ), 'extensions' => '*') ),
8413aff2 »
2012-07-31 Uploading:
504 'multipart' => true,
505 'urlstream_upload' => true,
506 'multipart_params' => array(
507 'action' => 'upload-attachment',
508 '_wpnonce' => wp_create_nonce( 'media-form' )
509 )
510 );
511
512 $settings = array(
513 'defaults' => $defaults,
514 'browser' => array(
515 'mobile' => wp_is_mobile(),
516 'supported' => _device_can_upload(),
517 )
518 );
519
520 $script = 'var _wpPluploadSettings = ' . json_encode( $settings ) . ';';
521 $data = $wp_scripts->get_data( 'wp-plupload', 'data' );
522
523 if ( ! empty( $data ) )
524 $script = "$data\n$script";
525
526 $wp_scripts->add_data( 'wp-plupload', 'data', $script );
527 }
528
529 /**
0a0ca28b »
2012-07-30 Weekend updates:
530 * Get the URL of a specific liveblog entry.
531 *
532 * @return string
533 */
534 private static function get_entries_endpoint_url() {
0dccc810 »
2012-09-19 Add correct endpoing to draft URLs with query args
535 $post_permalink = get_permalink( self::$post_id );
536 if ( false !== strpos( $post_permalink, '?p=' ) )
537 $url = add_query_arg( self::url_endpoint, '', $post_permalink ) . '='; // returns something like ?p=1&liveblog=
25be635c »
2012-09-04 Support for non-pretty permalinks
538 else
0dccc810 »
2012-09-19 Add correct endpoing to draft URLs with query args
539 $url = trailingslashit( trailingslashit( $post_permalink ) . self::url_endpoint ); // returns something like /2012/01/01/post/liveblog/
7330fcbe »
2012-09-19 Allow the endpoint URL to be filtered
540 $url = apply_filters( 'liveblog_endpoint_url', $url, self::$post_id );
25be635c »
2012-09-04 Support for non-pretty permalinks
541 return $url;
0a0ca28b »
2012-07-30 Weekend updates:
542 }
cb778e43 »
2012-06-05 Load initial entries server-side rather than via AJAX for SEO benefit
543
0a0ca28b »
2012-07-30 Weekend updates:
544 /** Display Methods *******************************************************/
cd6d5741 »
2012-07-26 * Code clean up.
545
0a0ca28b »
2012-07-30 Weekend updates:
546 /**
547 * Filter the_content and add the liveblog theme-side UI above the normal
548 * content area.
549 *
550 * @param string $content
551 * @return string
552 */
553 public static function add_liveblog_to_content( $content ) {
cb778e43 »
2012-06-05 Load initial entries server-side rather than via AJAX for SEO benefit
554
0a0ca28b »
2012-07-30 Weekend updates:
555 $liveblog_output = '<div id="liveblog-container" class="'. self::$post_id .'">';
556 $liveblog_output .= self::get_editor_output();
557 $liveblog_output .= '<div id="liveblog-update-spinner"></div>';
558 $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…
559 $liveblog_output .= '</div>';
8ff4206e »
2012-06-05 v1
560
09e766c0 »
2012-09-25 New filter: liveblog_add_to_content
561 $liveblog_output = apply_filters( 'liveblog_add_to_content', $liveblog_output, $content, self::$post_id );
562
7205206d »
2012-08-01 Put the post contents before the liveblog
563 return $content . $liveblog_output;
8ff4206e »
2012-06-05 v1
564 }
565
0a0ca28b »
2012-07-30 Weekend updates:
566 /**
567 * Return the posting area for the end-user to liveblog from
568 *
569 * @return string
570 */
571 private static function get_editor_output() {
b58c3a07 »
2012-07-04 Remove leading underscores from function names
572 if ( ! self::current_user_can_edit_liveblog() )
8ff4206e »
2012-06-05 v1
573 return;
ea5a8a60 »
2012-12-18 Introduce archiving
574 if ( 'archive' == self::get_liveblog_state() ) {
575 return;
576 }
8ff4206e »
2012-06-05 v1
577
0a0ca28b »
2012-07-30 Weekend updates:
578 // Get the template part
579 return self::get_template_part( 'liveblog-form.php' );
8ff4206e »
2012-06-05 v1
580 }
581
0a0ca28b »
2012-07-30 Weekend updates:
582 /**
583 * Get all the liveblog entries for this post
584 */
585 private static function get_all_entry_output() {
8413aff2 »
2012-07-31 Uploading:
586
0a0ca28b »
2012-07-30 Weekend updates:
587 // Get liveblog entries
9c2b7c37 »
2012-08-22 Order entries reverse-chronologically on initial load
588 $entries = (array) self::$entry_query->get_all();
8ff4206e »
2012-06-05 v1
589
0a0ca28b »
2012-07-30 Weekend updates:
590 // Get the template part
591 return self::get_template_part( 'liveblog-loop.php', compact( 'entries' ) );
592 }
593
594 /**
595 * Get the template part in an output buffer and return it
596 *
597 * @param string $template_name
598 * @param array $template_variables
599 */
600 public static function get_template_part( $template_name, $template_variables = array() ) {
601 ob_start();
602 extract( $template_variables );
603 include( dirname( __FILE__ ) . '/templates/' . $template_name );
604 return ob_get_clean();
8ff4206e »
2012-06-05 v1
605 }
8413aff2 »
2012-07-31 Uploading:
606
0a0ca28b »
2012-07-30 Weekend updates:
607 /** Admin Methods *********************************************************/
608
609 /**
610 * Register the metabox with the supporting post-type
611 *
612 * @param string $post_type
613 */
614 public static function add_meta_box( $post_type ) {
615
616 // Bail if not supported
617 if ( ! post_type_supports( $post_type, self::key ) )
618 return;
8ff4206e »
2012-06-05 v1
619
0a0ca28b »
2012-07-30 Weekend updates:
620 add_meta_box( self::key, __( 'Liveblog', 'liveblog' ), array( __CLASS__, 'display_meta_box' ) );
8ff4206e »
2012-06-05 v1
621 }
cd6d5741 »
2012-07-26 * Code clean up.
622
186ea96e »
2012-12-27 Add an image URL handler
623 public static function image_embed_handler( $matches, $attr, $url, $rawattr ) {
624 $embed = sprintf( '<img src="%s" alt="" />', esc_url( $url ) );
625 return apply_filters( 'embed_liveblog_image', $embed, $matches, $attr, $url, $rawattr );
626 }
627
0a0ca28b »
2012-07-30 Weekend updates:
628 /**
629 * Output the metabox
630 *
631 * @param WP_Post $post
632 */
633 public static function display_meta_box( $post ) {
ea5a8a60 »
2012-12-18 Introduce archiving
634 $current_state = self::get_liveblog_state( $post->ID );
635 $buttons = array(
8c3cdd8d »
2012-12-20 Remove the Disable button
636 'enable' => array( 'value' => 'enable', 'text' => __( 'Enable', 'liveblog' ),
637 'description' => __( 'Enables liveblog on this post. Posting tools are enabled for editors, visitors get the latest updates.' , 'liveblog'), 'active-text' => sprintf( __( 'There is an <strong>enabled</strong> liveblog on this post. <a href="%s">Visit the liveblog &rarr;</a>', 'liveblog' ), get_permalink( $post ) ), 'primary' => true, 'disabled' => false, ),
ea5a8a60 »
2012-12-18 Introduce archiving
638 'archive' => array( 'value' => 'archive', 'text' => __( 'Archive', 'liveblog' ),
8c3cdd8d »
2012-12-20 Remove the Disable button
639 'description' => __( 'Archives the liveblog on this post. Visitors still see the liveblog entries, but posting tools are hidden.' , 'liveblog'), 'active-text' => sprintf( __( 'There is an <strong>archived</strong> liveblog on this post. <a href="%s">Visit the liveblog archive &rarr;</a>', 'liveblog' ), get_permalink( $post ) ), 'primary' => false, 'disabled' => false ),
ea5a8a60 »
2012-12-18 Introduce archiving
640 );
8c3cdd8d »
2012-12-20 Remove the Disable button
641 if ( $current_state ) {
642 $active_text = $buttons[$current_state]['active-text'];
643 $buttons[$current_state]['disabled'] = true;
644 } else {
645 $active_text = __( 'This is a normal WordPress post, without a liveblog.', 'liveblog' );
646 $buttons['archive']['disabled'] = true;
ea5a8a60 »
2012-12-18 Introduce archiving
647 }
648 echo self::get_template_part( 'meta_box.php', compact( 'active_text', 'buttons' ) );
8ff4206e »
2012-06-05 v1
649 }
0a0ca28b »
2012-07-30 Weekend updates:
650
ea5a8a60 »
2012-12-18 Introduce archiving
651 public function admin_ajax_set_liveblog_state_for_post() {
652 $post_id = isset( $_REQUEST['post_id'] )? $_REQUEST['post_id'] : 0;
653 $new_state = isset( $_REQUEST['state'] )? $_REQUEST['state'] : '';
0a0ca28b »
2012-07-30 Weekend updates:
654
e447a3c5 »
2012-12-20 Check for permissions and nonces
655 self::ajax_current_user_can_edit_liveblog();
656 self::ajax_check_nonce();
8ff4206e »
2012-06-05 v1
657
ea5a8a60 »
2012-12-18 Introduce archiving
658 if ( !$REQUEST = get_post( $post_id ) ) {
feecd6bc »
2012-12-19 Add text domains
659 self::send_user_error( __( "Non-existing post ID: $post_id" , 'liveblog') );
ea5a8a60 »
2012-12-18 Introduce archiving
660 }
661
662 if ( wp_is_post_revision( $post_id ) ) {
feecd6bc »
2012-12-19 Add text domains
663 self::send_user_error( __( "The post is a revision: $post_id" , 'liveblog') );
ea5a8a60 »
2012-12-18 Introduce archiving
664 }
c9f98b5b »
2012-09-25 Only update/delete liveblog postmeta when it's changing.
665
ea5a8a60 »
2012-12-18 Introduce archiving
666 self::set_liveblog_state( $post_id, $_REQUEST['state'] );
667 self::display_meta_box( $REQUEST );
668 exit;
669 }
c9f98b5b »
2012-09-25 Only update/delete liveblog postmeta when it's changing.
670
ea5a8a60 »
2012-12-18 Introduce archiving
671 private function set_liveblog_state( $post_id, $state ) {
672 if ( in_array( $state, array( 'enable', 'archive' ) ) ) {
673 update_post_meta( $post_id, self::key, $state );
674 do_action( "liveblog_{$state}_post", $post_id );
675 } elseif ( 'disable' == $state ) {
8ff4206e »
2012-06-05 v1
676 delete_post_meta( $post_id, self::key );
7e39692c »
2012-09-25 Introduce some new hooks.
677 do_action( 'liveblog_disable_post', $post_id );
ea5a8a60 »
2012-12-18 Introduce archiving
678 } else {
679 return false;
7e39692c »
2012-09-25 Introduce some new hooks.
680 }
8ff4206e »
2012-06-05 v1
681 }
2ba7f864 »
2012-06-19 Remove trailing whitespace
682
0a0ca28b »
2012-07-30 Weekend updates:
683 /** Error Methods *********************************************************/
684
685 /**
686 * Can the current user edit liveblog data (non-ajax)
687 *
688 * @return bool
689 */
690 public static function current_user_can_edit_liveblog() {
691 return (bool) current_user_can( apply_filters( 'liveblog_edit_cap', self::edit_cap ) );
8ff4206e »
2012-06-05 v1
692 }
693
0a0ca28b »
2012-07-30 Weekend updates:
694 /**
695 * Can the current user edit liveblog data (ajax)
696 *
697 * Sends an error if not
698 */
699 public static function ajax_current_user_can_edit_liveblog() {
b58c3a07 »
2012-07-04 Remove leading underscores from function names
700 if ( ! self::current_user_can_edit_liveblog() ) {
69f9cbb2 »
2012-08-20 Add more specific HTTP error codes
701 self::send_forbidden_error( __( "Cheatin', uh?", 'liveblog' ) );
8ff4206e »
2012-06-05 v1
702 }
703 }
704
0a0ca28b »
2012-07-30 Weekend updates:
705 /**
706 * Check for valid intention, and send an error if there is none
707 *
708 * @param string $action
709 */
710 public static function ajax_check_nonce( $action = self::nonce_key ) {
8ff4206e »
2012-06-05 v1
711 if ( ! isset( $_REQUEST[ self::nonce_key ] ) || ! wp_verify_nonce( $_REQUEST[ self::nonce_key ], $action ) ) {
69f9cbb2 »
2012-08-20 Add more specific HTTP error codes
712 self::send_forbidden_error( __( 'Sorry, we could not authenticate you.', 'liveblog' ) );
8ff4206e »
2012-06-05 v1
713 }
714 }
715
0a0ca28b »
2012-07-30 Weekend updates:
716 /** Feedback **************************************************************/
717
718 /**
719 * Send an error message
720 * @param type $message
721 */
69f9cbb2 »
2012-08-20 Add more specific HTTP error codes
722 private static function send_server_error( $message ) {
0a0ca28b »
2012-07-30 Weekend updates:
723 self::status_header_with_message( 500, $message );
724 exit();
725 }
726
69f9cbb2 »
2012-08-20 Add more specific HTTP error codes
727 private static function send_user_error( $message ) {
728 self::status_header_with_message( 406, $message );
729 exit();
730 }
731
732 private static function send_forbidden_error( $message ) {
733 self::status_header_with_message( 403, $message );
734 exit();
735 }
736
0a0ca28b »
2012-07-30 Weekend updates:
737 /**
738 * Encode some data and echo it (possibly without cached headers)
739 *
740 * @param array $data
741 */
742 private static function json_return( $data ) {
20c5b025 »
2012-07-11 Get rid of the intermediate layer completely
743 $json_data = json_encode( $data );
8ff4206e »
2012-06-05 v1
744
f2908dfd »
2012-07-02 Get rid if return functionality in json_return()
745 header( 'Content-Type: application/json' );
cd6d5741 »
2012-07-26 * Code clean up.
746 if ( self::$do_not_cache_response )
6c667576 »
2012-07-04 Do not let the client cache future requests
747 nocache_headers();
20c5b025 »
2012-07-11 Get rid of the intermediate layer completely
748
749 echo $json_data;
0a0ca28b »
2012-07-30 Weekend updates:
750 exit();
d81e042f »
2012-07-11 Extract sending errors in its own method
751 }
752
0a0ca28b »
2012-07-30 Weekend updates:
753 /**
754 * Modify the header and description in the global array
755 *
756 * @global array $wp_header_to_desc
757 * @param int $status
758 * @param string $message
759 */
760 private static function status_header_with_message( $status, $message ) {
25323979 »
2012-07-11 Send HTTP errors instead of the success flag
761 global $wp_header_to_desc;
cd6d5741 »
2012-07-26 * Code clean up.
762
763 $status = absint( $status );
764 $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
765 $wp_header_to_desc[$status] = $message;
cd6d5741 »
2012-07-26 * Code clean up.
766
25323979 »
2012-07-11 Send HTTP errors instead of the success flag
767 status_header( $status );
cd6d5741 »
2012-07-26 * Code clean up.
768
25323979 »
2012-07-11 Send HTTP errors instead of the success flag
769 $wp_header_to_desc[$status] = $official_message;
770 }
8413aff2 »
2012-07-31 Uploading:
771
772 /** Plupload Helpers ******************************************************/
773
774 /**
775 * Convert hours to bytes
776 *
777 * @param unknown_type $size
778 * @return unknown
779 */
780 private static function convert_hr_to_bytes( $size ) {
781 $size = strtolower( $size );
782 $bytes = (int) $size;
783
784 if ( strpos( $size, 'k' ) !== false )
785 $bytes = intval( $size ) * 1024;
786 elseif ( strpos( $size, 'm' ) !== false )
787 $bytes = intval( $size ) * 1024 * 1024;
788 elseif ( strpos( $size, 'g' ) !== false )
789 $bytes = intval( $size ) * 1024 * 1024 * 1024;
790
791 return $bytes;
792 }
793
794 /**
795 * Convert bytes to hour
796 *
797 * @param string $bytes
798 * @return string
799 */
800 private static function convert_bytes_to_hr( $bytes ) {
801 $units = array( 0 => 'B', 1 => 'kB', 2 => 'MB', 3 => 'GB' );
802 $log = log( $bytes, 1024 );
803 $power = (int) $log;
804 $size = pow( 1024, $log - $power );
805
806 return $size . $units[$power];
807 }
808
809 /**
810 * Get the maximum upload file size
811 *
812 * @see wp_max_upload_size()
813 * @return string
814 */
815 private static function max_upload_size() {
816 $u_bytes = self::convert_hr_to_bytes( ini_get( 'upload_max_filesize' ) );
817 $p_bytes = self::convert_hr_to_bytes( ini_get( 'post_max_size' ) );
818 $bytes = apply_filters( 'upload_size_limit', min( $u_bytes, $p_bytes ), $u_bytes, $p_bytes );
819
820 return $bytes;
a6429c8f »
2012-08-15 Remove trailing whitespace
821 }
8ff4206e »
2012-06-05 v1
822 }
823
0a0ca28b »
2012-07-30 Weekend updates:
824 /**
825 * Load the one true WPCOM_Liveblog instance
826 *
827 * Loaded late on the 'plugins_loaded' hook to allow any other plugin to sneak
828 * in ahead of it, to add actions, filters, etc...
829 *
830 * @uses WPCOM_Liveblog::load()
831 */
832 function wpcom_liveblog_load() {
833 WPCOM_Liveblog::load();
834 }
835 add_action( 'plugins_loaded', 'wpcom_liveblog_load', 999 );
836
8ff4206e »
2012-06-05 v1
837 endif;
Something went wrong with that request. Please try again.