view-all-posts-pages.php 26.5 KB
Newer Older
Erick Hitter's avatar
PHPCS  
Erick Hitter committed
1
<?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
2
/**
Erick Hitter's avatar
PHPCS  
Erick Hitter committed
3 4
 * View All Posts Pages
 *
5 6 7 8 9 10 11
 * Plugin Name:     View All Posts Pages
 * Plugin URI:      http://www.oomphinc.com/plugins-modules/view-all-posts-pages/
 * Description:     Provides a "view all" (single page) option for posts, pages, and custom post types paged using WordPress' <a href="http://codex.wordpress.org/Write_Post_SubPanel#Quicktags" target="_blank"><code>&lt;!--nextpage--&gt;</code> Quicktag</a> (multipage posts).
 * Author:          Erick Hitter & Oomph, Inc.
 * Author URI:      http://www.oomphinc.com/
 * Text Domain:     view_all_posts_pages
 * Domain Path:     /languages
12
 * Version:         0.9.3
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
 *
 * @package         View_All_Posts_Pages
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */
30

Erick Hitter's avatar
PHPCS  
Erick Hitter committed
31 32 33 34
/**
 * Class view_all_posts_pages
 */
class view_all_posts_pages { // phpcs:ignore PEAR.NamingConventions.ValidClassName, Generic.Classes.OpeningBraceSameLine.ContentAfterBrace
Erick Hitter's avatar
Erick Hitter committed
35 36
	/**
	 * Singleton
Erick Hitter's avatar
PHPCS  
Erick Hitter committed
37 38
	 *
	 * @var self
Erick Hitter's avatar
Erick Hitter committed
39 40 41 42 43
	 */
	private static $__instance = null;

	/**
	 * Class variables
Erick Hitter's avatar
PHPCS  
Erick Hitter committed
44 45
	 *
	 * @var string
Erick Hitter's avatar
Erick Hitter committed
46
	 */
47 48
	private $query_var = 'view-all';

Erick Hitter's avatar
PHPCS  
Erick Hitter committed
49 50 51 52 53
	/**
	 * Namespace.
	 *
	 * @var string
	 */
54 55
	private $ns = 'view_all_posts_pages';

Erick Hitter's avatar
PHPCS  
Erick Hitter committed
56 57 58 59 60 61 62 63 64 65 66 67
	/**
	 * Option name.
	 *
	 * @var string
	 */
	private $settings_key = 'vapp';

	/**
	 * Default settings
	 *
	 * @var array|null
	 */
68
	private $settings_defaults = null;
69

Erick Hitter's avatar
PHPCS  
Erick Hitter committed
70 71 72 73 74
	/**
	 * Option indicating admin notice was dismissed.
	 *
	 * @var string
	 */
75 76
	private $notice_key = 'vapp_admin_notice_dismissed';

Erick Hitter's avatar
Erick Hitter committed
77 78 79 80 81 82 83 84 85 86 87 88 89
	/**
	 * Silence is golden
	 */
	private function __construct() {}

	/**
	 * Implement singleton
	 *
	 * @uses self::setup
	 * @return self
	 */
	public static function get_instance() {
		if ( ! is_a( self::$__instance, __CLASS__ ) ) {
Erick Hitter's avatar
Erick Hitter committed
90
			self::$__instance = new self();
Erick Hitter's avatar
Erick Hitter committed
91 92 93 94 95 96 97

			self::$__instance->setup();
		}

		return self::$__instance;
	}

98 99
	/**
	 * Register actions and filters.
Erick Hitter's avatar
Erick Hitter committed
100
	 *
Erick Hitter's avatar
Erick Hitter committed
101 102
	 * @uses register_deactivation_hook
	 * @uses add_action
103
	 */
Erick Hitter's avatar
Erick Hitter committed
104
	private function setup() {
105 106 107 108 109 110
		register_deactivation_hook( __FILE__, array( $this, 'deactivation_hook' ) );

		add_action( 'admin_init', array( $this, 'action_admin_init' ) );
		add_action( 'admin_menu', array( $this, 'action_admin_menu' ) );

		add_action( 'init', array( $this, 'action_init' ), 20 );
Erick Hitter's avatar
Erick Hitter committed
111
		add_action( 'redirect_canonical', array( $this, 'filter_redirect_canonical' ) );
112 113 114 115 116 117

		add_action( 'the_post', array( $this, 'action_the_post' ), 5 );
	}

	/**
	 * Clean up after plugin deactivation.
Erick Hitter's avatar
Erick Hitter committed
118
	 *
Erick Hitter's avatar
Erick Hitter committed
119 120
	 * @uses flush_rewrite_rules
	 * @uses delete_option
121 122 123
	 * @action register_deactivation_hook
	 */
	public function deactivation_hook() {
Erick Hitter's avatar
PHPCS  
Erick Hitter committed
124
		flush_rewrite_rules(); // phpcs:ignore WordPressVIPMinimum.Functions.RestrictedFunctions.flush_rewrite_rules_flush_rewrite_rules, WordPressVIPMinimum.VIP.RestrictedFunctions.rewrite_rules_flush_rewrite_rules
125 126 127 128 129 130 131

		delete_option( $this->settings_key );
		delete_option( $this->notice_key );
	}

	/**
	 * Register plugin option and disable rewrite rule flush warning.
Erick Hitter's avatar
Erick Hitter committed
132
	 *
Erick Hitter's avatar
Erick Hitter committed
133 134 135
	 * @uses register_setting
	 * @uses apply_filters
	 * @uses update_option
136 137 138 139 140
	 * @action admin_init
	 */
	public function action_admin_init() {
		register_setting( $this->settings_key, $this->settings_key, array( $this, 'admin_options_validate' ) );

Erick Hitter's avatar
PHPCS  
Erick Hitter committed
141 142 143 144 145
		if (
			isset( $_GET[ $this->notice_key ], $_GET[ $this->notice_key . '_nonce' ] ) &&
			wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET[ $this->notice_key . '_nonce' ] ) ), $this->notice_key ) &&
			apply_filters( 'vapp_display_rewrite_rules_notice', true )
		) {
146
			update_option( $this->notice_key, 1 );
Erick Hitter's avatar
Erick Hitter committed
147
		}
148 149 150 151
	}

	/**
	 * Determine if full post view is being requested.
Erick Hitter's avatar
Erick Hitter committed
152
	 *
153
	 * @global $wp_query
154
	 * @uses is_404
155 156 157 158
	 * @return bool
	 */
	public function is_view_all() {
		global $wp_query;
159
		return is_array( $wp_query->query ) && array_key_exists( $this->query_var, $wp_query->query ) && ! is_404();
160 161 162
	}

	/**
Erick Hitter's avatar
Erick Hitter committed
163 164 165
	 * Add rewrite endpoint, which sets query var and rewrite rules.
	 *
	 * @global $wp_rewrite
166
	 * @uses __
167 168 169 170 171
	 * @uses this::get_options
	 * @uses add_filter
	 * @uses apply_filters
	 * @uses get_option
	 * @uses add_action
172 173 174 175
	 * @uses add_rewrite_endpoint
	 * @action init
	 */
	public function action_init() {
Erick Hitter's avatar
PHPCS  
Erick Hitter committed
176
		// Populate default settings, with translation support.
177 178 179 180 181
		$this->settings_defaults = array(
			'wlp'             => true,
			'wlp_text'        => __( 'View All', 'view_all_posts_pages' ),
			'wlp_class'       => 'vapp',
			'wlp_post_types'  => array(
Erick Hitter's avatar
Erick Hitter committed
182
				'post',
183 184 185 186 187 188
			),
			'link'            => false,
			'link_position'   => 'below',
			'link_text'       => __( 'View All', 'view_all_posts_pages' ),
			'link_class'      => 'vapp',
			'link_post_types' => array(
Erick Hitter's avatar
Erick Hitter committed
189
				'post',
190 191 192 193
			),
			'link_priority'   => 10,
		);

194 195 196
		// Register additional plugin actions if settings call for them.
		$options = $this->get_options();

Erick Hitter's avatar
Erick Hitter committed
197
		if ( array_key_exists( 'wlp', $options ) && true === $options['wlp'] ) {
198
			add_filter( 'wp_link_pages_args', array( $this, 'filter_wp_link_pages_args_early' ), 0 );
Erick Hitter's avatar
Erick Hitter committed
199
		}
200

Erick Hitter's avatar
Erick Hitter committed
201 202 203
		if ( $options['link'] ) {
			add_filter( 'the_content', array( $this, 'filter_the_content_auto' ), $options['link_priority'] );
		}
204

Erick Hitter's avatar
Erick Hitter committed
205
		if ( apply_filters( 'vapp_display_rewrite_rules_notice', true ) && ! get_option( $this->notice_key ) ) {
206
			add_action( 'admin_notices', array( $this, 'action_admin_notices_activation' ) );
Erick Hitter's avatar
Erick Hitter committed
207
		}
208

Erick Hitter's avatar
PHPCS  
Erick Hitter committed
209
		// Register rewrite endpoint, which handles most of our rewrite needs.
210
		add_rewrite_endpoint( $this->query_var, EP_ALL );
Erick Hitter's avatar
Erick Hitter committed
211

Erick Hitter's avatar
PHPCS  
Erick Hitter committed
212
		// Extra rules needed if verbose page rules are requested.
Erick Hitter's avatar
Erick Hitter committed
213 214
		global $wp_rewrite;
		if ( $wp_rewrite->use_verbose_page_rules ) {
Erick Hitter's avatar
PHPCS  
Erick Hitter committed
215
			// Build regex.
Erick Hitter's avatar
Erick Hitter committed
216 217
			$regex  = substr( str_replace( $wp_rewrite->rewritecode, $wp_rewrite->rewritereplace, $wp_rewrite->permalink_structure ), 1 );
			$regex  = trailingslashit( $regex );
Erick Hitter's avatar
Erick Hitter committed
218 219
			$regex .= $this->query_var . '/?$';

Erick Hitter's avatar
PHPCS  
Erick Hitter committed
220
			// Build corresponding query string.
Erick Hitter's avatar
Erick Hitter committed
221 222 223 224 225 226 227 228 229 230 231 232 233 234
			$query = substr( str_replace( $wp_rewrite->rewritecode, $wp_rewrite->queryreplace, $wp_rewrite->permalink_structure ), 1 );
			$query = explode( '/', $query );
			$query = array_filter( $query );

			$i = 1;
			foreach ( $query as $key => $qv ) {
				$query[ $key ] .= '$matches[' . $i . ']';
				$i++;
			}

			$query[] = $this->query_var . '=1';

			$query = implode( '&', $query );

Erick Hitter's avatar
PHPCS  
Erick Hitter committed
235
			// Add rule.
Erick Hitter's avatar
Erick Hitter committed
236 237 238 239 240 241 242
			add_rewrite_rule( $regex, $wp_rewrite->index . '?' . $query, 'top' );
		}
	}

	/**
	 * Prevent canonical redirect if full-post page is requested.
	 *
Erick Hitter's avatar
PHPCS  
Erick Hitter committed
243
	 * @param string $url Canonical URL.
Erick Hitter's avatar
Erick Hitter committed
244 245
	 * @uses this::is_view_all
	 * @filter redirect_canonical
Erick Hitter's avatar
PHPCS  
Erick Hitter committed
246
	 * @return string|false
Erick Hitter's avatar
Erick Hitter committed
247 248
	 */
	public function filter_redirect_canonical( $url ) {
Erick Hitter's avatar
Erick Hitter committed
249
		if ( $this->is_view_all() ) {
Erick Hitter's avatar
Erick Hitter committed
250
			$url = false;
Erick Hitter's avatar
Erick Hitter committed
251
		}
Erick Hitter's avatar
Erick Hitter committed
252 253

		return $url;
254 255 256
	}

	/**
Erick Hitter's avatar
Erick Hitter committed
257
	 * Modify post variables to display entire post on one page.
258 259
	 *
	 * @global $pages, $more
Erick Hitter's avatar
PHPCS  
Erick Hitter committed
260
	 * @param WP_Post $post Post object.
261 262 263 264 265
	 * @uses this::is_view_all
	 * @action the_post
	 */
	public function action_the_post( $post ) {
		if ( $this->is_view_all() ) {
266
			global $pages, $more, $multipage;
267 268 269 270

			$post->post_content = str_replace( "\n<!--nextpage-->\n", "\n\n", $post->post_content );
			$post->post_content = str_replace( "\n<!--nextpage-->", "\n", $post->post_content );
			$post->post_content = str_replace( "<!--nextpage-->\n", "\n", $post->post_content );
Erick Hitter's avatar
Erick Hitter committed
271
			$post->post_content = str_replace( '<!--nextpage-->', ' ', $post->post_content );
272

Erick Hitter's avatar
Erick Hitter committed
273 274
			// phpcs:disable WordPress.WP.GlobalVariablesOverride.Prohibited
			$pages = array( $post->post_content );
275

Erick Hitter's avatar
Erick Hitter committed
276 277 278
			$more      = 1;
			$multipage = 0;
			// phpcs:enable WordPress.WP.GlobalVariablesOverride.Prohibited
279 280 281 282 283 284 285
		}
	}

	/**
	 * Add wp_link_pages arguments filter if automatic inclusion is chosen for a given post type.
	 * Automatic inclusion can be disabled by passing false through the vapp_display_link filter.
	 *
Erick Hitter's avatar
Erick Hitter committed
286
	 * @global $post
Erick Hitter's avatar
PHPCS  
Erick Hitter committed
287
	 * @param array $args wp_link_pages arguments.
Erick Hitter's avatar
Erick Hitter committed
288 289 290
	 * @uses this::get_options
	 * @uses apply_filters
	 * @uses add_filter
291 292 293 294 295 296 297 298
	 * @filter wp_link_pages
	 * @return array
	 */
	public function filter_wp_link_pages_args_early( $args ) {
		global $post;

		$options = $this->get_options();

Erick Hitter's avatar
PHPCS  
Erick Hitter committed
299
		if ( in_array( $post->post_type, $options['wlp_post_types'], true ) && apply_filters( 'vapp_display_link', true, (int) $post->ID, $options, $post ) ) {
300
			add_filter( 'wp_link_pages_args', array( $this, 'filter_wp_link_pages_args' ), 999 );
Erick Hitter's avatar
Erick Hitter committed
301
		}
302 303 304 305 306 307

		return $args;
	}

	/**
	 * Filter wp_link_pages arguments to append "View all" link to output.
Erick Hitter's avatar
Erick Hitter committed
308
	 *
Erick Hitter's avatar
Erick Hitter committed
309
	 * @global $more
Erick Hitter's avatar
PHPCS  
Erick Hitter committed
310
	 * @param array $args wp_link_pages arguments.
Erick Hitter's avatar
Erick Hitter committed
311 312 313 314
	 * @uses this::get_options
	 * @uses this::is_view_all
	 * @uses esc_attr
	 * @uses esc_url
315 316 317 318 319 320
	 * @return array
	 */
	public function filter_wp_link_pages_args( $args ) {
		$options = $this->get_options();

		if ( is_array( $options ) ) {
Erick Hitter's avatar
PHPCS  
Erick Hitter committed
321
			extract( $options, EXTR_OVERWRITE );
322

Erick Hitter's avatar
PHPCS  
Erick Hitter committed
323
			// Set global $more to false so that wp_link_pages outputs links for all pages when viewing full post page.
Erick Hitter's avatar
Erick Hitter committed
324
			if ( $this->is_view_all() ) {
Erick Hitter's avatar
Erick Hitter committed
325 326
				// phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
				$GLOBALS['more'] = false;
Erick Hitter's avatar
Erick Hitter committed
327
			}
328

Erick Hitter's avatar
Erick Hitter committed
329 330
			// Process link text, respecting pagelink parameter.
			$link_text = str_replace( '%', $wlp_text, $args['pagelink'] );
331

Erick Hitter's avatar
PHPCS  
Erick Hitter committed
332
			// View all.
Erick Hitter's avatar
Erick Hitter committed
333
			$link = ' ' . $args['link_before'];
334

Erick Hitter's avatar
Erick Hitter committed
335
			if ( $this->is_view_all() ) {
336
				$link .= '<span class="' . esc_attr( $wlp_class ) . '">' . $link_text . '</span><!-- .' . esc_attr( $wlp_class ) . ' -->';
Erick Hitter's avatar
Erick Hitter committed
337
			} else {
338
				$link .= '<a class="' . esc_attr( $wlp_class ) . '" href="' . esc_url( $this->url() ) . '">' . $link_text . '</a><!-- .' . esc_attr( $wlp_class ) . ' -->';
Erick Hitter's avatar
Erick Hitter committed
339
			}
340

Erick Hitter's avatar
Erick Hitter committed
341
			$link .= $args['link_after'] . ' ';
342

Erick Hitter's avatar
Erick Hitter committed
343
			$args['after'] = $link . $args['after'];
344 345 346 347 348 349
		}

		return $args;
	}

	/**
Erick Hitter's avatar
Erick Hitter committed
350 351
	 * Filter the content if automatic link inclusion is selected.
	 *
Erick Hitter's avatar
Erick Hitter committed
352
	 * @global $post
Erick Hitter's avatar
PHPCS  
Erick Hitter committed
353
	 * @param string $content Post content.
Erick Hitter's avatar
Erick Hitter committed
354 355 356 357 358
	 * @uses this::get_options
	 * @uses this::is_view_all
	 * @uses esc_attr
	 * @uses esc_url
	 * @uses this::url
359 360 361 362 363 364 365 366
	 * @filter the_content
	 * @return string
	 */
	public function filter_the_content_auto( $content ) {
		$options = $this->get_options();

		global $post;

Erick Hitter's avatar
Erick Hitter committed
367
		if ( ! $this->is_view_all() && is_array( $options ) && array_key_exists( 'link', $options ) && true === $options['link'] && in_array( $post->post_type, $options['link_post_types'] ) ) {
Erick Hitter's avatar
PHPCS  
Erick Hitter committed
368
			extract( $options, EXTR_OVERWRITE );
369 370 371

			$link = '<p class="vapp_wrapper"><a class="' . esc_attr( $link_class ) . '" href="' . esc_url( $this->url() ) . '">' . esc_html( $link_text ) . '</a></p><!-- .vapp_wrapper -->';

Erick Hitter's avatar
PHPCS  
Erick Hitter committed
372
			if ( 'above' === $link_position ) {
373
				$content = $link . $content;
Erick Hitter's avatar
PHPCS  
Erick Hitter committed
374
			} elseif ( 'below' === $link_position ) {
375
				$content = $content . $link;
Erick Hitter's avatar
PHPCS  
Erick Hitter committed
376
			} elseif ( 'both' === $link_position ) {
377
				$content = $link . $content . $link;
Erick Hitter's avatar
Erick Hitter committed
378
			}
379 380 381 382 383 384 385
		}

		return $content;
	}

	/**
	 * Generate URL
Erick Hitter's avatar
Erick Hitter committed
386
	 *
Erick Hitter's avatar
Erick Hitter committed
387 388
	 * @global $post
	 * @global $wp_rewrite
Erick Hitter's avatar
PHPCS  
Erick Hitter committed
389
	 * @param int|false $post_id Post ID.
Erick Hitter's avatar
Erick Hitter committed
390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406
	 * @uses is_singular
	 * @uses in_the_loop
	 * @uses get_permalink
	 * @uses is_home
	 * @uses is_front_page
	 * @uses home_url
	 * @uses is_category
	 * @uses get_category_link
	 * @uses get_query_var
	 * @uses is_tag
	 * @uses get_tag_link
	 * @uses is_tax
	 * @uses get_queried_object
	 * @uses get_term_link
	 * @uses path_join
	 * @uses trailingslashit
	 * @uses add_query_arg
407 408 409 410 411
	 * @return string or bool
	 */
	public function url( $post_id = false ) {
		$link = false;

Erick Hitter's avatar
PHPCS  
Erick Hitter committed
412
		// Get link base specific to page type being viewed.
413 414 415 416 417 418 419 420
		if ( is_singular() || in_the_loop() ) {
			$post_id = intval( $post_id );

			if ( ! $post_id ) {
				global $post;
				$post_id = $post->ID;
			}

Erick Hitter's avatar
Erick Hitter committed
421
			if ( ! $post_id ) {
422
				return false;
Erick Hitter's avatar
Erick Hitter committed
423
			}
424 425

			$link = get_permalink( $post_id );
Erick Hitter's avatar
Erick Hitter committed
426
		} elseif ( is_home() || is_front_page() ) {
427
			$link = home_url( '/' );
Erick Hitter's avatar
Erick Hitter committed
428
		} elseif ( is_category() ) {
429
			$link = get_category_link( get_query_var( 'cat' ) );
Erick Hitter's avatar
Erick Hitter committed
430
		} elseif ( is_tag() ) {
431
			$link = get_tag_link( get_query_var( 'tag_id' ) );
Erick Hitter's avatar
PHPCS  
Erick Hitter committed
432
		} elseif ( is_tax() ) {
433 434
			$queried_object = get_queried_object();

Erick Hitter's avatar
Erick Hitter committed
435 436 437
			if ( is_object( $queried_object ) && property_exists( $queried_object, 'taxonomy' ) && property_exists( $queried_object, 'term_id' ) ) {
				$link = get_term_link( (int) $queried_object->term_id, $queried_object->taxonomy );
			}
438 439
		}

Erick Hitter's avatar
PHPCS  
Erick Hitter committed
440
		// If link base is set, build link.
441 442 443 444 445 446
		if ( false !== $link ) {
			global $wp_rewrite;

			if ( $wp_rewrite->using_permalinks() ) {
				$link = path_join( $link, $this->query_var );

Erick Hitter's avatar
Erick Hitter committed
447
				if ( $wp_rewrite->use_trailing_slashes ) {
448
					$link = trailingslashit( $link );
Erick Hitter's avatar
Erick Hitter committed
449 450
				}
			} else {
451 452 453 454 455 456 457 458 459
				$link = add_query_arg( $this->query_var, 1, $link );
			}
		}

		return $link;
	}

	/**
	 * Add menu item for options page
Erick Hitter's avatar
Erick Hitter committed
460
	 *
Erick Hitter's avatar
Erick Hitter committed
461 462
	 * @uses __
	 * @uses add_options_page
463 464 465
	 * @action admin_menu
	 */
	public function action_admin_menu() {
Erick Hitter's avatar
PHPCS  
Erick Hitter committed
466
		/* translators: 1: Plugin name. */
467
		add_options_page( sprintf( __( '%s Options', 'view_all_posts_pages' ), "View All Post's Pages" ), "View All Post's Pages", 'manage_options', $this->ns, array( $this, 'admin_options' ) );
468 469 470 471
	}

	/**
	 * Render options page
Erick Hitter's avatar
Erick Hitter committed
472
	 *
Erick Hitter's avatar
Erick Hitter committed
473 474 475 476 477 478 479 480
	 * @uses settings_fields
	 * @uses this::get_options
	 * @uses this::post_types_array
	 * @uses __
	 * @uses _e
	 * @uses checked
	 * @uses esc_attr
	 * @uses submit_button
481 482
	 */
	public function admin_options() {
Erick Hitter's avatar
Erick Hitter committed
483
		?>
484 485 486 487 488 489 490 491 492 493 494
		<div class="wrap">
			<h2>View All Post's Pages</h2>

			<form action="options.php" method="post">
				<?php
					settings_fields( $this->settings_key );
					$options = $this->get_options();

					$post_types = $this->post_types_array();
				?>

Erick Hitter's avatar
PHPCS  
Erick Hitter committed
495 496 497 498 499 500
				<h3>
					<?php
					/* translators: 1: WordPress function name. */
						printf( wp_kses_post( __( '%s Options', 'view_all_posts_pages' ) ), '<em>wp_link_pages</em>' );
					?>
				</h3>
501

Erick Hitter's avatar
PHPCS  
Erick Hitter committed
502
				<p class="description"><?php esc_html_e( 'A "view all" link can be appended to WordPress\' standard page navigation using the options below.', 'view_all_posts_pages' ); ?></p>
503 504 505

				<table class="form-table">
					<tr>
Erick Hitter's avatar
PHPCS  
Erick Hitter committed
506
						<th scope="row"><?php esc_html_e( 'Automatically append link to post\'s page navigation?', 'view_all_posts_pages' ); ?></th>
507
						<td>
Erick Hitter's avatar
PHPCS  
Erick Hitter committed
508 509
							<input type="radio" name="<?php echo esc_attr( $this->settings_key ); ?>[wlp]" id="wlp-true" value="1"<?php checked( $options['wlp'], true, true ); ?> /> <label for="wlp-true"><?php esc_html_e( 'Yes', 'view_all_posts_pages' ); ?></label><br />
							<input type="radio" name="<?php echo esc_attr( $this->settings_key ); ?>[wlp]" id="wlp-false" value="0"<?php checked( $options['wlp'], false, true ); ?> /> <label for="wlp-false"><?php esc_html_e( 'No', 'view_all_posts_pages' ); ?></label>
510 511 512
						</td>
					</tr>
					<tr>
Erick Hitter's avatar
PHPCS  
Erick Hitter committed
513
						<th scope="row"><label for="wlp_text"><?php esc_html_e( 'Link text:', 'view_all_posts_pages' ); ?></label></th>
514
						<td>
Erick Hitter's avatar
PHPCS  
Erick Hitter committed
515
							<input type="text" name="<?php echo esc_attr( $this->settings_key ); ?>[wlp_text]" id="wlp_text" value="<?php echo esc_attr( $options['wlp_text'] ); ?>" class="regular-text" />
516 517 518
						</td>
					</tr>
					<tr>
Erick Hitter's avatar
PHPCS  
Erick Hitter committed
519
						<th scope="row"><label for="wlp_class"><?php esc_html_e( 'Link\'s CSS class(es):', 'view_all_posts_pages' ); ?></label></th>
520
						<td>
Erick Hitter's avatar
PHPCS  
Erick Hitter committed
521
							<input type="text" name="<?php echo esc_attr( $this->settings_key ); ?>[wlp_class]" id="wlp_class" value="<?php echo esc_attr( $options['wlp_class'] ); ?>" class="regular-text" />
522

Erick Hitter's avatar
PHPCS  
Erick Hitter committed
523
							<p class="description"><?php esc_html_e( 'Be aware that Internet Explorer will only interpret the first two CSS classes.', 'view_all_posts_pages' ); ?></p>
524 525 526
						</td>
					</tr>
					<tr>
Erick Hitter's avatar
PHPCS  
Erick Hitter committed
527
						<th scope="row"><?php esc_html_e( 'Display automatically on:', 'view_all_posts_pages' ); ?></th>
528 529
						<td>
							<?php foreach ( $post_types as $post_type ) : ?>
Erick Hitter's avatar
PHPCS  
Erick Hitter committed
530 531 532 533 534 535 536 537
								<input type="checkbox" name="<?php echo esc_attr( $this->settings_key ); ?>[wlp_post_types][]" id="wlp-pt-<?php echo esc_attr( $post_type->name ); ?>" value="<?php echo esc_attr( $post_type->name ); ?>"
									<?php
									if ( in_array( $post_type->name, $options['wlp_post_types'], true ) ) {
										echo ' checked="checked"';
									}
									?>
								/>
								<label for="wlp-pt-<?php echo esc_attr( $post_type->name ); ?>"><?php echo esc_html( $post_type->labels->name ); ?></label><br />
538 539 540 541 542
							<?php endforeach; ?>
						</td>
					</tr>
				</table>

Erick Hitter's avatar
PHPCS  
Erick Hitter committed
543
				<h3><?php esc_html_e( 'Standalone Link Options', 'view_all_posts_pages' ); ?></h3>
544

Erick Hitter's avatar
PHPCS  
Erick Hitter committed
545
				<p class="description"><?php esc_html_e( 'In addition to appending the "view all" link to WordPress\' standard navigation, link(s) can be added above and below post content.', 'view_all_posts_pages' ); ?></p>
546 547 548

				<table class="form-table">
					<tr>
Erick Hitter's avatar
PHPCS  
Erick Hitter committed
549
						<th scope="row"><?php esc_html_e( 'Automatically add links based on settings below?', 'view_all_posts_pages' ); ?></th>
550
						<td>
Erick Hitter's avatar
PHPCS  
Erick Hitter committed
551 552
							<input type="radio" name="<?php echo esc_attr( $this->settings_key ); ?>[link]" id="link-true" value="1"<?php checked( $options['link'], true, true ); ?> /> <label for="link-true"><?php esc_html_e( 'Yes', 'view_all_posts_pages' ); ?></label><br />
							<input type="radio" name="<?php echo esc_attr( $this->settings_key ); ?>[link]" id="link-false" value="0"<?php checked( $options['link'], false, true ); ?> /> <label for="link-false"><?php esc_html_e( 'No', 'view_all_posts_pages' ); ?></label>
553 554 555
						</td>
					</tr>
					<tr>
Erick Hitter's avatar
PHPCS  
Erick Hitter committed
556
						<th scope="row"><?php esc_html_e( 'Automatically place link:', 'view_all_posts_pages' ); ?></th>
557
						<td>
Erick Hitter's avatar
PHPCS  
Erick Hitter committed
558 559 560
							<input type="radio" name="<?php echo esc_attr( $this->settings_key ); ?>[link_position]" id="link_position-above" value="above"<?php checked( $options['link_position'], 'above', true ); ?> /> <label for="link_position-above"><?php esc_html_e( 'Above content', 'view_all_posts_pages' ); ?></label><br />
							<input type="radio" name="<?php echo esc_attr( $this->settings_key ); ?>[link_position]" id="link_position-below" value="below"<?php checked( $options['link_position'], 'below', true ); ?> /> <label for="link_position-below"><?php esc_html_e( 'Below content', 'view_all_posts_pages' ); ?></label><br />
							<input type="radio" name="<?php echo esc_attr( $this->settings_key ); ?>[link_position]" id="link_position-both" value="both"<?php checked( $options['link_position'], 'both', true ); ?> /> <label for="link_position-both"><?php esc_html_e( 'Above and below content', 'view_all_posts_pages' ); ?></label>
561 562 563
						</td>
					</tr>
					<tr>
Erick Hitter's avatar
PHPCS  
Erick Hitter committed
564
						<th scope="row"><?php esc_html_e( 'Display automatically on:', 'view_all_posts_pages' ); ?></th>
565 566
						<td>
							<?php foreach ( $post_types as $post_type ) : ?>
Erick Hitter's avatar
PHPCS  
Erick Hitter committed
567 568 569 570 571 572 573 574
								<input type="checkbox" name="<?php echo esc_attr( $this->settings_key ); ?>[link_post_types][]" id="link-pt-<?php echo esc_attr( $post_type->name ); ?>" value="<?php echo esc_attr( $post_type->name ); ?>"
									<?php
									if ( in_array( $post_type->name, $options['link_post_types'], true ) ) {
										echo ' checked="checked"';
									}
									?>
								/>
								<label for="link-pt-<?php echo esc_attr( $post_type->name ); ?>"><?php echo esc_html( $post_type->labels->name ); ?></label><br />
575 576 577 578
							<?php endforeach; ?>
						</td>
					</tr>
					<tr>
Erick Hitter's avatar
PHPCS  
Erick Hitter committed
579
						<th scope="row"><label for="link_text"><?php esc_html_e( 'Link text:', 'view_all_posts_pages' ); ?></label></th>
580
						<td>
Erick Hitter's avatar
PHPCS  
Erick Hitter committed
581
							<input type="text" name="<?php echo esc_attr( $this->settings_key ); ?>[link_text]" id="link_text" value="<?php echo esc_attr( $options['link_text'] ); ?>" class="regular-text" />
582 583 584
						</td>
					</tr>
					<tr>
Erick Hitter's avatar
PHPCS  
Erick Hitter committed
585
						<th scope="row"><label for="link_class"><?php esc_html_e( 'Link\'s CSS class(es):', 'view_all_posts_pages' ); ?></label></th>
586
						<td>
Erick Hitter's avatar
PHPCS  
Erick Hitter committed
587
							<input type="text" name="<?php echo esc_attr( $this->settings_key ); ?>[link_class]" id="link_class" value="<?php echo esc_attr( $options['link_class'] ); ?>" class="regular-text" />
588

Erick Hitter's avatar
PHPCS  
Erick Hitter committed
589
							<p class="description"><?php esc_html_e( 'Be aware that Internet Explorer will only interpret the first two CSS classes.', 'view_all_posts_pages' ); ?></p>
590 591 592
						</td>
					</tr>
					<tr>
Erick Hitter's avatar
PHPCS  
Erick Hitter committed
593
						<th scope="row"><label for="link_priority"><?php esc_html_e( 'Link\'s priority:', 'view_all_posts_pages' ); ?></label></th>
594
						<td>
Erick Hitter's avatar
PHPCS  
Erick Hitter committed
595
							<input type="text" name="<?php echo esc_attr( $this->settings_key ); ?>[link_priority]" id="link_priority" class="small-text code" value="<?php echo esc_attr( $options['link_priority'] ); ?>" />
596

Erick Hitter's avatar
PHPCS  
Erick Hitter committed
597 598
							<p class="description"><?php esc_html_e( 'Priority determines when the link is added to a post\'s content. You can use the above setting to modulate the link\'s placement.', 'view_all_posts_pages' ); ?></p>
							<p class="description"><?php echo wp_kses_post( __( 'The default value is <strong>10</strong>. Lower values mean the link will be added earlier, while higher values will add the link later.', 'view_all_posts_pages' ) ); ?></p>
599 600 601 602 603 604 605 606
						</td>
					</tr>
				</table>

				<?php submit_button(); ?>
			</form>

		</div><!-- .wrap -->
Erick Hitter's avatar
Erick Hitter committed
607
		<?php
608 609 610 611
	}

	/**
	 * Validate options
Erick Hitter's avatar
Erick Hitter committed
612
	 *
Erick Hitter's avatar
PHPCS  
Erick Hitter committed
613
	 * @param array $options Plugin options.
Erick Hitter's avatar
Erick Hitter committed
614 615 616 617
	 * @uses this::get_options
	 * @uses this::post_types_array
	 * @uses sanitize_text_field
	 * @uses absint
618 619 620 621 622 623 624
	 * @return array
	 */
	public function admin_options_validate( $options ) {
		$new_options = array();

		if ( is_array( $options ) ) {
			foreach ( $options as $key => $value ) {
Erick Hitter's avatar
Erick Hitter committed
625
				switch ( $key ) {
626 627
					case 'wlp':
					case 'link':
Erick Hitter's avatar
Erick Hitter committed
628 629
						$new_options[ $key ] = (bool) $value;
						break;
630 631 632 633 634

					case 'link_position':
						$placements = array(
							'above',
							'below',
Erick Hitter's avatar
Erick Hitter committed
635
							'both',
636 637
						);

Erick Hitter's avatar
PHPCS  
Erick Hitter committed
638
						$new_options[ $key ] = in_array( $value, $placements, true ) ? $value : 'below';
Erick Hitter's avatar
Erick Hitter committed
639
						break;
640 641 642 643 644 645 646 647 648

					case 'wlp_post_types':
					case 'link_post_types':
						$post_types = $this->post_types_array();

						$new_options[ $key ] = array();

						if ( is_array( $value ) && is_array( $post_types ) ) {
							foreach ( $post_types as $post_type ) {
Erick Hitter's avatar
PHPCS  
Erick Hitter committed
649
								if ( in_array( $post_type->name, $value, true ) ) {
650
									$new_options[ $key ][] = $post_type->name;
Erick Hitter's avatar
Erick Hitter committed
651
								}
652 653
							}
						}
Erick Hitter's avatar
Erick Hitter committed
654
						break;
655 656 657 658 659 660 661

					case 'wlp_text':
					case 'wlp_class':
					case 'link_text':
					case 'link_class':
						$value = sanitize_text_field( $value );

Erick Hitter's avatar
PHPCS  
Erick Hitter committed
662
						if ( ( 'wlp_text' === $key || 'link_text' === $key ) && empty( $value ) ) {
663
							$value = 'View all';
Erick Hitter's avatar
Erick Hitter committed
664
						}
665 666

						$new_options[ $key ] = $value;
Erick Hitter's avatar
Erick Hitter committed
667
						break;
668 669 670 671 672

					case 'link_priority':
						$value = absint( $value );

						$new_options[ $key ] = $value;
Erick Hitter's avatar
Erick Hitter committed
673
						break;
674 675

					default:
Erick Hitter's avatar
Erick Hitter committed
676
						break;
677 678 679 680 681 682 683 684 685
				}
			}
		}

		return $new_options;
	}

	/**
	 * Return plugin options array parsed with default options
Erick Hitter's avatar
Erick Hitter committed
686
	 *
Erick Hitter's avatar
Erick Hitter committed
687 688
	 * @uses get_option
	 * @uses wp_parse_args
689 690 691 692 693
	 * @return array
	 */
	private function get_options() {
		$options = get_option( $this->settings_key, $this->settings_defaults );

Erick Hitter's avatar
Erick Hitter committed
694
		if ( ! is_array( $options ) ) {
695
			$options = array();
Erick Hitter's avatar
Erick Hitter committed
696
		}
697

Erick Hitter's avatar
Erick Hitter committed
698 699 700
		if ( ! array_key_exists( 'wlp_post_types', $options ) ) {
			$options['wlp_post_types'] = array();
		}
701

Erick Hitter's avatar
Erick Hitter committed
702 703 704
		if ( ! array_key_exists( 'link_post_types', $options ) ) {
			$options['link_post_types'] = array();
		}
705 706 707 708 709

		return wp_parse_args( $options, $this->settings_defaults );
	}

	/**
Erick Hitter's avatar
Erick Hitter committed
710 711
	 * Build array of available post types, excluding all built-in ones except 'post' and 'page'.
	 *
712 713 714 715 716 717
	 * @uses get_post_types
	 * @return array
	 */
	private function post_types_array() {
		$post_types = array();
		foreach ( get_post_types( array(), 'objects' ) as $post_type ) {
Erick Hitter's avatar
PHPCS  
Erick Hitter committed
718
			if ( false === $post_type->_builtin || 'post' === $post_type->name || 'page' === $post_type->name ) {
719
				$post_types[] = $post_type;
Erick Hitter's avatar
Erick Hitter committed
720
			}
721 722 723 724 725 726 727
		}

		return $post_types;
	}

	/**
	 * Display admin notice regarding rewrite rules flush.
Erick Hitter's avatar
Erick Hitter committed
728
	 *
Erick Hitter's avatar
Erick Hitter committed
729 730 731 732 733 734
	 * @uses get_option
	 * @uses apply_filters
	 * @uses _e
	 * @uses __
	 * @uses admin_url
	 * @uses add_query_arg
735 736 737 738
	 * @action admin_notices
	 */
	public function action_admin_notices_activation() {
		if ( ! get_option( $this->notice_key ) && apply_filters( 'vapp_display_rewrite_rules_notice', true ) ) :
Erick Hitter's avatar
Erick Hitter committed
739
			?>
740 741

		<div id="wpf-rewrite-flush-warning" class="error fade">
Erick Hitter's avatar
PHPCS  
Erick Hitter committed
742 743 744 745 746 747 748 749
			<p><strong><?php esc_html_e( 'View All Post\'s Pages', 'view_all_posts_pages' ); ?></strong></p>

			<p>
				<?php
					/* translators: 1: Permalinks settings page URL. */
					printf( wp_kses_post( __( 'You must refresh your site\'s permalinks before <em>View All Post\'s Pages</em> is fully activated. To do so, go to <a href="%s">Permalinks</a> and click the <strong><em>Save Changes</em></strong> button at the bottom of the screen.', 'view_all_posts_pages' ) ), esc_url( admin_url( 'options-permalink.php' ) ) );
				?>
			</p>
750

Erick Hitter's avatar
PHPCS  
Erick Hitter committed
751 752 753 754 755 756
			<p>
				<?php
					$query_args = array(
						$this->notice_key            => 1,
						$this->notice_key . '_nonce' => wp_create_nonce( $this->notice_key ),
					);
757

Erick Hitter's avatar
PHPCS  
Erick Hitter committed
758 759
					/* translators: 1: URL to dismiss admin notice. */
					printf( wp_kses_post( __( 'When finished, click <a href="%s">here</a> to hide this message.', 'view_all_posts_pages' ) ), esc_url( admin_url( add_query_arg( $query_args, 'index.php' ) ) ) );
Erick Hitter's avatar
PHPCS  
Erick Hitter committed
760
					?>
Erick Hitter's avatar
PHPCS  
Erick Hitter committed
761
			</p>
762 763
		</div>

Erick Hitter's avatar
Erick Hitter committed
764
			<?php
765 766 767
		endif;
	}
}
Erick Hitter's avatar
Erick Hitter committed
768 769 770 771 772

/**
 * Alias global variable used to hold instantiated plugin prior to singleton's introduction in version 0.7.
 */
$GLOBALS['vapp'] = view_all_posts_pages::get_instance();
773 774 775

/**
 * Shortcut to public function for generating full post view URL
Erick Hitter's avatar
Erick Hitter committed
776
 *
Erick Hitter's avatar
PHPCS  
Erick Hitter committed
777
 * @param int|false $post_id Post ID.
Erick Hitter's avatar
Erick Hitter committed
778
 * @uses view_all_posts_pages::get_instance
779 780 781
 * @return string or bool
 */
function vapp_get_url( $post_id = false ) {
Erick Hitter's avatar
Erick Hitter committed
782
	return view_all_posts_pages::get_instance()->url( intval( $post_id ) );
783 784 785 786
}

/**
 * Output link to full post view.
Erick Hitter's avatar
Erick Hitter committed
787 788
 *
 * @global $post
Erick Hitter's avatar
PHPCS  
Erick Hitter committed
789 790
 * @param string $link_text Link text.
 * @param string $class Link class.
Erick Hitter's avatar
Erick Hitter committed
791 792 793 794
 * @uses vapp_get_url
 * @uses esc_attr
 * @uses esc_url
 * @uses esc_html
795 796 797 798 799 800 801 802
 */
function vapp_the_link( $link_text = 'View All', $class = 'vapp' ) {
	global $post;
	$url = vapp_get_url( $post->ID );

	if ( $url ) {
		$link = '<a ' . ( $class ? 'class="' . esc_attr( $class ) . '"' : '' ) . ' href="' . esc_url( $url ) . '">' . esc_html( $link_text ) . '</a>';

Erick Hitter's avatar
PHPCS  
Erick Hitter committed
803
		echo wp_kses_post( $link );
804 805 806 807 808 809
	}
}

/**
 * Filter wp_link_pages args.
 * Function is a shortcut to class' filter.
Erick Hitter's avatar
Erick Hitter committed
810
 *
Erick Hitter's avatar
PHPCS  
Erick Hitter committed
811
 * @param array $args wp_link_pages args.
Erick Hitter's avatar
Erick Hitter committed
812
 * @uses view_all_posts_pages::get_instance
813 814 815
 * @return array
 */
function vapp_filter_wp_link_pages_args( $args ) {
Erick Hitter's avatar
Erick Hitter committed
816
	return view_all_posts_pages::get_instance()->filter_wp_link_pages_args( $args );
817 818 819 820 821
}

if ( ! function_exists( 'is_view_all' ) ) {
	/**
	 * Conditional tag indicating if full post view was requested.
Erick Hitter's avatar
Erick Hitter committed
822
	 *
Erick Hitter's avatar
Erick Hitter committed
823
	 * @uses view_all_posts_pages::get_instance
824 825
	 * @return bool
	 */
Erick Hitter's avatar
PHPCS  
Erick Hitter committed
826
	function is_view_all() { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedFunctionFound
Erick Hitter's avatar
Erick Hitter committed
827
		return view_all_posts_pages::get_instance()->is_view_all();
828 829
	}
}