Table of Contents Plus - Version 1112

Version Description

  • Released: 9 December 2011
  • New: auto width option added which takes up only the needed amount of horizontal space up to 100%.
  • Removed trailing - or _ characters from the anchor to make it more pretty.
  • This plugin's long name has changed from "Table of Contents+" to "Table of Contents Plus". The short name remains as "TOC+".
  • Fixed: when using the TOC shortcode within your content, your post or article would display the TOC on the homepage despite having the exclude from homepage option enabled. If you also used the "more tag", then you may have resulted with an empty TOC box. These are now addressed.
  • Fixed: all anchors ending with "-2" when no headings were repeated. This was caused by plugins and themes that trigger the_content filter. The counters are now reset everytime the_content is run rather than only on initialisation.
Download this release

Release Info

Developer conjur3r
Plugin Icon 128x128 Table of Contents Plus
Version 1112
Comparing to
See all releases

Code changes from version 1111 to 1112

Files changed (2) hide show
  1. readme.txt +11 -3
  2. toc.php +121 -101
readme.txt CHANGED
@@ -4,14 +4,14 @@ Donate link:
4
  Tags: table of contents, indexes, toc, sitemap, cms, options, list, page listing, category listing
5
  Requires at least: 3.0
6
  Tested up to: 3.3
7
- Stable tag: 1111
8
 
9
  A powerful yet user friendly plugin that automatically creates a table of contents. Can also output a sitemap listing all pages and categories.
10
 
11
 
12
  == Description ==
13
 
14
- A powerful yet user friendly plugin that automatically creates a context specific index or table of contents for long pages (and custom post types). More than just a table of contents plugin, this plugin can also output a sitemap listing pages and/or categories.
15
 
16
  Built from the ground up and with Wikipedia in mind, the table of contents by default appears before the first heading on a page. This allows the author to insert lead-in content that may summarise or introduce the rest of the page. It also uses a unique numbering scheme that doesn't get lost through CSS differences across themes.
17
 
@@ -19,7 +19,7 @@ This plugin is a great companion for content rich sites such as content manageme
19
 
20
  Includes an administration options panel where you can customise settings like display position, define the minimum number of headings before an index is displayed, appearance, etc. Using shortcodes, you can override default behaviour such as special exclusions on a specific page or even to hide the table of contents altogether.
21
 
22
- Custom post types are supported, however, auto insertion works only when the_content() has been used by the custom post type. Each post type will appear in the options panel, so enable the ones you want.
23
 
24
  If you have questions or suggestions, please place them at [http://dublue.com/plugins/toc/](http://dublue.com/plugins/toc/)
25
 
@@ -75,6 +75,14 @@ Same as `[sitemap_pages]` but for categories.
75
 
76
  == Changelog ==
77
 
 
 
 
 
 
 
 
 
78
  = 1111 =
79
  * Released: 11 November 2011
80
  * New: option to adjust the font size. Thanks to [DJ](http://dublue.com/plugins/toc/comment-page-1/#comment-323) for the suggestion. The default remains at 95%.
4
  Tags: table of contents, indexes, toc, sitemap, cms, options, list, page listing, category listing
5
  Requires at least: 3.0
6
  Tested up to: 3.3
7
+ Stable tag: 1112
8
 
9
  A powerful yet user friendly plugin that automatically creates a table of contents. Can also output a sitemap listing all pages and categories.
10
 
11
 
12
  == Description ==
13
 
14
+ A powerful yet user friendly plugin that automatically creates a context specific index or table of contents (TOC) for long pages (and custom post types). More than just a table of contents plugin, this plugin can also output a sitemap listing pages and/or categories.
15
 
16
  Built from the ground up and with Wikipedia in mind, the table of contents by default appears before the first heading on a page. This allows the author to insert lead-in content that may summarise or introduce the rest of the page. It also uses a unique numbering scheme that doesn't get lost through CSS differences across themes.
17
 
19
 
20
  Includes an administration options panel where you can customise settings like display position, define the minimum number of headings before an index is displayed, appearance, etc. Using shortcodes, you can override default behaviour such as special exclusions on a specific page or even to hide the table of contents altogether.
21
 
22
+ Custom post types are supported, however, auto insertion works only when the_content() has been used by the custom post type. Each post type will appear in the options panel, so enable the ones you want.
23
 
24
  If you have questions or suggestions, please place them at [http://dublue.com/plugins/toc/](http://dublue.com/plugins/toc/)
25
 
75
 
76
  == Changelog ==
77
 
78
+ = 1112 =
79
+ * Released: 9 December 2011
80
+ * New: auto width option added which takes up only the needed amount of horizontal space up to 100%.
81
+ * Removed trailing - or _ characters from the anchor to make it more pretty.
82
+ * This plugin's long name has changed from "Table of Contents+" to "Table of Contents Plus". The short name remains as "TOC+".
83
+ * Fixed: when using the TOC shortcode within your content, your post or article would display the TOC on the homepage despite having the exclude from homepage option enabled. If you also used the "more tag", then you may have resulted with an empty TOC box. These are now addressed.
84
+ * Fixed: all anchors ending with "-2" when no headings were repeated. This was caused by plugins and themes that trigger `the_content` filter. The counters are now reset everytime `the_content` is run rather than only on initialisation.
85
+
86
  = 1111 =
87
  * Released: 11 November 2011
88
  * New: option to adjust the font size. Thanks to [DJ](http://dublue.com/plugins/toc/comment-page-1/#comment-323) for the suggestion. The default remains at 95%.
toc.php CHANGED
@@ -76,7 +76,7 @@ if ( !class_exists( 'toc' ) ) :
76
  $this->path = dirname( WP_PLUGIN_URL . '/' . plugin_basename( __FILE__ ) );
77
  $this->show_toc = true;
78
  $this->exclude_post_types = array( 'attachment', 'revision', 'nav_menu_item', 'safecss' );
79
- $this->collection_collector = array();
80
 
81
  // get options
82
  $defaults = array( // default options
@@ -473,7 +473,7 @@ if ( !class_exists( 'toc' ) ) :
473
  ?>
474
  <div id='toc' class='wrap'>
475
  <div id="icon-options-general" class="icon32"><br /></div>
476
- <h2><?php _e('Table of Contents', 'toc+'); ?>+</h2>
477
  <?php echo $msg; ?>
478
  <form method="post" action="<?php echo htmlentities('?page=' . $_GET['page'] . '&update'); ?>">
479
  <?php wp_nonce_field( plugin_basename(__FILE__), 'toc-admin-options' ); ?>
@@ -587,6 +587,7 @@ if ( !class_exists( 'toc' ) ) :
587
  <option value="400px"<?php if ( '400px' == $this->options['width'] ) echo ' selected="selected"'; ?>><?php _e('400px'); ?></option>
588
  </optgroup>
589
  <optgroup label="<?php _e('Relative', 'toc+'); ?>">
 
590
  <option value="25%"<?php if ( '25%' == $this->options['width'] ) echo ' selected="selected"'; ?>><?php _e('25%'); ?></option>
591
  <option value="33%"<?php if ( '33%' == $this->options['width'] ) echo ' selected="selected"'; ?>><?php _e('33%'); ?></option>
592
  <option value="50%"<?php if ( '50%' == $this->options['width'] ) echo ' selected="selected"'; ?>><?php _e('50%'); ?></option>
@@ -925,6 +926,8 @@ div#toc_container {
925
  else
926
  echo $this->options['width_custom'] . $this->options['width_custom_units'];
927
  echo ";\n";
 
 
928
  }
929
 
930
  if ( '95%' != $this->options['font_size'] . $this->options['font_size_units'] ) {
@@ -1014,6 +1017,9 @@ div#toc_container ul.toc_list a:visited {
1014
  '_',
1015
  $return
1016
  );
 
 
 
1017
 
1018
  // if blank, then prepend with the fragment prefix
1019
  // blank anchors normally appear on sites that don't use the latin charset
@@ -1022,12 +1028,12 @@ div#toc_container ul.toc_list a:visited {
1022
  }
1023
  }
1024
 
1025
- if ( array_key_exists($return, $this->collection_collector) ) {
1026
- $this->collection_collector[$return]++;
1027
- $return .= '-' . $this->collection_collector[$return];
1028
  }
1029
  else
1030
- $this->collection_collector[$return] = 1;
1031
 
1032
  return $return;
1033
  }
@@ -1041,7 +1047,7 @@ div#toc_container ul.toc_list a:visited {
1041
  $numbered_items_min = null;
1042
 
1043
  // reset the internal collision collection
1044
- $this->collection_collector = array();
1045
 
1046
  // find the minimum heading to establish our baseline
1047
  for ($i = 0; $i < count($matches); $i++) {
@@ -1165,7 +1171,7 @@ div#toc_container ul.toc_list a:visited {
1165
  // get all headings
1166
  // the html spec allows for a maximum of 6 heading depths
1167
  if ( preg_match_all('/(<h([1-6]{1})[^>]*>).*<\/h\2>/', $content, $matches, PREG_SET_ORDER) >= $this->options['start'] ) {
1168
-
1169
  // remove disqualified headings (if any) as defined by heading_levels
1170
  if ( count($this->options['heading_levels']) != 6 ) {
1171
  $new_matches = array();
@@ -1213,14 +1219,28 @@ div#toc_container ul.toc_list a:visited {
1213
  /**
1214
  * Returns true if the table of contents is eligible to be printed, false otherwise.
1215
  */
1216
- public function is_eligible()
1217
  {
1218
  global $post;
1219
-
1220
- return (
1221
- ( in_array(get_post_type($post), $this->options['auto_insert_post_types']) && $this->show_toc && !is_search() && !is_archive() && !is_front_page() ) ||
1222
- ( $this->options['include_homepage'] && is_front_page() )
1223
- );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1224
  }
1225
 
1226
 
@@ -1230,95 +1250,100 @@ div#toc_container ul.toc_list a:visited {
1230
  $items = $css_classes = $anchor = '';
1231
  $custom_toc_position = strpos($content, '<!--TOC-->');
1232
  $find = $replace = array();
 
 
 
 
 
1233
 
1234
- if (
1235
- $this->is_eligible() ||
1236
- ( $custom_toc_position !== false ) // user specified toc to appear at a custom position
1237
- ) {
1238
  $items = $this->extract_headings( &$find, &$replace, $content );
1239
 
1240
- // do we display the toc within the content or has the user opted
1241
- // to only show it in the widget? if so, then we still need to
1242
- // make the find/replace call to insert the anchors
1243
- if ( $this->options['show_toc_in_widget_only'] ) {
1244
- $content = $this->mb_find_replace($find, $replace, $content);
1245
- }
1246
- else {
 
1247
 
1248
- // wrapping css classes
1249
- switch( $this->options['wrapping'] ) {
1250
- case TOC_WRAPPING_LEFT:
1251
- $css_classes .= ' toc_wrap_left';
1252
- break;
1253
-
1254
- case TOC_WRAPPING_RIGHT:
1255
- $css_classes .= ' toc_wrap_right';
1256
- break;
1257
 
1258
- case TOC_WRAPPING_NONE:
1259
- default:
1260
- // do nothing
1261
- }
1262
-
1263
- // colour themes
1264
- switch ( $this->options['theme'] ) {
1265
- case TOC_THEME_LIGHT_BLUE:
1266
- $css_classes .= ' toc_light_blue';
1267
- break;
1268
 
1269
- case TOC_THEME_WHITE:
1270
- $css_classes .= ' toc_white';
1271
- break;
 
 
1272
 
1273
- case TOC_THEME_BLACK:
1274
- $css_classes .= ' toc_black';
1275
- break;
1276
-
1277
- case TOC_THEME_TRANSPARENT:
1278
- $css_classes .= ' toc_transparent';
1279
- break;
1280
-
1281
- case TOC_THEME_GREY:
1282
- default:
1283
- // do nothing
1284
- }
1285
-
1286
- // bullets?
1287
- if ( $this->options['bullet_spacing'] )
1288
- $css_classes .= ' have_bullets';
1289
- else
1290
- $css_classes .= ' no_bullets';
1291
-
1292
- $css_classes = trim($css_classes);
1293
-
1294
- // an empty class="" is invalid markup!
1295
- if ( !$css_classes ) $css_classes = ' ';
1296
-
1297
- // add container, toc title and list items
1298
- $html = '<div id="toc_container" class="' . $css_classes . '">';
1299
- if ( $this->options['show_heading_text'] ) $html .= '<p class="toc_title">' . htmlentities( $this->options['heading_text'], ENT_COMPAT, 'UTF-8' ) . '</p>';
1300
- $html .= '<ul class="toc_list">' . $items . '</ul></div>' . "\n";
1301
-
1302
- if ( $custom_toc_position !== false ) {
1303
- $find[] = '<!--TOC-->';
1304
- $replace[] = $html;
1305
- $content = $this->mb_find_replace($find, $replace, $content);
1306
- }
1307
- else {
1308
- if ( count($find) > 0 ) {
1309
- switch ( $this->options['position'] ) {
1310
- case TOC_POSITION_TOP:
1311
- $content = $html . $this->mb_find_replace($find, $replace, $content);
1312
- break;
1313
 
1314
- case TOC_POSITION_BOTTOM:
1315
- $content = $this->mb_find_replace($find, $replace, $content) . $html;
1316
- break;
1317
 
1318
- case TOC_POSITION_BEFORE_FIRST_HEADING:
1319
- default:
1320
- $replace[0] = $html . $replace[0];
1321
- $content = $this->mb_find_replace($find, $replace, $content);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1322
  }
1323
  }
1324
  }
@@ -1360,16 +1385,12 @@ if ( !class_exists( 'toc_widget' ) ) :
1360
  $items = $custom_toc_position = '';
1361
  $find = $replace = array();
1362
 
 
1363
  $post = get_post( $wp_query->post->ID );
1364
  $custom_toc_position = strpos( $post->post_content, '[toc]' ); // at this point, shortcodes haven't run yet so we can't search for <!--TOC-->
1365
 
1366
- if (
1367
- $tic->is_eligible() ||
1368
- $custom_toc_position !== false
1369
- ) {
1370
 
1371
- $toc_options = $tic->get_options();
1372
-
1373
  extract( $args );
1374
 
1375
  $items = $tic->extract_headings( &$find, &$replace, $post->post_content );
@@ -1424,7 +1445,6 @@ if ( !class_exists( 'toc_widget' ) ) :
1424
 
1425
  $defaults = array(
1426
  'title' => ''
1427
- //'hide_inline' => $toc_options['show_toc_in_widget_only']
1428
  );
1429
  $instance = wp_parse_args( (array)$instance, $defaults );
1430
 
76
  $this->path = dirname( WP_PLUGIN_URL . '/' . plugin_basename( __FILE__ ) );
77
  $this->show_toc = true;
78
  $this->exclude_post_types = array( 'attachment', 'revision', 'nav_menu_item', 'safecss' );
79
+ $this->collision_collector = array();
80
 
81
  // get options
82
  $defaults = array( // default options
473
  ?>
474
  <div id='toc' class='wrap'>
475
  <div id="icon-options-general" class="icon32"><br /></div>
476
+ <h2><?php _e('Table of Contents Plus', 'toc+'); ?></h2>
477
  <?php echo $msg; ?>
478
  <form method="post" action="<?php echo htmlentities('?page=' . $_GET['page'] . '&update'); ?>">
479
  <?php wp_nonce_field( plugin_basename(__FILE__), 'toc-admin-options' ); ?>
587
  <option value="400px"<?php if ( '400px' == $this->options['width'] ) echo ' selected="selected"'; ?>><?php _e('400px'); ?></option>
588
  </optgroup>
589
  <optgroup label="<?php _e('Relative', 'toc+'); ?>">
590
+ <option value="Auto"<?php if ( 'Auto' == $this->options['width'] ) echo ' selected="selected"'; ?>><?php _e('Auto'); ?></option>
591
  <option value="25%"<?php if ( '25%' == $this->options['width'] ) echo ' selected="selected"'; ?>><?php _e('25%'); ?></option>
592
  <option value="33%"<?php if ( '33%' == $this->options['width'] ) echo ' selected="selected"'; ?>><?php _e('33%'); ?></option>
593
  <option value="50%"<?php if ( '50%' == $this->options['width'] ) echo ' selected="selected"'; ?>><?php _e('50%'); ?></option>
926
  else
927
  echo $this->options['width_custom'] . $this->options['width_custom_units'];
928
  echo ";\n";
929
+ if ( $this->options['width'] == 'Auto' )
930
+ echo ' display: table;' . "\n";
931
  }
932
 
933
  if ( '95%' != $this->options['font_size'] . $this->options['font_size_units'] ) {
1017
  '_',
1018
  $return
1019
  );
1020
+
1021
+ // remove trailing - and _
1022
+ $return = rtrim( $return, '-_' );
1023
 
1024
  // if blank, then prepend with the fragment prefix
1025
  // blank anchors normally appear on sites that don't use the latin charset
1028
  }
1029
  }
1030
 
1031
+ if ( array_key_exists($return, $this->collision_collector) ) {
1032
+ $this->collision_collector[$return]++;
1033
+ $return .= '-' . $this->collision_collector[$return];
1034
  }
1035
  else
1036
+ $this->collision_collector[$return] = 1;
1037
 
1038
  return $return;
1039
  }
1047
  $numbered_items_min = null;
1048
 
1049
  // reset the internal collision collection
1050
+ $this->collision_collector = array();
1051
 
1052
  // find the minimum heading to establish our baseline
1053
  for ($i = 0; $i < count($matches); $i++) {
1171
  // get all headings
1172
  // the html spec allows for a maximum of 6 heading depths
1173
  if ( preg_match_all('/(<h([1-6]{1})[^>]*>).*<\/h\2>/', $content, $matches, PREG_SET_ORDER) >= $this->options['start'] ) {
1174
+
1175
  // remove disqualified headings (if any) as defined by heading_levels
1176
  if ( count($this->options['heading_levels']) != 6 ) {
1177
  $new_matches = array();
1219
  /**
1220
  * Returns true if the table of contents is eligible to be printed, false otherwise.
1221
  */
1222
+ public function is_eligible( $shortcode_used = false )
1223
  {
1224
  global $post;
1225
+
1226
+ // if the shortcode was used, this bypasses many of the global options
1227
+ if ( $shortcode_used !== false ) {
1228
+ // shortcode is used, make sure it adheres to the exclude from
1229
+ // homepage option if we're on the homepage
1230
+ if ( !$this->options['include_homepage'] && is_front_page() )
1231
+ return false;
1232
+ else
1233
+ return true;
1234
+ }
1235
+ else {
1236
+ if (
1237
+ ( in_array(get_post_type($post), $this->options['auto_insert_post_types']) && $this->show_toc && !is_search() && !is_archive() && !is_front_page() ) ||
1238
+ ( $this->options['include_homepage'] && is_front_page() )
1239
+ )
1240
+ return true;
1241
+ else
1242
+ return false;
1243
+ }
1244
  }
1245
 
1246
 
1250
  $items = $css_classes = $anchor = '';
1251
  $custom_toc_position = strpos($content, '<!--TOC-->');
1252
  $find = $replace = array();
1253
+
1254
+ // reset the internal collision collection as the_content may have been triggered elsewhere
1255
+ // eg by themes or other plugins that need to read in content such as metadata fields in
1256
+ // the head html tag, or to provide descriptions to twitter/facebook
1257
+ $this->collision_collector = array();
1258
 
1259
+ if ( $this->is_eligible($custom_toc_position) ) {
1260
+
 
 
1261
  $items = $this->extract_headings( &$find, &$replace, $content );
1262
 
1263
+ if ( $items ) {
1264
+ // do we display the toc within the content or has the user opted
1265
+ // to only show it in the widget? if so, then we still need to
1266
+ // make the find/replace call to insert the anchors
1267
+ if ( $this->options['show_toc_in_widget_only'] ) {
1268
+ $content = $this->mb_find_replace($find, $replace, $content);
1269
+ }
1270
+ else {
1271
 
1272
+ // wrapping css classes
1273
+ switch( $this->options['wrapping'] ) {
1274
+ case TOC_WRAPPING_LEFT:
1275
+ $css_classes .= ' toc_wrap_left';
1276
+ break;
1277
+
1278
+ case TOC_WRAPPING_RIGHT:
1279
+ $css_classes .= ' toc_wrap_right';
1280
+ break;
1281
 
1282
+ case TOC_WRAPPING_NONE:
1283
+ default:
1284
+ // do nothing
1285
+ }
 
 
 
 
 
 
1286
 
1287
+ // colour themes
1288
+ switch ( $this->options['theme'] ) {
1289
+ case TOC_THEME_LIGHT_BLUE:
1290
+ $css_classes .= ' toc_light_blue';
1291
+ break;
1292
 
1293
+ case TOC_THEME_WHITE:
1294
+ $css_classes .= ' toc_white';
1295
+ break;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1296
 
1297
+ case TOC_THEME_BLACK:
1298
+ $css_classes .= ' toc_black';
1299
+ break;
1300
 
1301
+ case TOC_THEME_TRANSPARENT:
1302
+ $css_classes .= ' toc_transparent';
1303
+ break;
1304
+
1305
+ case TOC_THEME_GREY:
1306
+ default:
1307
+ // do nothing
1308
+ }
1309
+
1310
+ // bullets?
1311
+ if ( $this->options['bullet_spacing'] )
1312
+ $css_classes .= ' have_bullets';
1313
+ else
1314
+ $css_classes .= ' no_bullets';
1315
+
1316
+ $css_classes = trim($css_classes);
1317
+
1318
+ // an empty class="" is invalid markup!
1319
+ if ( !$css_classes ) $css_classes = ' ';
1320
+
1321
+ // add container, toc title and list items
1322
+ $html = '<div id="toc_container" class="' . $css_classes . '">';
1323
+ if ( $this->options['show_heading_text'] ) $html .= '<p class="toc_title">' . htmlentities( $this->options['heading_text'], ENT_COMPAT, 'UTF-8' ) . '</p>';
1324
+ $html .= '<ul class="toc_list">' . $items . '</ul></div>' . "\n";
1325
+
1326
+ if ( $custom_toc_position !== false ) {
1327
+ $find[] = '<!--TOC-->';
1328
+ $replace[] = $html;
1329
+ $content = $this->mb_find_replace($find, $replace, $content);
1330
+ }
1331
+ else {
1332
+ if ( count($find) > 0 ) {
1333
+ switch ( $this->options['position'] ) {
1334
+ case TOC_POSITION_TOP:
1335
+ $content = $html . $this->mb_find_replace($find, $replace, $content);
1336
+ break;
1337
+
1338
+ case TOC_POSITION_BOTTOM:
1339
+ $content = $this->mb_find_replace($find, $replace, $content) . $html;
1340
+ break;
1341
+
1342
+ case TOC_POSITION_BEFORE_FIRST_HEADING:
1343
+ default:
1344
+ $replace[0] = $html . $replace[0];
1345
+ $content = $this->mb_find_replace($find, $replace, $content);
1346
+ }
1347
  }
1348
  }
1349
  }
1385
  $items = $custom_toc_position = '';
1386
  $find = $replace = array();
1387
 
1388
+ $toc_options = $tic->get_options();
1389
  $post = get_post( $wp_query->post->ID );
1390
  $custom_toc_position = strpos( $post->post_content, '[toc]' ); // at this point, shortcodes haven't run yet so we can't search for <!--TOC-->
1391
 
1392
+ if ( $tic->is_eligible($custom_toc_position) ) {
 
 
 
1393
 
 
 
1394
  extract( $args );
1395
 
1396
  $items = $tic->extract_headings( &$find, &$replace, $post->post_content );
1445
 
1446
  $defaults = array(
1447
  'title' => ''
 
1448
  );
1449
  $instance = wp_parse_args( (array)$instance, $defaults );
1450