From 42297f797f1c4d8e85b9924785c10b231cd5c870 Mon Sep 17 00:00:00 2001
From: Erick Hitter <ehitter@gmail.com>
Date: Mon, 3 Mar 2014 19:29:49 -0800
Subject: [PATCH] Version 0.2: paging by word

Build on work by @bendoh merged in f96afe5397 and implement two paging options as toggles in the UI. Also makes the approach to applying the various paging types more modular and a bit easier to follow.

Lastly, WP coding standards. There's lots to clean up, so I only dealt with those bits I actually touched in the aforementioned work.
---
 automatically-paginate-posts.php | 191 ++++++++++++++++++-------------
 readme.txt                       |   8 +-
 2 files changed, 119 insertions(+), 80 deletions(-)

diff --git a/automatically-paginate-posts.php b/automatically-paginate-posts.php
index 611d7f7..6b506ab 100644
--- a/automatically-paginate-posts.php
+++ b/automatically-paginate-posts.php
@@ -30,13 +30,17 @@ class Automatically_Paginate_Posts {
 	private $post_types_default = array( 'post' );
 
 	private $num_pages;
-	private $num_pages_default = 2;
-	private $num_words_default = '';
+	private $paging_type_default = 'pages';
+	private $num_pages_default   = 2;
+	private $num_words_default   = '';
 
-	//Ensure option names match values in this::uninstall
-	private $option_name_post_types = 'autopaging_post_types';
-	private $option_name_num_pages = 'autopaging_num_pages';
-	private $option_name_num_words = 'autopaging_num_words';
+	private $paging_types_allowed = array( 'pages', 'words' );
+
+	// Ensure option names match values in this::uninstall
+	private $option_name_post_types  = 'autopaging_post_types';
+	private $option_name_paging_type = 'pages';
+	private $option_name_num_pages   = 'autopaging_num_pages';
+	private $option_name_num_words   = 'autopaging_num_words';
 
 	private $meta_key_disable_autopaging = '_disable_autopaging';
 
@@ -94,6 +98,7 @@ class Automatically_Paginate_Posts {
 	 */
 	public function uninstall() {
 		delete_option( 'autopaging_post_types' );
+		delete_option( 'autopaging_paging_type' );
 		delete_option( 'autopaging_num_pages' );
 		delete_option( 'autopaging_num_words' );
 	}
@@ -122,13 +127,15 @@ class Automatically_Paginate_Posts {
 	 */
 	public function action_admin_init() {
 		register_setting( 'reading', $this->option_name_post_types, array( $this, 'sanitize_supported_post_types' ) );
+		register_setting( 'reading', $this->option_name_paging_type, array( $this, 'sanitize_paging_type' ) );
 		register_setting( 'reading', $this->option_name_num_pages, array( $this, 'sanitize_num_pages' ) );
 		register_setting( 'reading', $this->option_name_num_words, array( $this, 'sanitize_num_words' ) );
 
 		add_settings_section( 'autopaging', __( 'Automatically Paginate Posts', 'autopaging' ), '__return_false', 'reading' );
 		add_settings_field( 'autopaging-post-types', __( 'Supported post types:', 'autopaging' ), array( $this, 'settings_field_post_types' ), 'reading', 'autopaging' );
-		add_settings_field( 'autopaging-num-pages', __( 'Number of pages to split content into:', 'autopaging' ), array( $this, 'settings_field_num_pages' ), 'reading', 'autopaging' );
-		add_settings_field( 'autopaging-num-words', __( 'Number of words for each page:', 'autopaging' ), array( $this, 'settings_field_num_words' ), 'reading', 'autopaging' );
+		add_settings_field( 'autopaging-paging-type', __( 'Split post by:', 'autopaging' ), array( $this, 'settings_field_paging_type' ), 'reading', 'autopaging' );
+		// add_settings_field( 'autopaging-num-pages', __( 'Number of pages to split content into:', 'autopaging' ), array( $this, 'settings_field_num_pages' ), 'reading', 'autopaging' );
+		// add_settings_field( 'autopaging-num-words', __( 'Number of words for each page:', 'autopaging' ), array( $this, 'settings_field_num_words' ), 'reading', 'autopaging' );
 	}
 
 	/**
@@ -187,6 +194,45 @@ class Automatically_Paginate_Posts {
 		return $post_types_sanitized;
 	}
 
+	/**
+	 * Render option to choose paging type and options for that type
+	 *
+	 * @uses get_option()
+	 * @uses esc_attr()
+	 * @uses checked()
+	 * @return string
+	 */
+	public function settings_field_paging_type() {
+		$paging_type = get_option( $this->option_name_paging_type, $this->paging_type_default );
+		if ( ! in_array( $paging_type, $this->paging_types_allowed ) ) {
+			$paging_type = $this->paging_type_default;
+		}
+
+		$labels = array(
+			'pages' => __( 'Pages', 'autopaging' ),
+			'words' => __( 'Words', 'autopaging' ),
+		);
+
+		foreach ( $this->paging_types_allowed as $type ) :
+			$type_escaped = esc_attr( $type );
+			$func = 'settings_field_num_' . $type;
+			?>
+			<p><input type="radio" name="<?php echo esc_attr( $this->option_name_paging_type ); ?>" id="autopaging-type-<?php echo $type_escaped; ?>" value="<?php echo $type_escaped; ?>"<?php checked( $type, $paging_type ); ?> /> <label for="autopaging-type-<?php echo $type_escaped; ?>">
+				<strong><?php echo $labels[ $type ]; ?></strong>: <?php $this->{$func}(); ?>
+			</label></p>
+		<?php endforeach;
+	}
+
+	/**
+	 * Validate chosen paging type against allowed values
+	 *
+	 * @param string
+	 * @return string
+	 */
+	public function sanitize_paging_type( $type ) {
+		return in_array( $type, $this->paging_types_allowed ) ? $type : $this->paging_type_default;
+	}
+
 	/**
 	 * Render dropdown for choosing number of pages to break content over
 	 *
@@ -218,7 +264,7 @@ class Automatically_Paginate_Posts {
 	}
 
 	/**
-	 * Render dropdown for choosing number of pages to break content over
+	 * Render input field for specifying approximate number of words each page should contain
 	 *
 	 * @uses get_option, apply_filters, esc_attr, selected
 	 * @return string
@@ -227,25 +273,26 @@ class Automatically_Paginate_Posts {
 		$num_words = apply_filters( 'autopaging_num_words', get_option( $this->option_name_num_words ) )
 		?>
 			<input name="<?php echo esc_attr( $this->option_name_num_words ); ?>" value="<?php echo esc_attr( $num_words ); ?>" size="4" />
-	
-			<p class="description">If set, each page will contain approximately this many words, more or less depending on paragraph lengths, and Number of pages will be ignored.</p>
+
+			<p class="description">If set, each page will contain approximately this many words, more or less depending on paragraph lengths.</p>
 		<?php
 	}
 
 	/**
-	 * Sanitize number of words input. No fewer than 10 (by default, filterable by autopaging_min_num_words)
+	 * Sanitize number of words input. No fewer than 10 by default, filterable by autopaging_max_num_words
 	 *
-	 * @param int $numwords
+	 * @param int $num_words
 	 * @uses apply_filters
 	 * @return int
 	 */
 	public function sanitize_num_words( $num_words ) {
-		$num_words = apply_filters( 'autopaging_num_words', $num_words );
+		$num_words = absint( $num_words );
 
-		if( empty( $num_words ) )
-			return '';	
+		if ( ! $num_words ) {
+			return 0;
+		}
 
-		return max( 1, (int) $num_words );
+		return max( $num_words, apply_filters( 'autopaging_min_num_words', 10 ) );
 	}
 
 	/**
@@ -336,71 +383,67 @@ class Automatically_Paginate_Posts {
 						//Explode content at double (or more) line breaks
 						$content = explode( "\r\n\r\n", $content );
 
-						//Aggregate paragraphs
-						if( !empty( $num_words ) ) {
-							$word_counter = 0;
-
-							//Aggregate num_words paged content here
-							$aggregate = array();
-							$aggregate_index = 0;
-
-							//Collapse together paragraph according to number of words per page
-							foreach( $content as $index => $paragraph ) {
-								$paragraph_words = count( preg_split( '/\s+/', strip_tags( $paragraph ) ) );
-
-								if( $word_counter + $paragraph_words / 2 >= $num_words ) {
-									$aggregate_index++;
-									$word_counter = 0;
+						switch ( get_option( $this->option_name_paging_type, $this->paging_type_default ) ) {
+							case 'words' :
+								$word_counter = 0;
+
+								// Count words per paragraph and break after the paragraph that exceeds the set threshold
+								foreach ( $content as $index => $paragraph ) {
+									$paragraph_words = count( preg_split( '/\s+/', strip_tags( $paragraph ) ) );
+									$word_counter += $paragraph_words;
+
+									if ( $word_counter >= $num_words ) {
+										$content[ $index ] .= '<!--nextpage-->';
+										$word_counter = 0;
+									} else {
+										continue;
+									}
 								}
 
-								if( !isset( $aggregate[$aggregate_index] ) )
-									$aggregate[$aggregate_index] = '';
-
-								$aggregate[$aggregate_index] .= $paragraph . "\r\n\r\n";
-
-								$word_counter += $paragraph_words;
+								unset( $word_counter );
+								unset( $index );
+								unset( $paragraph );
+								unset( $paragraph_words );
 
-								if( $word_counter > $num_words ) {
-									$aggregate_index++;
-									$word_counter = 0;
-								}
-							}
+								break;
 
-							//Pretend the aggregated paragraphs based on max_words
-							//are the original set
-							$content = $aggregate;
+							case 'pages' :
+							default :
+								//Count number of paragraphs content was exploded to
+								$count = count( $content );
 
-							//Override num_pages
-							$num_pages = count( $content );
+								//Determine when to insert Quicktag
+								$insert_every = $count / $num_pages;
+								$insert_every_rounded = round( $insert_every );
 
-							unset( $word_counter );
-							unset( $aggregate );
-							unset( $aggregate_index );
-						}
+								//If number of pages is greater than number of paragraphs, put each paragraph on its own page
+								if ( $num_pages > $count ) {
+									$insert_every_rounded = 1;
+								}
 
-						//Count number of paragraphs content was exploded to
-						$count = count( $content );
+								//Set initial counter position.
+								$i = $count - 1 == $num_pages ? 2 : 1;
 
-						//Determine when to insert Quicktag
-						$insert_every = $count / $num_pages;
-						$insert_every_rounded = round( $insert_every );
+								//Loop through content pieces and append Quicktag as is appropriate
+								foreach ( $content as $key => $value ) {
+									if ( $key + 1 == $count ) {
+										break;
+									}
 
-						//If number of pages is greater than number of paragraphs, put each paragraph on its own page
-						if ( $num_pages > $count )
-							$insert_every_rounded = 1;
+									if ( ( $key + 1 ) == ( $i * $insert_every_rounded ) ) {
+										$content[ $key ] = $content[ $key ] . '<!--nextpage-->';
+										$i++;
+									}
+								}
 
-						//Set initial counter position.
-						$i = $count - 1 == $num_pages ? 2 : 1;
+								//Clean up
+								unset( $count );
+								unset( $insert_every );
+								unset( $insert_every_rounded );
+								unset( $key );
+								unset( $value );
 
-						//Loop through content pieces and append Quicktag as is appropriate
-						foreach( $content as $key => $value ) {
-							if ( $key + 1 == $count )
 								break;
-
-							if ( ( $key + 1 ) == ( $i * $insert_every_rounded ) ) {
-								$content[ $key ] = $content[ $key ] . '<!--nextpage-->';
-								$i++;
-							}
 						}
 
 						//Reunite content
@@ -408,17 +451,11 @@ class Automatically_Paginate_Posts {
 
 						//And, overwrite the original content
 						$the_post->post_content = $content;
-
-						//Clean up
-						unset( $count );
-						unset( $insert_every );
-						unset( $insert_every_rounded );
-						unset( $key );
-						unset( $value );
 					}
 
 					//Lastly, clean up.
 					unset( $num_pages );
+					unset( $num_words );
 					unset( $content );
 					unset( $count );
 				}
diff --git a/readme.txt b/readme.txt
index 306b06f..f0b45c4 100644
--- a/readme.txt
+++ b/readme.txt
@@ -3,8 +3,8 @@ Contributors: ethitter, thinkoomph, bendoh
 Donate link:
 Tags: paginate, nextpage, Quicktag
 Requires at least: 3.4
-Tested up to: 3.8
-Stable tag: 0.1
+Tested up to: 3.9
+Stable tag: 0.2
 License: GPLv2 or later
 License URI: http://www.gnu.org/licenses/gpl-2.0.html
 
@@ -40,8 +40,10 @@ You can also use the filter `autopaging_post_types` to add support by appending
 = What filters does this plugin include? =
 * `autopaging_post_types` - modify the post types supported by this plugin. Will override the values set under Settings > Reading.
 * `autopaging_num_pages_default` - modify the default number of pages over which a post is displayed. Will override the value set under Settings > Reading.
-* `autopaging_max_num_pages` - override the maximum number of pages available in the settings page dropdown.
+* `autopaging_max_num_pages` - override the maximum number of pages available in the settings page dropdown when the paging type is "pages".
+* `autopaging_max_num_words` - override the minimum number of words allowed per page page when the paging type is "words".
 * `autopaging_num_pages` - change the number of pages content is displayed on at runtime. Filter provides access to the full post object in addition to the number of pages.
+* `autopaging_num_words` - change the number of words displayed per page at runtime. Filter provides access to the full post object in addition to the number of words.
 
 == Changelog ==
 
-- 
GitLab