PluginProbe
Advanced Excerpt / 4.1
Advanced Excerpt v4.1
trunk 0.2.2 3.0 3.1 4.0 4.1 4.1.1 4.2 4.2.1 4.2.2 4.2.3 4.2.4 4.2.5 4.2.6 4.2.7 4.2.8 4.2.9 4.3.0 4.3.1 4.3.2 4.3.3 4.3.4 4.3.5 4.3.6 4.3.7 All 30 releases
advanced-excerpt / advanced-excerpt.php

advanced-excerpt.php in Advanced Excerpt 4.1, at advanced-excerpt.php

496 lines 18.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /*
3 Plugin Name: Advanced Excerpt
4 Plugin URI: http://basvd.com/code/advanced-excerpt/
5 Description: Several improvements over WP's default excerpt. The size of the excerpt can be limited using character or word count, and HTML markup is not removed.
6 Version: 4.1
7 Author: Bas van Doren
8 Author URI: http://basvd.com/
9
10 Copyright 2007 Bas van Doren
11
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 3 of the License, or
15 (at your option) any later version.
16
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
21
22 You should have received a copy of the GNU General Public License
23 along with this program. If not, see <http://www.gnu.org/licenses/>.
24 */
25
26 if (!class_exists('AdvancedExcerpt')):
27 class AdvancedExcerpt
28 {
29 // Plugin configuration
30 public $name;
31 public $text_domain;
32 public $options;
33 public $default_options = array(
34 'length' => 40,
35 'use_words' => 1,
36 'no_custom' => 1,
37 'no_shortcode' => 1,
38 'finish_word' => 0,
39 'finish_sentence' => 0,
40 'ellipsis' => '&hellip;',
41 'read_more' => 'Read the rest',
42 'add_link' => 0,
43 'allowed_tags' => array('_all')
44 );
45
46 // Basic HTML tags (determines which tags are in the checklist by default)
47 public static $options_basic_tags = array
48 (
49 'a', 'abbr', 'acronym', 'b', 'big',
50 'blockquote', 'br', 'center', 'cite', 'code', 'dd', 'del', 'div', 'dl', 'dt',
51 'em', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'hr', 'i', 'img', 'ins',
52 'li', 'ol', 'p', 'pre', 'q', 's', 'small', 'span', 'strike', 'strong', 'sub',
53 'sup', 'table', 'td', 'th', 'tr', 'u', 'ul'
54 );
55
56 // Almost all HTML tags (extra options)
57 public static $options_all_tags = array(
58 'a', 'abbr', 'acronym', 'address', 'applet',
59 'area', 'b', 'bdo', 'big', 'blockquote', 'br', 'button', 'caption', 'center',
60 'cite', 'code', 'col', 'colgroup', 'dd', 'del', 'dfn', 'dir', 'div', 'dl',
61 'dt', 'em', 'fieldset', 'font', 'form', 'frame', 'frameset', 'h1', 'h2', 'h3',
62 'h4', 'h5', 'h6', 'hr', 'i', 'iframe', 'img', 'input', 'ins', 'isindex', 'kbd',
63 'label', 'legend', 'li', 'map', 'menu', 'noframes', 'noscript', 'object',
64 'ol', 'optgroup', 'option', 'p', 'param', 'pre', 'q', 's', 'samp', 'script',
65 'select', 'small', 'span', 'strike', 'strong', 'style', 'sub', 'sup', 'table',
66 'tbody', 'td', 'textarea', 'tfoot', 'th', 'thead', 'tr', 'tt', 'u', 'ul',
67 'var'
68 );
69
70 // Singleton
71 private static $inst = null;
72 public static function Instance($new = false)
73 {
74 if (self::$inst == null || $new)
75 {
76 self::$inst = new AdvancedExcerpt();
77 }
78 return self::$inst;
79 }
80
81 private function __construct()
82 {
83 $this->name = strtolower(get_class());
84 $this->text_domain = $this->name;
85 $this->load_options();
86
87 load_plugin_textdomain($this->text_domain, false, dirname(plugin_basename(__FILE__)));
88 register_activation_hook(__FILE__, array(
89 &$this,
90 'install'
91 ));
92 //register_deactivation_hook($file, array(&$this, 'uninstall'));
93
94 add_action('admin_menu', array(
95 &$this,
96 'add_pages'
97 ));
98
99 // Replace the default filter (see /wp-includes/default-filters.php)
100 //remove_filter('get_the_excerpt', 'wp_trim_excerpt');
101 // Replace everything
102 remove_all_filters('get_the_excerpt');
103 add_filter('get_the_excerpt', array(
104 &$this,
105 'filter'
106 ));
107 }
108
109 public function filter($text)
110 {
111 // Extract options (skip collisions)
112 if (is_array($this->options))
113 {
114 extract($this->options, EXTR_SKIP);
115 $this->options = null; // Reset
116 }
117 extract($this->default_options, EXTR_SKIP);
118
119 // Avoid custom excerpts
120 if (!empty($text) && !$no_custom)
121 return $text;
122
123 // Get the full content and filter it
124 $text = get_the_content('');
125 if (1 == $no_shortcode)
126 $text = strip_shortcodes($text);
127 $text = apply_filters('the_content', $text);
128
129 // From the default wp_trim_excerpt():
130 // Some kind of precaution against malformed CDATA in RSS feeds I suppose
131 $text = str_replace(']]>', ']]&gt;', $text);
132
133 // Determine allowed tags
134 if(!isset($allowed_tags))
135 $allowed_tags = self::$options_all_tags;
136
137 if(isset($exclude_tags))
138 $allowed_tags = array_diff($allowed_tags, $exclude_tags);
139
140 // Strip HTML if allow-all is not set
141 if (!in_array('_all', $allowed_tags))
142 {
143 if (count($allowed_tags) > 0)
144 $tag_string = '<' . implode('><', $allowed_tags) . '>';
145 else
146 $tag_string = '';
147 $text = strip_tags($text, $tag_string);
148 }
149
150 // Create the excerpt
151 $text = $this->text_excerpt($text, $length, $use_words, $finish_word, $finish_sentence);
152
153 // Add the ellipsis or link
154 $text = $this->text_add_more($text, $ellipsis, ($add_link) ? $read_more : false);
155
156 return $text;
157 }
158
159 public function text_excerpt($text, $length, $use_words, $finish_word, $finish_sentence)
160 {
161 $tokens = array();
162 $out = '';
163 $w = 0;
164
165 // Divide the string into tokens; HTML tags, or words, followed by any whitespace
166 // (<[^>]+>|[^<>\s]+\s*)
167 preg_match_all('/(<[^>]+>|[^<>\s]+)\s*/u', $text, $tokens);
168 foreach ($tokens[0] as $t)
169 { // Parse each token
170 if ($w >= $length && !$finish_sentence)
171 { // Limit reached
172 break;
173 }
174 if ($t[0] != '<')
175 { // Token is not a tag
176 if ($w >= $length && $finish_sentence && preg_match('/[\?\.\!]\s*$/uS', $t) == 1)
177 { // Limit reached, continue until ? . or ! occur at the end
178 $out .= trim($t);
179 break;
180 }
181 if (1 == $use_words)
182 { // Count words
183 $w++;
184 } else
185 { // Count/trim characters
186 $chars = trim($t); // Remove surrounding space
187 $c = strlen($chars);
188 if ($c + $w > $length && !$finish_sentence)
189 { // Token is too long
190 $c = ($finish_word) ? $c : $length - $w; // Keep token to finish word
191 $t = substr($t, 0, $c);
192 }
193 $w += $c;
194 }
195 }
196 // Append what's left of the token
197 $out .= $t;
198 }
199
200 return trim(force_balance_tags($out));
201 }
202
203 public function text_add_more($text, $ellipsis, $read_more)
204 {
205 // New filter in WP2.9, seems unnecessary for now
206 //$ellipsis = apply_filters('excerpt_more', $ellipsis);
207
208 if ($read_more)
209 $ellipsis .= sprintf(' <a href="%s" class="read_more">%s</a>', get_permalink(), $read_more);
210
211 $pos = strrpos($text, '</');
212 if ($pos !== false)
213 // Inside last HTML tag
214 $text = substr_replace($text, $ellipsis, $pos, 0);
215 else
216 // After the content
217 $text .= $ellipsis;
218
219 return $text;
220 }
221
222 public function install()
223 {
224 foreach($this->default_options as $k => $v)
225 {
226 add_option($this->name . '_' . $k, $v);
227 }
228 }
229
230 public function uninstall()
231 {
232 // Nothing to do (note: deactivation hook is also disabled)
233 }
234
235 private function load_options()
236 {
237 foreach($this->default_options as $k => $v)
238 {
239 $this->default_options[$k] = get_option($this->name . '_' . $k, $v);
240 }
241 }
242
243 private function update_options()
244 {
245 $length = (int) $_POST[$this->name . '_length'];
246 $use_words = ('on' == $_POST[$this->name . '_use_words']) ? 1 : 0;
247 $no_custom = ('on' == $_POST[$this->name . '_no_custom']) ? 1 : 0;
248 $no_shortcode = ('on' == $_POST[$this->name . '_no_shortcode']) ? 1 : 0;
249 $finish_word = ('on' == $_POST[$this->name . '_finish_word']) ? 1 : 0;
250 $finish_sentence = ('on' == $_POST[$this->name . '_finish_sentence']) ? 1 : 0;
251 $add_link = ('on' == $_POST[$this->name . '_add_link']) ? 1 : 0;
252
253 // TODO: Drop magic quotes (deprecated in php 5.3)
254 $ellipsis = (get_magic_quotes_gpc() == 1) ? stripslashes($_POST[$this->name . '_ellipsis']) : $_POST[$this->name . '_ellipsis'];
255 $read_more = (get_magic_quotes_gpc() == 1) ? stripslashes($_POST[$this->name . '_read_more']) : $_POST[$this->name . '_read_more'];
256
257 $allowed_tags = array_unique((array) $_POST[$this->name . '_allowed_tags']);
258
259 update_option($this->name . '_length', $length);
260 update_option($this->name . '_use_words', $use_words);
261 update_option($this->name . '_no_custom', $no_custom);
262 update_option($this->name . '_no_shortcode', $no_shortcode);
263 update_option($this->name . '_finish_word', $finish_word);
264 update_option($this->name . '_finish_sentence', $finish_sentence);
265 update_option($this->name . '_ellipsis', $ellipsis);
266 update_option($this->name . '_read_more', $read_more);
267 update_option($this->name . '_add_link', $add_link);
268 update_option($this->name . '_allowed_tags', $allowed_tags);
269
270 $this->load_options();
271 ?>
272 <div id="message" class="updated fade"><p>Options saved.</p></div>
273 <?php
274 }
275
276 public function page_options()
277 {
278 if ('POST' == $_SERVER['REQUEST_METHOD'])
279 {
280 check_admin_referer($this->name . '_update_options');
281 $this->update_options();
282 }
283
284 extract($this->default_options, EXTR_SKIP);
285
286 $ellipsis = htmlentities($ellipsis);
287 $read_more = htmlentities($read_more);
288
289 $tag_list = array_unique(self::$options_basic_tags + $allowed_tags);
290 sort($tag_list);
291 $tag_cols = 5;
292 ?>
293 <div class="wrap">
294 <div id="icon-options-general" class="icon32"><br /></div>
295 <h2><?php
296 _e("Advanced Excerpt Options", $this->text_domain);
297 ?></h2>
298 <form method="post" action="">
299 <?php
300 if (function_exists('wp_nonce_field'))
301 wp_nonce_field($this->name . '_update_options');
302 ?>
303
304 <table class="form-table">
305 <tr valign="top">
306 <th scope="row"><label for="<?php echo $this->name; ?>_length">
307 <?php _e("Excerpt Length:", $this->text_domain); ?></label></th>
308 <td>
309 <input name="<?php echo $this->name; ?>_length" type="text"
310 id="<?php echo $this->name; ?>_length"
311 value="<?php echo $length; ?>" size="2"/>
312 <input name="<?php echo $this->name; ?>_use_words" type="checkbox"
313 id="<?php echo $this->name; ?>_use_words" value="on"<?php
314 echo (1 == $use_words) ? ' checked="checked"' : ''; ?>/>
315 <?php _e("Use words?", $this->text_domain); ?>
316 </td>
317 </tr>
318 <tr valign="top">
319 <th scope="row"><label for="<?php echo $this->name; ?>_ellipsis">
320 <?php _e("Ellipsis:", $this->text_domain); ?></label></th>
321 <td>
322 <input name="<?php echo $this->name; ?>_ellipsis" type="text"
323 id="<?php echo $this->name; ?>_ellipsis"
324 value="<?php echo $ellipsis; ?>" size="5"/>
325 <?php _e('(use <a href="http://www.w3schools.com/tags/ref_entities.asp">HTML entities</a>)', $this->text_domain); ?>
326 <br />
327 <?php _e("Will substitute the part of the post that is omitted in the excerpt.", $this->text_domain); ?>
328 </td>
329 </tr>
330 <tr valign="top">
331 <th scope="row"><label for="<?php echo $this->name; ?>_length">
332 <?php _e("Finish:", $this->text_domain); ?></label></th>
333 <td>
334 <input name="<?php echo $this->name; ?>_finish_word" type="checkbox"
335 id="<?php echo $this->name; ?>_finish_word" value="on"<?php
336 echo (1 == $finish_word) ? ' checked="checked"' : ''; ?>/>
337 <?php _e("Word", $this->text_domain); ?><br/>
338 <input name="<?php echo $this->name; ?>_finish_sentence" type="checkbox"
339 id="<?php echo $this->name; ?>_finish_sentence" value="on"<?php
340 echo (1 == $finish_sentence) ? ' checked="checked"' : ''; ?>/>
341 <?php _e("Sentence", $this->text_domain); ?>
342 <br />
343 <?php _e("Prevents cutting a word or sentence at the end of an excerpt. This option can result in (slightly) longer excerpts.", $this->text_domain); ?>
344 </td>
345 </tr>
346 <tr valign="top">
347 <th scope="row"><label for="<?php echo $this->name; ?>_read_more">
348 <?php _e("&lsquo;Read-more&rsquo; Text:", $this->text_domain); ?></label></th>
349 <td>
350 <input name="<?php echo $this->name; ?>_read_more" type="text"
351 id="<?php echo $this->name; ?>_read_more" value="<?php echo $read_more; ?>" />
352 <input name="<?php echo $this->name; ?>_add_link" type="checkbox"
353 id="<?php echo $this->name; ?>_add_link" value="on" <?php
354 echo (1 == $add_link) ? 'checked="checked" ' : ''; ?>/>
355 <?php _e("Add link to excerpt", $this->text_domain); ?>
356 </td>
357 </tr>
358 <tr valign="top">
359 <th scope="row"><label for="<?php echo $this->name; ?>_no_custom">
360 <?php _e("No Custom Excerpts:", $this->text_domain); ?></label></th>
361 <td>
362 <input name="<?php echo $this->name; ?>_no_custom" type="checkbox"
363 id="<?php echo $this->name; ?>_no_custom" value="on" <?php
364 echo (1 == $no_custom) ? 'checked="checked" ' : ''; ?>/>
365 <?php _e("Generate excerpts even if a post has a custom excerpt attached.", $this->text_domain); ?>
366 </td>
367 </tr>
368 <tr valign="top">
369 <th scope="row"><label for="<?php echo $this->name; ?>_no_shortcode">
370 <?php _e("Strip Shortcodes:", $this->text_domain); ?></label></th>
371 <td>
372 <input name="<?php echo $this->name; ?>_no_shortcode" type="checkbox"
373 id="<?php echo $this->name; ?>_no_shortcode" value="on" <?php
374 echo (1 == $no_shortcode) ? 'checked="checked" ' : ''; ?>/>
375 <?php _e("Remove shortcodes from the excerpt. <em>(recommended)</em>", $this->text_domain); ?>
376 </td>
377 </tr>
378 <tr valign="top">
379 <th scope="row"><?php _e("Keep Markup:", $this->text_domain); ?></th>
380 <td>
381 <table id="<?php echo $this->name; ?>_tags_table">
382 <tr>
383 <td colspan="<?php echo $tag_cols; ?>">
384 <input name="<?php echo $this->name; ?>_allowed_tags[]" type="checkbox"
385 value="_all" <?php echo (in_array('_all', $allowed_tags)) ? 'checked="checked" ' : ''; ?>/>
386 <?php _e("Don't remove any markup", $this->text_domain); ?>
387 </td>
388 </tr>
389 <?php
390 $i = 0;
391 foreach ($tag_list as $tag):
392 if ($tag == '_all')
393 continue;
394 if (0 == $i % $tag_cols):
395 ?>
396 <tr>
397 <?php
398 endif;
399 $i++;
400 ?>
401 <td>
402 <input name="<?php echo $this->name; ?>_allowed_tags[]" type="checkbox"
403 value="<?php echo $tag; ?>" <?php
404 echo (in_array($tag, $allowed_tags)) ? 'checked="checked" ' : ''; ?>/>
405 <code><?php echo $tag; ?></code>
406 </td>
407 <?php
408 if (0 == $i % $tag_cols):
409 $i = 0;
410 echo '</tr>';
411 endif;
412 endforeach;
413 if (0 != $i % $tag_cols):
414 ?>
415 <td colspan="<?php echo ($tag_cols - $i); ?>">&nbsp;</td>
416 </tr>
417 <?php
418 endif;
419 ?>
420 </table>
421 <a href="" id="<?php echo $this->name; ?>_select_all">Select all</a>
422 / <a href="" id="<?php echo $this->name; ?>_select_none">Select none</a><br />
423 More tags:
424 <select name="<?php echo $this->name; ?>_more_tags" id="<?php echo $this->name; ?>_more_tags">
425 <?php
426 foreach (self::$options_all_tags as $tag):
427 ?>
428 <option value="<?php echo $tag; ?>"><?php echo $tag; ?></option>
429 <?php
430 endforeach;
431 ?>
432 </select>
433 <input type="button" name="<?php echo $this->name; ?>_add_tag" id="<?php echo $this->name; ?>_add_tag" class="button" value="Add tag" />
434 </td>
435 </tr>
436 </table>
437 <p class="submit"><input type="submit" name="Submit" class="button-primary"
438 value="<?php _e("Save Changes", $this->text_domain); ?>" /></p>
439 </form>
440 </div>
441 <?php
442 }
443
444 public function page_script()
445 {
446 wp_enqueue_script($this->name . '_script', WP_PLUGIN_URL . '/advanced-excerpt/advanced-excerpt.js', array(
447 'jquery'
448 ));
449 }
450
451 public function add_pages()
452 {
453 $options_page = add_options_page(__("Advanced Excerpt Options", $this->text_domain), __("Excerpt", $this->text_domain), 'manage_options', 'options-' . $this->name, array(
454 &$this,
455 'page_options'
456 ));
457
458 // Scripts
459 add_action('admin_print_scripts-' . $options_page, array(
460 &$this,
461 'page_script'
462 ));
463 }
464 }
465
466 AdvancedExcerpt::Instance();
467
468 // Do not use outside the Loop!
469 function the_advanced_excerpt($args = '', $get = true)
470 {
471 if (!empty($args) && !is_array($args))
472 {
473 $args = wp_parse_args($args);
474
475 // Parse query style parameters
476 if (isset($args['ellipsis']))
477 $args['ellipsis'] = urldecode($args['ellipsis']);
478
479 if (isset($args['allowed_tags']))
480 $args['allowed_tags'] = preg_split('/[\s,]+/', $args['allowed_tags']);
481
482 if (isset($args['exclude_tags']))
483 {
484 $args['exclude_tags'] = preg_split('/[\s,]+/', $args['exclude_tags']);
485 }
486 }
487 // Set temporary options
488 AdvancedExcerpt::Instance()->options = $args;
489
490 if ($get)
491 return get_the_excerpt();
492 else
493 the_excerpt();
494 }
495 endif;
496