Plugin Directory

Changeset 2749430


Ignore:
Timestamp:
06/29/2022 04:36:18 AM (3 years ago)
Author:
ethitter
Message:

Update to version 0.3 from GitLab (https://git.ethitter.com/wp-plugins/automatically-paginate-posts; https://git.ethitter.com/wp-plugins/automatically-paginate-posts/-/jobs/19922)

Location:
automatically-paginate-posts
Files:
12 added
6 edited
1 copied

Legend:

Unmodified
Added
Removed
  • automatically-paginate-posts/tags/0.3/automatically-paginate-posts.php

    r869001 r2749430  
    1 <?php
    2 /*
    3 Plugin Name: Automatically Paginate Posts
    4 Plugin URI: http://www.oomphinc.com/plugins-modules/automatically-paginate-posts/
    5 Description: Automatically inserts the &lt;!--nextpage--&gt; Quicktag into WordPress posts, pages, or custom post type content.
    6 Version: 0.2
    7 Author: Erick Hitter & Oomph, Inc.
    8 Author URI: http://www.oomphinc.com/
    9 
    10 This program is free software; you can redistribute it and/or modify
    11 it under the terms of the GNU General Public License as published by
    12 the Free Software Foundation; either version 2 of the License, or
    13 (at your option) any later version.
    14 
    15 This program is distributed in the hope that it will be useful,
    16 but WITHOUT ANY WARRANTY; without even the implied warranty of
    17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    18 GNU General Public License for more details.
    19 
    20 You should have received a copy of the GNU General Public License
    21 along with this program; if not, write to the Free Software
    22 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    23 */
    24 
     1<?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
     2/**
     3 * Automatically inserts the &lt;!--nextpage--&gt; Quicktag into WordPress posts, pages, or custom post type content.
     4 *
     5 * Plugin Name: Automatically Paginate Posts
     6 * Plugin URI: http://www.oomphinc.com/plugins-modules/automatically-paginate-posts/
     7 * Description: Automatically inserts the &lt;!--nextpage--&gt; Quicktag into WordPress posts, pages, or custom post type content.
     8 * Version: 0.3
     9 * Author: Erick Hitter & Oomph, Inc.
     10 * Author URI: http://www.oomphinc.com/
     11 * Text Domain: autopaging
     12 * Domain Path: /languages/
     13 *
     14 * This program is free software; you can redistribute it and/or modify
     15 * it under the terms of the GNU General Public License as published by
     16 * the Free Software Foundation; either version 2 of the License, or
     17 * (at your option) any later version.
     18 *
     19 * This program is distributed in the hope that it will be useful,
     20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     22 * GNU General Public License for more details.
     23 *
     24 * You should have received a copy of the GNU General Public License
     25 * along with this program; if not, write to the Free Software
     26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     27 *
     28 * @package automatically-paginate-posts
     29 */
     30
     31require_once dirname( __FILE__ ) . '/inc/class-block-editor.php';
     32
     33/**
     34 * Class Automatically_Paginate_Posts.
     35 */
    2536class Automatically_Paginate_Posts {
    2637    /**
    27      * Class variables
     38     * WordPress Quicktag that creates pagination.
     39     */
     40    const QUICKTAG = '<!--nextpage-->';
     41
     42    /**
     43     * String length of nextpage Quicktag.
     44     */
     45    const QUICKTAG_LENGTH = 15;
     46
     47    /**
     48     * Supported post types.
     49     *
     50     * @var array
    2851     */
    2952    private $post_types;
     53
     54    /**
     55     * Default supported post types.
     56     *
     57     * @var array
     58     */
    3059    private $post_types_default = array( 'post' );
    3160
     61    /**
     62     * Desired number of pages to split to.
     63     *
     64     * @var int
     65     */
    3266    private $num_pages;
     67
     68    /**
     69     * Method for splitting content, either words or desired number of pages.
     70     *
     71     * @var string
     72     */
    3373    private $paging_type_default = 'pages';
    34     private $num_pages_default   = 2;
    35     private $num_words_default   = '';
    36 
     74
     75    /**
     76     * Default number of pages to split to.
     77     *
     78     * @var int
     79     */
     80    private $num_pages_default = 2;
     81
     82    /**
     83     * Desired number of words per pages.
     84     *
     85     * @var int
     86     */
     87    private $num_words;
     88
     89    /**
     90     * Default number of words to split on.
     91     *
     92     * @var string|int
     93     */
     94    private $num_words_default = '';
     95
     96    /**
     97     * When splitting by word counts, these blocks are considered. Tags are
     98     * stripped and remaining content is counted.
     99     *
     100     * @var array
     101     */
     102    private $supported_block_types_for_word_counts = array(
     103        'core/paragraph',
     104    );
     105
     106    /**
     107     * Allowed split types.
     108     *
     109     * @var array
     110     */
    37111    private $paging_types_allowed = array( 'pages', 'words' );
    38112
    39     // Ensure option names match values in this::uninstall
    40     private $option_name_post_types  = 'autopaging_post_types';
     113    /**
     114     * Supported-post-types option name.
     115     *
     116     * @var string
     117     */
     118    private $option_name_post_types = 'autopaging_post_types';
     119
     120    /**
     121     * Split-type option name.
     122     *
     123     * @var string
     124     */
    41125    private $option_name_paging_type = 'pages';
    42     private $option_name_num_pages   = 'autopaging_num_pages';
    43     private $option_name_num_words   = 'autopaging_num_words';
    44 
     126
     127    /**
     128     * Option holding number of pages to split to.
     129     *
     130     * @var string
     131     */
     132    private $option_name_num_pages = 'autopaging_num_pages';
     133
     134    /**
     135     * Option holding number of words to split on.
     136     *
     137     * @var string
     138     */
     139    private $option_name_num_words = 'autopaging_num_words';
     140
     141    /**
     142     * Meta key used to indicate that a post shouldn't be automatically split.
     143     *
     144     * @var string
     145     */
    45146    private $meta_key_disable_autopaging = '_disable_autopaging';
    46147
    47148    /**
    48      * Register actions and filters
    49      *
    50      * @uses add_action, register_uninstall_hook, add_filter
    51      * @return null
     149     * Class constructor.
     150     *
     151     * @return void
    52152     */
    53153    public function __construct() {
    54         //Filters
     154        $this->setup_hooks();
     155
     156        new Automatically_Paginate_Posts\Block_Editor( $this );
     157    }
     158
     159    /**
     160     * Register hooks.
     161     *
     162     * @return void
     163     */
     164    protected function setup_hooks() {
     165        add_action( 'plugins_loaded', array( $this, 'load_textdomain' ) );
    55166        add_action( 'init', array( $this, 'action_init' ) );
    56167
    57         //Admin settings
     168        // Admin settings.
    58169        register_uninstall_hook( __FILE__, array( 'Automatically_Paginate_Posts', 'uninstall' ) );
    59170        add_filter( 'plugin_action_links', array( $this, 'filter_plugin_action_links' ), 10, 2 );
    60171        add_action( 'admin_init', array( $this, 'action_admin_init' ) );
    61172
    62         //Post-type settings
     173        // Post-type settings.
    63174        add_action( 'add_meta_boxes', array( $this, 'action_add_meta_boxes' ) );
    64175        add_action( 'save_post', array( $this, 'action_save_post' ) );
    65176        add_filter( 'the_posts', array( $this, 'filter_the_posts' ) );
    66177    }
    67 
    68     /**
    69      * Set post types this plugin can act on, either from Reading page or via filter
    70      * Also sets default number of pages to break content over, either from Reading page or via filter
     178    /**
     179     * Allow access to meta key for disabling autopaging.
     180     *
     181     * @param string $name Property name.
     182     * @return array|string|null
     183     */
     184    public function __get( $name ) {
     185        if ( 'meta_key' === $name ) {
     186            return $this->meta_key_disable_autopaging;
     187        }
     188
     189        if ( 'post_types' === $name ) {
     190            if ( ! did_action( 'init' ) ) {
     191                _doing_it_wrong(
     192                    __METHOD__,
     193                    esc_html__(
     194                        'Post types can only be retrieved after the "init" hook.',
     195                        'autopaging'
     196                    ),
     197                    '0.3'
     198                );
     199
     200                return null;
     201            }
     202
     203            return $this->post_types;
     204        }
     205
     206        return null;
     207    }
     208
     209    /**
     210     * Prevent setting properties.
     211     *
     212     * @param string $name  Property name.
     213     * @param string $value Property value.
     214     * @return false
     215     */
     216    public function __set( $name, $value ) {
     217        return false;
     218    }
     219
     220    /**
     221     * Indicate if a property is set.
     222     *
     223     * @param string $name Property name.
     224     * @return bool
     225     */
     226    public function __isset( $name ) {
     227        if ( 'meta_key' === $name ) {
     228            return true;
     229        }
     230
     231        if ( 'post_types' === $name ) {
     232            return did_action( 'init' );
     233        }
     234
     235        return false;
     236    }
     237
     238    /**
     239     * Load plugin translations.
     240     *
     241     * @return void
     242     */
     243    public function load_textdomain() {
     244        load_plugin_textdomain(
     245            'autopaging',
     246            false,
     247            dirname( plugin_basename( __FILE__ ) ) . '/languages/'
     248        );
     249    }
     250
     251    /**
     252     * Set post types this plugin can act on, either from Reading page or via filter.
     253     * Also sets default number of pages to break content over, either from Reading page or via filter.
    71254     *
    72255     * @uses apply_filters, get_option
    73256     * @action init
    74      * @return null
     257     * @return void
    75258     */
    76259    public function action_init() {
    77         //Post types
     260        // Post types.
    78261        $this->post_types = apply_filters( 'autopaging_post_types', get_option( $this->option_name_post_types, $this->post_types_default ) );
    79262
    80         //Number of pages to break over
     263        // Number of pages to break over.
    81264        $this->num_pages = absint( apply_filters( 'autopaging_num_pages_default', get_option( $this->option_name_num_pages, $this->num_pages_default ) ) );
    82         if ( 0 == $this->num_pages )
     265        if ( 0 == $this->num_pages ) {
    83266            $this->num_pages = $this->num_pages_default;
    84 
    85         //Number of words to break over
     267        }
     268
     269        // Number of words to break over.
    86270        $this->num_words = absint( apply_filters( 'autopaging_num_words_default', get_option( $this->option_name_num_words, $this->num_words_default ) ) );
    87         if ( 0 == $this->num_words )
     271        if ( 0 == $this->num_words ) {
    88272            $this->num_words = $this->num_words_default;
     273        }
     274
     275        // Supported blocks for splitting by words.
     276        $this->supported_block_types_for_word_counts = apply_filters(
     277            'autopaging_supported_block_types_for_word_counts',
     278            $this->supported_block_types_for_word_counts
     279        );
    89280    }
    90281
     
    95286     * @uses delete_option
    96287     * @action uninstall
    97      * @return null
     288     * @return void
    98289     */
    99290    public function uninstall() {
     
    107298     * Add settings link to plugin's row actions
    108299     *
    109      * @param array $actions
    110      * @param string $file
     300     * @param array  $actions Plugin's actions.
     301     * @param string $file    Plugin filename.
    111302     * @filter plugin_action_links,
    112303     */
    113304    public function filter_plugin_action_links( $actions, $file ) {
    114         if ( false !== strpos( $file, basename( __FILE__ ) ) )
    115             $actions[ 'settings' ] = '<a href="' . admin_url( 'options-reading.php' ) . '">Settings</a>';
     305        if ( false !== strpos( $file, basename( __FILE__ ) ) ) {
     306            $actions['settings'] = '<a href="' . admin_url( 'options-reading.php' ) . '">Settings</a>';
     307        }
    116308
    117309        return $actions;
     
    119311
    120312    /**
    121      * Register settings and settings sections
    122      * Settings appear on the Reading page
     313     * Register settings and settings sections.
     314     * Settings appear on the Reading page.
    123315     *
    124316     * @uses register_setting, add_settings_section, __, __return_false, add_settings_field
    125317     * @action admin_init
    126      * @return null
     318     * @return void
    127319     */
    128320    public function action_admin_init() {
     
    138330
    139331    /**
    140      * Render post types options
     332     * Render post types options.
    141333     *
    142334     * @uses get_post_types, get_option, esc_attr, checked, esc_html
    143      * @return string
     335     * @return void
    144336     */
    145337    public function settings_field_post_types() {
    146         //Get all public post types
    147         $post_types = get_post_types( array(
    148             'public' => true
    149         ), 'objects' );
    150 
    151         //Remove attachments
    152         unset( $post_types[ 'attachment' ] );
    153 
    154         //Current settings
     338        // Get all public post types.
     339        $post_types = get_post_types(
     340            array(
     341                'public' => true,
     342            ),
     343            'objects'
     344        );
     345
     346        unset( $post_types['attachment'] );
     347
     348        // Current settings.
    155349        $current_types = get_option( $this->option_name_post_types, $this->post_types_default );
    156350
    157         //Output checkboxes
     351        // Output checkboxes.
    158352        foreach ( $post_types as $post_type => $atts ) :
    159         ?>
     353            ?>
    160354            <input type="checkbox" name="<?php echo esc_attr( $this->option_name_post_types ); ?>[]" id="post-type-<?php echo esc_attr( $post_type ); ?>" value="<?php echo esc_attr( $post_type ); ?>"<?php checked( in_array( $post_type, $current_types ) ); ?> /> <label for="post-type-<?php echo esc_attr( $post_type ); ?>"><?php echo esc_html( $atts->label ); ?></label><br />
    161         <?php
     355            <?php
    162356        endforeach;
    163357    }
    164358
    165359    /**
    166      * Sanitize post type inputs
    167      *
    168      * @param array $post_types_checked
     360     * Sanitize post type inputs.
     361     *
     362     * @param array $post_types_checked Selected post types to sanitize.
    169363     * @uses get_post_types
    170364     * @return array
     
    173367        $post_types_sanitized = array();
    174368
    175         //Ensure that only existing, public post types are submitted as valid options
     369        // Ensure that only existing, public post types are submitted as valid options.
    176370        if ( is_array( $post_types_checked ) && ! empty( $post_types_checked ) ) {
    177             //Get all public post types
    178             $post_types = get_post_types( array(
    179                 'public' => true
    180             ) );
    181 
    182             //Remove attachments
    183             unset( $post_types[ 'attachment' ] );
    184 
    185             //Check input post types against those registered with WordPress and made available to this plugin
     371            // Get all public post types.
     372            $post_types = get_post_types(
     373                array(
     374                    'public' => true,
     375                )
     376            );
     377
     378            unset( $post_types['attachment'] );
     379
     380            // Check input post types against those registered with WordPress and made available to this plugin.
    186381            foreach ( $post_types_checked as $post_type ) {
    187                 if ( array_key_exists( $post_type, $post_types ) )
     382                if ( array_key_exists( $post_type, $post_types ) ) {
    188383                    $post_types_sanitized[] = $post_type;
     384                }
    189385            }
    190386        }
     
    194390
    195391    /**
    196      * Render option to choose paging type and options for that type
     392     * Render option to choose paging type and options for that type.
    197393     *
    198394     * @uses get_option()
    199395     * @uses esc_attr()
    200396     * @uses checked()
    201      * @return string
     397     * @return void
    202398     */
    203399    public function settings_field_paging_type() {
     
    208404
    209405        $labels = array(
    210             'pages' => __( 'Total number of pages: ', 'autopaging' ),
    211             'words' => __( 'Approximate words per page: ', 'autopaging' ),
     406            'pages' => __( 'Total number of pages:', 'autopaging' ),
     407            'words' => __( 'Approximate words per page:', 'autopaging' ),
    212408        );
    213409
    214410        foreach ( $this->paging_types_allowed as $type ) :
    215             $type_escaped = esc_attr( $type );
    216411            $func = 'settings_field_num_' . $type;
    217412            ?>
    218             <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; ?>">
    219                 <strong><?php echo $labels[ $type ]; ?></strong><?php $this->{$func}(); ?>
    220             </label></p>
    221         <?php endforeach;
    222     }
    223 
    224     /**
    225      * Validate chosen paging type against allowed values
    226      *
    227      * @param string
     413            <p>
     414                <input type="radio" name="<?php echo esc_attr( $this->option_name_paging_type ); ?>" id="autopaging-type-<?php echo esc_attr( $type ); ?>" value="<?php echo esc_attr( $type ); ?>"<?php checked( $type, $paging_type ); ?> />
     415                <label for="autopaging-type-<?php echo esc_attr( $type ); ?>">
     416                    <?php echo esc_html( $labels[ $type ] ); ?>
     417                    &nbsp;
     418                    <?php $this->{$func}(); ?>
     419                </label>
     420            </p>
     421            <br />
     422            <?php
     423        endforeach;
     424    }
     425
     426    /**
     427     * Validate chosen paging type against allowed values.
     428     *
     429     * @param string $type Selected paging type.
    228430     * @return string
    229431     */
    230432    public function sanitize_paging_type( $type ) {
    231         return in_array( $type, $this->paging_types_allowed ) ? $type : $this->paging_type_default;
    232     }
    233 
    234     /**
    235      * Render dropdown for choosing number of pages to break content over
     433        return in_array( $type, $this->paging_types_allowed, true ) ? $type : $this->paging_type_default;
     434    }
     435
     436    /**
     437     * Render dropdown for choosing number of pages to break content over.
    236438     *
    237439     * @uses get_option, apply_filters, esc_attr, selected
    238      * @return string
     440     * @return void
    239441     */
    240442    public function settings_field_num_pages() {
     
    244446        ?>
    245447            <select name="<?php echo esc_attr( $this->option_name_num_pages ); ?>">
    246                 <?php for( $i = 2; $i <= $max_pages; $i++ ) : ?>
     448                <?php for ( $i = 2; $i <= $max_pages; $i++ ) : ?>
    247449                    <option value="<?php echo intval( $i ); ?>"<?php selected( (int) $i, (int) $num_pages ); ?>><?php echo intval( $i ); ?></option>
    248450                <?php endfor; ?>
     
    252454
    253455    /**
    254      * Sanitize number of pages input
    255      *
    256      * @param int $num_pages
     456     * Sanitize number of pages input.
     457     *
     458     * @param int $num_pages Number of pages to split to.
    257459     * @uses apply_filters
    258460     * @return int
     
    263465
    264466    /**
    265      * Render input field for specifying approximate number of words each page should contain
     467     * Render input field for specifying approximate number of words each page should contain.
    266468     *
    267469     * @uses get_option, apply_filters, esc_attr, selected
    268      * @return string
     470     * @return void
    269471     */
    270472    public function settings_field_num_words() {
    271473        $num_words = apply_filters( 'autopaging_num_words', get_option( $this->option_name_num_words ) )
    272474        ?>
    273             <input name="<?php echo esc_attr( $this->option_name_num_words ); ?>" value="<?php echo esc_attr( $num_words ); ?>" size="4" />
    274 
    275             <p class="description"><?php _e( 'If chosen, each page will contain approximately this many words, depending on paragraph lengths.', 'autopaging' ); ?></p>
     475            <input
     476                name="<?php echo esc_attr( $this->option_name_num_words ); ?>"
     477                value="<?php echo esc_attr( $num_words ); ?>"
     478                class="small-text"
     479                type="number"
     480                step="1"
     481                min="1"
     482            />
     483
     484            <p class="description"><?php esc_html_e( 'If chosen, each page will contain approximately this many words, depending on paragraph lengths.', 'autopaging' ); ?></p>
    276485        <?php
    277486    }
    278487
    279488    /**
    280      * Sanitize number of words input. No fewer than 10 by default, filterable by autopaging_max_num_words
    281      *
    282      * @param int $num_words
     489     * Sanitize number of words input. No fewer than 10 by default, filterable by `autopaging_max_num_words`.
     490     *
     491     * @param int $num_words Number of words to split on.
    283492     * @uses apply_filters
    284493     * @return int
     
    295504
    296505    /**
    297      * Add autopaging metabox
     506     * Add autopaging metabox.
    298507     *
    299508     * @uses add_metabox, __
    300509     * @action add_meta_box
    301      * @return null
     510     * @return void
    302511     */
    303512    public function action_add_meta_boxes() {
    304513        foreach ( $this->post_types as $post_type ) {
    305             add_meta_box( 'autopaging', __( 'Post Autopaging', 'autopaging' ), array( $this, 'meta_box_autopaging' ), $post_type, 'side' );
    306         }
    307     }
    308 
    309     /**
    310      * Render autopaging metabox
    311      *
    312      * @param object $post
     514            if (
     515                function_exists( 'use_block_editor_for_post_type' ) &&
     516                use_block_editor_for_post_type( $post_type )
     517            ) {
     518                continue;
     519            }
     520
     521            add_meta_box( 'autopaging', __( 'Autopaging', 'autopaging' ), array( $this, 'meta_box_autopaging' ), $post_type, 'side' );
     522        }
     523    }
     524
     525    /**
     526     * Render autopaging metabox.
     527     *
     528     * @param object $post Post object.
    313529     * @uses esc_attr, checked, _e, __, wp_nonce_field
    314      * @return string
     530     * @return void
    315531     */
    316532    public function meta_box_autopaging( $post ) {
    317     ?>
     533        ?>
    318534        <p>
    319             <input type="checkbox" name="<?php echo esc_attr( $this->meta_key_disable_autopaging ); ?>" id="<?php echo esc_attr( $this->meta_key_disable_autopaging ); ?>_checkbox" value="1"<?php checked( (bool) get_post_meta( $post->ID, $this->meta_key_disable_autopaging, true ) ); ?> /> <label for="<?php echo esc_attr( $this->meta_key_disable_autopaging ); ?>_checkbox">Disable autopaging for this post?</label>
     535            <input type="checkbox" name="<?php echo esc_attr( $this->meta_key_disable_autopaging ); ?>" id="<?php echo esc_attr( $this->meta_key_disable_autopaging ); ?>_checkbox" value="1"<?php checked( (bool) get_post_meta( $post->ID, $this->meta_key_disable_autopaging, true ) ); ?> />
     536            <label for="<?php echo esc_attr( $this->meta_key_disable_autopaging ); ?>_checkbox">
     537                <?php esc_html_e( 'Disable autopaging for this post?', 'autopaging' ); ?>
     538            </label>
    320539        </p>
    321         <p class="description"><?php _e( 'Check the box above to prevent this post from automatically being split over multiple pages.', 'autopaging' ); ?></p>
    322         <p class="description"><?php printf( __( 'Note that if the %1$s Quicktag is used to manually page this post, automatic paging won\'t be applied, regardless of the setting above.', 'autopaging' ), '<code>&lt;!--nextpage--&gt;</code>' ); ?></p>
    323     <?php
     540        <p class="description"><?php esc_html__( 'Check the box above to prevent this post from automatically being split over multiple pages.', 'autopaging' ); ?></p>
     541        <p class="description">
     542            <?php
     543                printf(
     544                    /* translators: 1. Quicktag code example. */
     545                    esc_html__(
     546                        'Note that if the %1$s Quicktag is used to manually page this post, automatic paging won\'t be applied, regardless of the setting above.',
     547                        'autopaging'
     548                    ),
     549                    // No need to escape a class constant.
     550                    // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
     551                    '<code>' . htmlentities( static::QUICKTAG, ENT_QUOTES ) . '</code>'
     552                );
     553            ?>
     554        </p>
     555
     556        <?php
    324557        wp_nonce_field( $this->meta_key_disable_autopaging, $this->meta_key_disable_autopaging . '_wpnonce' );
    325558    }
    326559
    327560    /**
    328      * Save autopaging metabox
    329      *
    330      * @param int $post_id
     561     * Save autopaging metabox.
     562     *
     563     * @param int $post_id Post ID.
    331564     * @uses DOING_AUTOSAVE, wp_verify_nonce, update_post_meta, delete_post_meta
    332565     * @action save_post
     
    334567     */
    335568    public function action_save_post( $post_id ) {
    336         if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
     569        if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
    337570            return;
     571        }
     572
     573        if (
     574            function_exists( 'use_block_editor_for_post' )
     575            && use_block_editor_for_post( $post_id )
     576        ) {
     577            return;
     578        }
    338579
    339580        if ( isset( $_POST[ $this->meta_key_disable_autopaging . '_wpnonce' ] ) && wp_verify_nonce( $_POST[ $this->meta_key_disable_autopaging . '_wpnonce' ], $this->meta_key_disable_autopaging ) ) {
    340             $disable = isset( $_POST[ $this->meta_key_disable_autopaging ] ) ? true : false;
    341 
    342             if ( $disable )
     581            $disable = isset( $_POST[ $this->meta_key_disable_autopaging ] );
     582
     583            if ( $disable ) {
    343584                update_post_meta( $post_id, $this->meta_key_disable_autopaging, true );
    344             else
     585            } else {
    345586                delete_post_meta( $post_id, $this->meta_key_disable_autopaging );
     587            }
    346588        }
    347589    }
     
    351593     * Only applied if the post type matches specified options and post doesn't already contain the Quicktag.
    352594     *
    353      * @param array $posts
     595     * @param array $posts Array of posts retrieved by WP_Query.
    354596     * @uses is_admin, get_post_meta, absint, apply_filters
    355597     * @filter the_posts
     
    357599     */
    358600    public function filter_the_posts( $posts ) {
    359         if ( ! is_admin() ) {
    360             foreach( $posts as $the_post ) {
    361                 if ( in_array( $the_post->post_type, $this->post_types ) && ! preg_match( '#<!--nextpage-->#i', $the_post->post_content ) && ! (bool) get_post_meta( $the_post->ID, $this->meta_key_disable_autopaging, true ) ) {
    362                     //In-time filtering of number of pages to break over, based on post data. If value is less than 2, nothing should be done.
    363                     $num_pages = absint( apply_filters( 'autopaging_num_pages', absint( $this->num_pages ), $the_post ) );
    364                     $num_words = absint( apply_filters( 'autopaging_num_words', absint( $this->num_words ), $the_post ) );
    365 
    366                     if ( $num_pages < 2 && empty( $num_words ) )
    367                         continue;
    368 
    369                     //Start with post content, but alias to protect the raw content.
    370                     $content = $the_post->post_content;
    371 
    372                     //Normalize post content to simplify paragraph counting and automatic paging. Accounts for content that hasn't been cleaned up by TinyMCE.
    373                     $content = preg_replace( '#<p>(.+?)</p>#i', "$1\r\n\r\n", $content );
    374                     $content = preg_replace( '#<br(\s*/)?>#i', "\r\n", $content );
    375 
    376                     //Count paragraphs
    377                     $count = preg_match_all( '#\r\n\r\n#', $content, $matches );
    378 
    379                     //Keep going, if we have something to count.
    380                     if ( is_int( $count ) && 0 < $count ) {
    381                         //Explode content at double (or more) line breaks
    382                         $content = explode( "\r\n\r\n", $content );
    383 
    384                         switch ( get_option( $this->option_name_paging_type, $this->paging_type_default ) ) {
    385                             case 'words' :
    386                                 $word_counter = 0;
    387 
    388                                 // Count words per paragraph and break after the paragraph that exceeds the set threshold
    389                                 foreach ( $content as $index => $paragraph ) {
    390                                     $paragraph_words = count( preg_split( '/\s+/', strip_tags( $paragraph ) ) );
    391                                     $word_counter += $paragraph_words;
    392 
    393                                     if ( $word_counter >= $num_words ) {
    394                                         $content[ $index ] .= '<!--nextpage-->';
    395                                         $word_counter = 0;
    396                                     } else {
    397                                         continue;
    398                                     }
    399                                 }
    400 
    401                                 unset( $word_counter );
    402                                 unset( $index );
    403                                 unset( $paragraph );
    404                                 unset( $paragraph_words );
    405 
    406                                 break;
    407 
    408                             case 'pages' :
    409                             default :
    410                                 //Count number of paragraphs content was exploded to
    411                                 $count = count( $content );
    412 
    413                                 //Determine when to insert Quicktag
    414                                 $insert_every = $count / $num_pages;
    415                                 $insert_every_rounded = round( $insert_every );
    416 
    417                                 //If number of pages is greater than number of paragraphs, put each paragraph on its own page
    418                                 if ( $num_pages > $count ) {
    419                                     $insert_every_rounded = 1;
    420                                 }
    421 
    422                                 //Set initial counter position.
    423                                 $i = $count - 1 == $num_pages ? 2 : 1;
    424 
    425                                 //Loop through content pieces and append Quicktag as is appropriate
    426                                 foreach ( $content as $key => $value ) {
    427                                     if ( $key + 1 == $count ) {
    428                                         break;
    429                                     }
    430 
    431                                     if ( ( $key + 1 ) == ( $i * $insert_every_rounded ) ) {
    432                                         $content[ $key ] = $content[ $key ] . '<!--nextpage-->';
    433                                         $i++;
    434                                     }
    435                                 }
    436 
    437                                 //Clean up
    438                                 unset( $count );
    439                                 unset( $insert_every );
    440                                 unset( $insert_every_rounded );
    441                                 unset( $key );
    442                                 unset( $value );
    443 
    444                                 break;
     601        if ( is_admin() ) {
     602            return $posts;
     603        }
     604
     605        $paging_type = get_option(
     606            $this->option_name_paging_type,
     607            $this->paging_type_default
     608        );
     609
     610        foreach ( $posts as &$the_post ) {
     611            if (
     612                ! in_array(
     613                    $the_post->post_type,
     614                    $this->post_types,
     615                    true
     616                )
     617            ) {
     618                continue;
     619            }
     620
     621            if (
     622                preg_match(
     623                    '#' . static::QUICKTAG . '#i',
     624                    $the_post->post_content
     625                )
     626            ) {
     627                continue;
     628            }
     629
     630            if (
     631                (bool) get_post_meta(
     632                    $the_post->ID,
     633                    $this->meta_key_disable_autopaging,
     634                    true
     635                )
     636            ) {
     637                continue;
     638            }
     639
     640            $num_pages = absint(
     641                apply_filters(
     642                    'autopaging_num_pages',
     643                    absint( $this->num_pages ),
     644                    $the_post
     645                )
     646            );
     647            $num_words = absint(
     648                apply_filters(
     649                    'autopaging_num_words',
     650                    absint( $this->num_words ),
     651                    $the_post
     652                )
     653            );
     654
     655            if ( $num_pages < 2 && empty( $num_words ) ) {
     656                continue;
     657            }
     658
     659            if (
     660                function_exists( 'has_blocks' )
     661                && has_blocks( $the_post )
     662            ) {
     663                $this->filter_block_editor_post(
     664                    $the_post,
     665                    $paging_type,
     666                    $num_words,
     667                    $num_pages
     668                );
     669            } else {
     670                $this->filter_classic_editor_post(
     671                    $the_post,
     672                    $paging_type,
     673                    $num_words,
     674                    $num_pages
     675                );
     676            }
     677        }
     678
     679        return $posts;
     680    }
     681
     682    /**
     683     * Add pagination Quicktag to post authored in the Classic Editor.
     684     *
     685     * @param WP_Post|object $the_post    Post object.
     686     * @param string         $paging_type How to split post.
     687     * @param int            $num_words   Number of words to split on.
     688     * @param int            $num_pages   Number of pages to split to.
     689     * @return void
     690     */
     691    protected function filter_classic_editor_post(
     692        &$the_post,
     693        $paging_type,
     694        $num_words,
     695        $num_pages
     696    ) {
     697        // Start with post content, but alias to protect the raw content.
     698        $content = $the_post->post_content;
     699
     700        // Normalize post content to simplify paragraph counting and automatic paging. Accounts for content that hasn't been cleaned up by TinyMCE.
     701        $content = preg_replace( '#<p>(.+?)</p>#i', "$1\r\n\r\n", $content );
     702        $content = preg_replace( '#<br(\s*/)?>#i', "\r\n", $content );
     703        $content = explode( "\r\n\r\n", $content );
     704
     705        // Count number of paragraphs content was exploded to.
     706        $count = count( $content );
     707
     708        // Nothing to do, goodbye.
     709        if ( $count <= 1 ) {
     710            return;
     711        }
     712
     713        switch ( $paging_type ) {
     714            case 'words':
     715                $word_counter = 0;
     716
     717                // Count words per paragraph and break after the paragraph that exceeds the set threshold.
     718                foreach ( $content as $index => $paragraph ) {
     719                    $word_counter += mb_strlen(
     720                        wp_strip_all_tags(
     721                            $paragraph
     722                        )
     723                    );
     724
     725                    if ( $word_counter >= $num_words ) {
     726                        $content[ $index ] .= static::QUICKTAG;
     727                        $word_counter = 0;
     728                    }
     729                }
     730
     731                // Prevent the last page from being empty.
     732                $last_page = array_pop( $content );
     733                if (
     734                    static::QUICKTAG ===
     735                        substr(
     736                            $last_page,
     737                            - static::QUICKTAG_LENGTH
     738                        )
     739                    ) {
     740                    $content[] = substr(
     741                        $last_page,
     742                        0,
     743                        strlen( $last_page ) - static::QUICKTAG_LENGTH
     744                    );
     745                } else {
     746                    $content[] = $last_page;
     747                }
     748
     749                break;
     750
     751            case 'pages':
     752            default:
     753                $frequency = $this->get_insertion_frequency_by_pages(
     754                    $count,
     755                    $num_pages
     756                );
     757
     758                $i = 1;
     759
     760                // Loop through content pieces and append Quicktag as is appropriate.
     761                foreach ( $content as $key => $value ) {
     762                    if ( $this->is_at_end_for_pages( $key, $count ) ) {
     763                        break;
     764                    }
     765
     766                    if (
     767                        $this->is_insertion_point_for_pages(
     768                            $key,
     769                            $i,
     770                            $frequency
     771                        )
     772                    ) {
     773                        $content[ $key ] .= static::QUICKTAG;
     774                        $i++;
     775                    }
     776                }
     777
     778                break;
     779        }
     780
     781        // Reunite content.
     782        $content = implode( "\r\n\r\n", $content );
     783
     784        // And, overwrite the original content.
     785        $the_post->post_content = $content;
     786    }
     787
     788    /**
     789     * Add pagination block to post authored in the Block Editor.
     790     *
     791     * @param WP_Post $the_post    Post object.
     792     * @param string  $paging_type How to split post.
     793     * @param int     $num_words   Number of words to split on.
     794     * @param int     $num_pages   Number of pages to split to.
     795     * @return void
     796     */
     797    protected function filter_block_editor_post(
     798        &$the_post,
     799        $paging_type,
     800        $num_words,
     801        $num_pages
     802    ) {
     803        $blocks     = parse_blocks( $the_post->post_content );
     804        $new_blocks = array();
     805
     806        switch ( $paging_type ) {
     807            case 'words':
     808                $word_count = 0;
     809
     810                foreach ( $blocks as $block ) {
     811                    $new_blocks[] = $block;
     812
     813                    if (
     814                        in_array(
     815                            $block['blockName'],
     816                            $this->supported_block_types_for_word_counts,
     817                            true
     818                        )
     819                    ) {
     820                        $word_count += mb_strlen(
     821                            trim(
     822                                wp_strip_all_tags(
     823                                    $block['innerHTML']
     824                                )
     825                            )
     826                        );
     827
     828                        if ( $word_count >= $num_words ) {
     829                            $new_blocks[] = $this->get_parsed_nextpage_block();
     830
     831                            $word_count = 0;
    445832                        }
    446 
    447                         //Reunite content
    448                         $content = implode( "\r\n\r\n", $content );
    449 
    450                         //And, overwrite the original content
    451                         $the_post->post_content = $content;
    452833                    }
    453 
    454                     //Lastly, clean up.
    455                     unset( $num_pages );
    456                     unset( $num_words );
    457                     unset( $content );
    458                     unset( $count );
    459834                }
    460             }
    461         }
    462 
    463         return $posts;
     835
     836                $last_block = array_pop( $new_blocks );
     837                if ( $this->get_parsed_nextpage_block() !== $last_block ) {
     838                    $new_blocks[] = $last_block;
     839                }
     840                break;
     841
     842            case 'pages':
     843            default:
     844                $count = count( $blocks );
     845
     846                $frequency = $this->get_insertion_frequency_by_pages(
     847                    $count,
     848                    $num_pages
     849                );
     850
     851                $i = 1;
     852
     853                foreach ( $blocks as $key => $block ) {
     854                    $new_blocks[] = $block;
     855
     856                    if ( $this->is_at_end_for_pages( $key, $count ) ) {
     857                        break;
     858                    }
     859
     860                    if (
     861                        $this->is_insertion_point_for_pages(
     862                            $key,
     863                            $i,
     864                            $frequency
     865                        )
     866                    ) {
     867                        $new_blocks[] = $this->get_parsed_nextpage_block();
     868                        $i++;
     869                    }
     870                }
     871                break;
     872        }
     873
     874        $the_post->post_content = serialize_blocks( $new_blocks );
     875    }
     876
     877    /**
     878     * Determine after how many paragraphs a page break should be inserted.
     879     *
     880     * @param int $count     Total number of paragraphs.
     881     * @param int $num_pages Desired number of pages.
     882     * @return int
     883     */
     884    protected function get_insertion_frequency_by_pages( $count, $num_pages ) {
     885        $frequency = (int) round( $count / $num_pages );
     886
     887        // If number of pages is greater than number of paragraphs, put each paragraph on its own page.
     888        if ( $num_pages > $count ) {
     889            $frequency = 1;
     890        }
     891
     892        return $frequency;
     893    }
     894
     895    /**
     896     * Determine if more page breaks should be inserted.
     897     *
     898     * @param int $key   Current position in array of blocks.
     899     * @param int $count Total number of paragraphs.
     900     * @return bool
     901     */
     902    protected function is_at_end_for_pages( $key, $count ) {
     903        return ( $key + 1 ) === $count;
     904    }
     905
     906    /**
     907     * Determine if current loop iteration is where a page break is expected.
     908     *
     909     * @param int $loop_key            Current position in array of blocks.
     910     * @param int $insertion_iterator  Current number of page breaks inserted.
     911     * @param int $insertion_frequency After this many blocks a should break be
     912     *                                 inserted.
     913     * @return bool
     914     */
     915    protected function is_insertion_point_for_pages(
     916        $loop_key,
     917        $insertion_iterator,
     918        $insertion_frequency
     919    ) {
     920        return ( $loop_key + 1 ) ===
     921            ( $insertion_iterator * $insertion_frequency );
     922    }
     923
     924    /**
     925     * Create parsed representation of block for insertion in list of post's
     926     * blocks.
     927     *
     928     * @return array
     929     */
     930    protected function get_parsed_nextpage_block() {
     931        static $block;
     932
     933        if ( ! $block ) {
     934            $_block = parse_blocks(
     935                '<!-- wp:nextpage -->
     936' . static::QUICKTAG . '
     937<!-- /wp:nextpage -->'
     938            );
     939
     940            $block = array_shift( $_block );
     941        }
     942
     943        return $block;
    464944    }
    465945}
    466 new Automatically_Paginate_Posts;
     946
     947new Automatically_Paginate_Posts();
    467948?>
  • automatically-paginate-posts/tags/0.3/languages/automatically-paginate-posts.pot

    r2268447 r2749430  
    1 # Copyright (C) 2020 Erick Hitter & Oomph, Inc.
     1# Copyright (C) 2022 Erick Hitter & Oomph, Inc.
    22# This file is distributed under the same license as the Automatically Paginate Posts package.
    33msgid ""
    44msgstr ""
    5 "Project-Id-Version: Automatically Paginate Posts 0.2\n"
     5"Project-Id-Version: Automatically Paginate Posts 0.3\n"
    66"Report-Msgid-Bugs-To: "
    77"https://wordpress.org/support/plugin/automatically-paginate-posts\n"
    8 "POT-Creation-Date: 2020-03-26 17:10:56+00:00\n"
     8"POT-Creation-Date: 2022-06-29 04:16:26+00:00\n"
    99"MIME-Version: 1.0\n"
    1010"Content-Type: text/plain; charset=utf-8\n"
    1111"Content-Transfer-Encoding: 8bit\n"
    12 "PO-Revision-Date: 2020-MO-DA HO:MI+ZONE\n"
     12"PO-Revision-Date: 2022-MO-DA HO:MI+ZONE\n"
    1313"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
    1414"Language-Team: LANGUAGE <[email protected]>\n"
    15 "X-Generator: grunt-wp-i18n 0.5.4\n"
    16 "X-Poedit-KeywordsList: "
    17 "__;_e;_x:1,2c;_ex:1,2c;_n:1,2;_nx:1,2,4c;_n_noop:1,2;_nx_noop:1,2,3c;esc_"
    18 "attr__;esc_html__;esc_attr_e;esc_html_e;esc_attr_x:1,2c;esc_html_x:1,2c;\n"
    1915"Language: en\n"
    2016"Plural-Forms: nplurals=2; plural=(n != 1);\n"
    2117"X-Poedit-Country: United States\n"
    2218"X-Poedit-SourceCharset: UTF-8\n"
     19"X-Poedit-KeywordsList: "
     20"__;_e;_x:1,2c;_ex:1,2c;_n:1,2;_nx:1,2,4c;_n_noop:1,2;_nx_noop:1,2,3c;esc_"
     21"attr__;esc_html__;esc_attr_e;esc_html_e;esc_attr_x:1,2c;esc_html_x:1,2c;\n"
    2322"X-Poedit-Basepath: ../\n"
    2423"X-Poedit-SearchPath-0: .\n"
    2524"X-Poedit-Bookmarks: \n"
    2625"X-Textdomain-Support: yes\n"
     26"X-Generator: grunt-wp-i18n 1.0.3\n"
     27
     28#: automatically-paginate-posts.php:193
     29msgid "Post types can only be retrieved after the \"init\" hook."
     30msgstr ""
    2731
    2832#. Plugin Name of the plugin/theme
     
    3034msgstr ""
    3135
    32 #: automatically-paginate-posts.php:135
     36#: automatically-paginate-posts.php:327
    3337msgid "Supported post types:"
    3438msgstr ""
    3539
    36 #: automatically-paginate-posts.php:136
     40#: automatically-paginate-posts.php:328
    3741msgid "Split post by:"
    3842msgstr ""
    3943
    40 #: automatically-paginate-posts.php:210
    41 msgid "Total number of pages: "
     44#: automatically-paginate-posts.php:406
     45msgid "Total number of pages:"
    4246msgstr ""
    4347
    44 #: automatically-paginate-posts.php:211
    45 msgid "Approximate words per page: "
     48#: automatically-paginate-posts.php:407
     49msgid "Approximate words per page:"
    4650msgstr ""
    4751
    48 #: automatically-paginate-posts.php:275
     52#: automatically-paginate-posts.php:484
    4953msgid ""
    5054"If chosen, each page will contain approximately this many words, depending "
     
    5256msgstr ""
    5357
    54 #: automatically-paginate-posts.php:305
    55 msgid "Post Autopaging"
     58#: automatically-paginate-posts.php:521
     59msgid "Autopaging"
    5660msgstr ""
    5761
    58 #: automatically-paginate-posts.php:321
     62#: automatically-paginate-posts.php:537
     63msgid "Disable autopaging for this post?"
     64msgstr ""
     65
     66#: automatically-paginate-posts.php:540
    5967msgid ""
    6068"Check the box above to prevent this post from automatically being split "
     
    6270msgstr ""
    6371
    64 #: automatically-paginate-posts.php:322
     72#: automatically-paginate-posts.php:545
     73#. translators: 1. Quicktag code example.
    6574msgid ""
    6675"Note that if the %1$s Quicktag is used to manually page this post, "
    6776"automatic paging won't be applied, regardless of the setting above."
     77msgstr ""
     78
     79#: inc/class-block-editor.php:65
     80msgid "Whether or not to disable pagination for this post."
    6881msgstr ""
    6982
  • automatically-paginate-posts/tags/0.3/readme.txt

    r2268447 r2749430  
    44Tags: paginate, nextpage, Quicktag
    55Requires at least: 3.4
    6 Tested up to: 5.4
    7 Stable tag: 0.2
     6Tested up to: 6.0
     7Stable tag: 0.3
    88License: GPLv2 or later
    99License URI: http://www.gnu.org/licenses/gpl-2.0.html
    1010
    11 Automatically paginate posts by inserting the &lt;!--nextpage--&gt; Quicktag into WordPress posts, pages, or custom post type content.
     11Automatically paginate posts by inserting the `<!--nextpage-->` Quicktag.
    1212
    13 == DESCRIPTION ==
     13== Description ==
    1414
    15 Automatically paginate WordPress content by inserting the &lt;!--nextpage--&gt; Quicktag.
     15Automatically paginate WordPress content by inserting the `<!--nextpage-->` Quicktag at intervals controlled by plugin's settings.
    1616
    17 Option is provided to control what post types are automatically paginated (default is just `post`). Supports `post`, `page`, and any public custom post types.
     17Option is provided to control which post types are automatically paginated (default is the "Post" post type). Supports any public custom post types (non-public types are supported via the `autopaging_post_types` filter).
    1818
    1919Option is also provided to specify how many pages content should be broken out over, or how many words should be included per page.
     
    2121== Installation ==
    2222
    23 1. Upload automatically-paginate-posts to /wp-content/plugins/.
     231. Upload automatically-paginate-posts to `/wp-content/plugins/`.
    24242. Activate plugin through the WordPress Plugins menu.
    25 3. Configure plugin by going to Settings > Reading.
     253. Configure plugin by going to **Settings > Reading**.
    2626
    2727== Frequently Asked Questions ==
    2828
    29 = Where do I set the plugin's options =
     29= Where do I set the plugin's options? =
    3030The plugin's options are added to the built-in **Reading** settings page in WordPress.
    3131
    32 = Can I disable the plugin's functionality for specific posts, pages, or custom post type objects? =
    33 Yes, the plugin adds a metabox to individual items in supported post types that allows the autopaging to be disabled on a per-post basis.
     32= Can I disable the plugin's functionality for specific content? =
     33Yes, the plugin adds a metabox (Classic Editor) and a sidebar component (Block Editor) to individual items in supported post types that allows the autopaging to be disabled on a per-post basis.
    3434
    3535= How can I add support for my custom post type? =
    36 Navigate to Settings > Reading in WP Admin to enable this plugin for your custom post type.
     36Navigate to **Settings > Reading** in WP Admin to enable this plugin for your custom post type.
    3737
    3838You can also use the filter `autopaging_post_types` to add support by appending your post type's name to the array.
     
    4545* `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.
    4646* `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.
     47* `autopaging_supported_block_types_for_word_counts` - specify which block types are considered when splitting a block-editor post by word count.
    4748
    4849== Changelog ==
     50
     51= 0.3 =
     52* Add support for content authored in block editor (Gutenberg).
     53* Add native block-editor control to replace legacy metabox.
     54* Fix bug that created empty pages.
     55
     56= 0.2 =
     57* Allow for number of words to be specified instead of number of pages.
    4958
    5059= 0.1 =
    5160* Initial release.
    5261
     62== Upgrade Notice ==
     63
     64= 0.3 =
     65Add support for block editor and fix bug that created empty pages.
     66
    5367= 0.2 =
    54 * Allow for number of words to be specified instead of number of pages.
    55 
    56 == Upgrade Notice ==
     68Allow for number of words to be specified instead of number of pages.
    5769
    5870= 0.1 =
    5971Initial release
    60 
    61 = 0.2 =
    62 * Allow for number of words to be specified instead of number of pages.
  • automatically-paginate-posts/trunk/automatically-paginate-posts.php

    r869001 r2749430  
    1 <?php
    2 /*
    3 Plugin Name: Automatically Paginate Posts
    4 Plugin URI: http://www.oomphinc.com/plugins-modules/automatically-paginate-posts/
    5 Description: Automatically inserts the &lt;!--nextpage--&gt; Quicktag into WordPress posts, pages, or custom post type content.
    6 Version: 0.2
    7 Author: Erick Hitter & Oomph, Inc.
    8 Author URI: http://www.oomphinc.com/
    9 
    10 This program is free software; you can redistribute it and/or modify
    11 it under the terms of the GNU General Public License as published by
    12 the Free Software Foundation; either version 2 of the License, or
    13 (at your option) any later version.
    14 
    15 This program is distributed in the hope that it will be useful,
    16 but WITHOUT ANY WARRANTY; without even the implied warranty of
    17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    18 GNU General Public License for more details.
    19 
    20 You should have received a copy of the GNU General Public License
    21 along with this program; if not, write to the Free Software
    22 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    23 */
    24 
     1<?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
     2/**
     3 * Automatically inserts the &lt;!--nextpage--&gt; Quicktag into WordPress posts, pages, or custom post type content.
     4 *
     5 * Plugin Name: Automatically Paginate Posts
     6 * Plugin URI: http://www.oomphinc.com/plugins-modules/automatically-paginate-posts/
     7 * Description: Automatically inserts the &lt;!--nextpage--&gt; Quicktag into WordPress posts, pages, or custom post type content.
     8 * Version: 0.3
     9 * Author: Erick Hitter & Oomph, Inc.
     10 * Author URI: http://www.oomphinc.com/
     11 * Text Domain: autopaging
     12 * Domain Path: /languages/
     13 *
     14 * This program is free software; you can redistribute it and/or modify
     15 * it under the terms of the GNU General Public License as published by
     16 * the Free Software Foundation; either version 2 of the License, or
     17 * (at your option) any later version.
     18 *
     19 * This program is distributed in the hope that it will be useful,
     20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     22 * GNU General Public License for more details.
     23 *
     24 * You should have received a copy of the GNU General Public License
     25 * along with this program; if not, write to the Free Software
     26 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     27 *
     28 * @package automatically-paginate-posts
     29 */
     30
     31require_once dirname( __FILE__ ) . '/inc/class-block-editor.php';
     32
     33/**
     34 * Class Automatically_Paginate_Posts.
     35 */
    2536class Automatically_Paginate_Posts {
    2637    /**
    27      * Class variables
     38     * WordPress Quicktag that creates pagination.
     39     */
     40    const QUICKTAG = '<!--nextpage-->';
     41
     42    /**
     43     * String length of nextpage Quicktag.
     44     */
     45    const QUICKTAG_LENGTH = 15;
     46
     47    /**
     48     * Supported post types.
     49     *
     50     * @var array
    2851     */
    2952    private $post_types;
     53
     54    /**
     55     * Default supported post types.
     56     *
     57     * @var array
     58     */
    3059    private $post_types_default = array( 'post' );
    3160
     61    /**
     62     * Desired number of pages to split to.
     63     *
     64     * @var int
     65     */
    3266    private $num_pages;
     67
     68    /**
     69     * Method for splitting content, either words or desired number of pages.
     70     *
     71     * @var string
     72     */
    3373    private $paging_type_default = 'pages';
    34     private $num_pages_default   = 2;
    35     private $num_words_default   = '';
    36 
     74
     75    /**
     76     * Default number of pages to split to.
     77     *
     78     * @var int
     79     */
     80    private $num_pages_default = 2;
     81
     82    /**
     83     * Desired number of words per pages.
     84     *
     85     * @var int
     86     */
     87    private $num_words;
     88
     89    /**
     90     * Default number of words to split on.
     91     *
     92     * @var string|int
     93     */
     94    private $num_words_default = '';
     95
     96    /**
     97     * When splitting by word counts, these blocks are considered. Tags are
     98     * stripped and remaining content is counted.
     99     *
     100     * @var array
     101     */
     102    private $supported_block_types_for_word_counts = array(
     103        'core/paragraph',
     104    );
     105
     106    /**
     107     * Allowed split types.
     108     *
     109     * @var array
     110     */
    37111    private $paging_types_allowed = array( 'pages', 'words' );
    38112
    39     // Ensure option names match values in this::uninstall
    40     private $option_name_post_types  = 'autopaging_post_types';
     113    /**
     114     * Supported-post-types option name.
     115     *
     116     * @var string
     117     */
     118    private $option_name_post_types = 'autopaging_post_types';
     119
     120    /**
     121     * Split-type option name.
     122     *
     123     * @var string
     124     */
    41125    private $option_name_paging_type = 'pages';
    42     private $option_name_num_pages   = 'autopaging_num_pages';
    43     private $option_name_num_words   = 'autopaging_num_words';
    44 
     126
     127    /**
     128     * Option holding number of pages to split to.
     129     *
     130     * @var string
     131     */
     132    private $option_name_num_pages = 'autopaging_num_pages';
     133
     134    /**
     135     * Option holding number of words to split on.
     136     *
     137     * @var string
     138     */
     139    private $option_name_num_words = 'autopaging_num_words';
     140
     141    /**
     142     * Meta key used to indicate that a post shouldn't be automatically split.
     143     *
     144     * @var string
     145     */
    45146    private $meta_key_disable_autopaging = '_disable_autopaging';
    46147
    47148    /**
    48      * Register actions and filters
    49      *
    50      * @uses add_action, register_uninstall_hook, add_filter
    51      * @return null
     149     * Class constructor.
     150     *
     151     * @return void
    52152     */
    53153    public function __construct() {
    54         //Filters
     154        $this->setup_hooks();
     155
     156        new Automatically_Paginate_Posts\Block_Editor( $this );
     157    }
     158
     159    /**
     160     * Register hooks.
     161     *
     162     * @return void
     163     */
     164    protected function setup_hooks() {
     165        add_action( 'plugins_loaded', array( $this, 'load_textdomain' ) );
    55166        add_action( 'init', array( $this, 'action_init' ) );
    56167
    57         //Admin settings
     168        // Admin settings.
    58169        register_uninstall_hook( __FILE__, array( 'Automatically_Paginate_Posts', 'uninstall' ) );
    59170        add_filter( 'plugin_action_links', array( $this, 'filter_plugin_action_links' ), 10, 2 );
    60171        add_action( 'admin_init', array( $this, 'action_admin_init' ) );
    61172
    62         //Post-type settings
     173        // Post-type settings.
    63174        add_action( 'add_meta_boxes', array( $this, 'action_add_meta_boxes' ) );
    64175        add_action( 'save_post', array( $this, 'action_save_post' ) );
    65176        add_filter( 'the_posts', array( $this, 'filter_the_posts' ) );
    66177    }
    67 
    68     /**
    69      * Set post types this plugin can act on, either from Reading page or via filter
    70      * Also sets default number of pages to break content over, either from Reading page or via filter
     178    /**
     179     * Allow access to meta key for disabling autopaging.
     180     *
     181     * @param string $name Property name.
     182     * @return array|string|null
     183     */
     184    public function __get( $name ) {
     185        if ( 'meta_key' === $name ) {
     186            return $this->meta_key_disable_autopaging;
     187        }
     188
     189        if ( 'post_types' === $name ) {
     190            if ( ! did_action( 'init' ) ) {
     191                _doing_it_wrong(
     192                    __METHOD__,
     193                    esc_html__(
     194                        'Post types can only be retrieved after the "init" hook.',
     195                        'autopaging'
     196                    ),
     197                    '0.3'
     198                );
     199
     200                return null;
     201            }
     202
     203            return $this->post_types;
     204        }
     205
     206        return null;
     207    }
     208
     209    /**
     210     * Prevent setting properties.
     211     *
     212     * @param string $name  Property name.
     213     * @param string $value Property value.
     214     * @return false
     215     */
     216    public function __set( $name, $value ) {
     217        return false;
     218    }
     219
     220    /**
     221     * Indicate if a property is set.
     222     *
     223     * @param string $name Property name.
     224     * @return bool
     225     */
     226    public function __isset( $name ) {
     227        if ( 'meta_key' === $name ) {
     228            return true;
     229        }
     230
     231        if ( 'post_types' === $name ) {
     232            return did_action( 'init' );
     233        }
     234
     235        return false;
     236    }
     237
     238    /**
     239     * Load plugin translations.
     240     *
     241     * @return void
     242     */
     243    public function load_textdomain() {
     244        load_plugin_textdomain(
     245            'autopaging',
     246            false,
     247            dirname( plugin_basename( __FILE__ ) ) . '/languages/'
     248        );
     249    }
     250
     251    /**
     252     * Set post types this plugin can act on, either from Reading page or via filter.
     253     * Also sets default number of pages to break content over, either from Reading page or via filter.
    71254     *
    72255     * @uses apply_filters, get_option
    73256     * @action init
    74      * @return null
     257     * @return void
    75258     */
    76259    public function action_init() {
    77         //Post types
     260        // Post types.
    78261        $this->post_types = apply_filters( 'autopaging_post_types', get_option( $this->option_name_post_types, $this->post_types_default ) );
    79262
    80         //Number of pages to break over
     263        // Number of pages to break over.
    81264        $this->num_pages = absint( apply_filters( 'autopaging_num_pages_default', get_option( $this->option_name_num_pages, $this->num_pages_default ) ) );
    82         if ( 0 == $this->num_pages )
     265        if ( 0 == $this->num_pages ) {
    83266            $this->num_pages = $this->num_pages_default;
    84 
    85         //Number of words to break over
     267        }
     268
     269        // Number of words to break over.
    86270        $this->num_words = absint( apply_filters( 'autopaging_num_words_default', get_option( $this->option_name_num_words, $this->num_words_default ) ) );
    87         if ( 0 == $this->num_words )
     271        if ( 0 == $this->num_words ) {
    88272            $this->num_words = $this->num_words_default;
     273        }
     274
     275        // Supported blocks for splitting by words.
     276        $this->supported_block_types_for_word_counts = apply_filters(
     277            'autopaging_supported_block_types_for_word_counts',
     278            $this->supported_block_types_for_word_counts
     279        );
    89280    }
    90281
     
    95286     * @uses delete_option
    96287     * @action uninstall
    97      * @return null
     288     * @return void
    98289     */
    99290    public function uninstall() {
     
    107298     * Add settings link to plugin's row actions
    108299     *
    109      * @param array $actions
    110      * @param string $file
     300     * @param array  $actions Plugin's actions.
     301     * @param string $file    Plugin filename.
    111302     * @filter plugin_action_links,
    112303     */
    113304    public function filter_plugin_action_links( $actions, $file ) {
    114         if ( false !== strpos( $file, basename( __FILE__ ) ) )
    115             $actions[ 'settings' ] = '<a href="' . admin_url( 'options-reading.php' ) . '">Settings</a>';
     305        if ( false !== strpos( $file, basename( __FILE__ ) ) ) {
     306            $actions['settings'] = '<a href="' . admin_url( 'options-reading.php' ) . '">Settings</a>';
     307        }
    116308
    117309        return $actions;
     
    119311
    120312    /**
    121      * Register settings and settings sections
    122      * Settings appear on the Reading page
     313     * Register settings and settings sections.
     314     * Settings appear on the Reading page.
    123315     *
    124316     * @uses register_setting, add_settings_section, __, __return_false, add_settings_field
    125317     * @action admin_init
    126      * @return null
     318     * @return void
    127319     */
    128320    public function action_admin_init() {
     
    138330
    139331    /**
    140      * Render post types options
     332     * Render post types options.
    141333     *
    142334     * @uses get_post_types, get_option, esc_attr, checked, esc_html
    143      * @return string
     335     * @return void
    144336     */
    145337    public function settings_field_post_types() {
    146         //Get all public post types
    147         $post_types = get_post_types( array(
    148             'public' => true
    149         ), 'objects' );
    150 
    151         //Remove attachments
    152         unset( $post_types[ 'attachment' ] );
    153 
    154         //Current settings
     338        // Get all public post types.
     339        $post_types = get_post_types(
     340            array(
     341                'public' => true,
     342            ),
     343            'objects'
     344        );
     345
     346        unset( $post_types['attachment'] );
     347
     348        // Current settings.
    155349        $current_types = get_option( $this->option_name_post_types, $this->post_types_default );
    156350
    157         //Output checkboxes
     351        // Output checkboxes.
    158352        foreach ( $post_types as $post_type => $atts ) :
    159         ?>
     353            ?>
    160354            <input type="checkbox" name="<?php echo esc_attr( $this->option_name_post_types ); ?>[]" id="post-type-<?php echo esc_attr( $post_type ); ?>" value="<?php echo esc_attr( $post_type ); ?>"<?php checked( in_array( $post_type, $current_types ) ); ?> /> <label for="post-type-<?php echo esc_attr( $post_type ); ?>"><?php echo esc_html( $atts->label ); ?></label><br />
    161         <?php
     355            <?php
    162356        endforeach;
    163357    }
    164358
    165359    /**
    166      * Sanitize post type inputs
    167      *
    168      * @param array $post_types_checked
     360     * Sanitize post type inputs.
     361     *
     362     * @param array $post_types_checked Selected post types to sanitize.
    169363     * @uses get_post_types
    170364     * @return array
     
    173367        $post_types_sanitized = array();
    174368
    175         //Ensure that only existing, public post types are submitted as valid options
     369        // Ensure that only existing, public post types are submitted as valid options.
    176370        if ( is_array( $post_types_checked ) && ! empty( $post_types_checked ) ) {
    177             //Get all public post types
    178             $post_types = get_post_types( array(
    179                 'public' => true
    180             ) );
    181 
    182             //Remove attachments
    183             unset( $post_types[ 'attachment' ] );
    184 
    185             //Check input post types against those registered with WordPress and made available to this plugin
     371            // Get all public post types.
     372            $post_types = get_post_types(
     373                array(
     374                    'public' => true,
     375                )
     376            );
     377
     378            unset( $post_types['attachment'] );
     379
     380            // Check input post types against those registered with WordPress and made available to this plugin.
    186381            foreach ( $post_types_checked as $post_type ) {
    187                 if ( array_key_exists( $post_type, $post_types ) )
     382                if ( array_key_exists( $post_type, $post_types ) ) {
    188383                    $post_types_sanitized[] = $post_type;
     384                }
    189385            }
    190386        }
     
    194390
    195391    /**
    196      * Render option to choose paging type and options for that type
     392     * Render option to choose paging type and options for that type.
    197393     *
    198394     * @uses get_option()
    199395     * @uses esc_attr()
    200396     * @uses checked()
    201      * @return string
     397     * @return void
    202398     */
    203399    public function settings_field_paging_type() {
     
    208404
    209405        $labels = array(
    210             'pages' => __( 'Total number of pages: ', 'autopaging' ),
    211             'words' => __( 'Approximate words per page: ', 'autopaging' ),
     406            'pages' => __( 'Total number of pages:', 'autopaging' ),
     407            'words' => __( 'Approximate words per page:', 'autopaging' ),
    212408        );
    213409
    214410        foreach ( $this->paging_types_allowed as $type ) :
    215             $type_escaped = esc_attr( $type );
    216411            $func = 'settings_field_num_' . $type;
    217412            ?>
    218             <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; ?>">
    219                 <strong><?php echo $labels[ $type ]; ?></strong><?php $this->{$func}(); ?>
    220             </label></p>
    221         <?php endforeach;
    222     }
    223 
    224     /**
    225      * Validate chosen paging type against allowed values
    226      *
    227      * @param string
     413            <p>
     414                <input type="radio" name="<?php echo esc_attr( $this->option_name_paging_type ); ?>" id="autopaging-type-<?php echo esc_attr( $type ); ?>" value="<?php echo esc_attr( $type ); ?>"<?php checked( $type, $paging_type ); ?> />
     415                <label for="autopaging-type-<?php echo esc_attr( $type ); ?>">
     416                    <?php echo esc_html( $labels[ $type ] ); ?>
     417                    &nbsp;
     418                    <?php $this->{$func}(); ?>
     419                </label>
     420            </p>
     421            <br />
     422            <?php
     423        endforeach;
     424    }
     425
     426    /**
     427     * Validate chosen paging type against allowed values.
     428     *
     429     * @param string $type Selected paging type.
    228430     * @return string
    229431     */
    230432    public function sanitize_paging_type( $type ) {
    231         return in_array( $type, $this->paging_types_allowed ) ? $type : $this->paging_type_default;
    232     }
    233 
    234     /**
    235      * Render dropdown for choosing number of pages to break content over
     433        return in_array( $type, $this->paging_types_allowed, true ) ? $type : $this->paging_type_default;
     434    }
     435
     436    /**
     437     * Render dropdown for choosing number of pages to break content over.
    236438     *
    237439     * @uses get_option, apply_filters, esc_attr, selected
    238      * @return string
     440     * @return void
    239441     */
    240442    public function settings_field_num_pages() {
     
    244446        ?>
    245447            <select name="<?php echo esc_attr( $this->option_name_num_pages ); ?>">
    246                 <?php for( $i = 2; $i <= $max_pages; $i++ ) : ?>
     448                <?php for ( $i = 2; $i <= $max_pages; $i++ ) : ?>
    247449                    <option value="<?php echo intval( $i ); ?>"<?php selected( (int) $i, (int) $num_pages ); ?>><?php echo intval( $i ); ?></option>
    248450                <?php endfor; ?>
     
    252454
    253455    /**
    254      * Sanitize number of pages input
    255      *
    256      * @param int $num_pages
     456     * Sanitize number of pages input.
     457     *
     458     * @param int $num_pages Number of pages to split to.
    257459     * @uses apply_filters
    258460     * @return int
     
    263465
    264466    /**
    265      * Render input field for specifying approximate number of words each page should contain
     467     * Render input field for specifying approximate number of words each page should contain.
    266468     *
    267469     * @uses get_option, apply_filters, esc_attr, selected
    268      * @return string
     470     * @return void
    269471     */
    270472    public function settings_field_num_words() {
    271473        $num_words = apply_filters( 'autopaging_num_words', get_option( $this->option_name_num_words ) )
    272474        ?>
    273             <input name="<?php echo esc_attr( $this->option_name_num_words ); ?>" value="<?php echo esc_attr( $num_words ); ?>" size="4" />
    274 
    275             <p class="description"><?php _e( 'If chosen, each page will contain approximately this many words, depending on paragraph lengths.', 'autopaging' ); ?></p>
     475            <input
     476                name="<?php echo esc_attr( $this->option_name_num_words ); ?>"
     477                value="<?php echo esc_attr( $num_words ); ?>"
     478                class="small-text"
     479                type="number"
     480                step="1"
     481                min="1"
     482            />
     483
     484            <p class="description"><?php esc_html_e( 'If chosen, each page will contain approximately this many words, depending on paragraph lengths.', 'autopaging' ); ?></p>
    276485        <?php
    277486    }
    278487
    279488    /**
    280      * Sanitize number of words input. No fewer than 10 by default, filterable by autopaging_max_num_words
    281      *
    282      * @param int $num_words
     489     * Sanitize number of words input. No fewer than 10 by default, filterable by `autopaging_max_num_words`.
     490     *
     491     * @param int $num_words Number of words to split on.
    283492     * @uses apply_filters
    284493     * @return int
     
    295504
    296505    /**
    297      * Add autopaging metabox
     506     * Add autopaging metabox.
    298507     *
    299508     * @uses add_metabox, __
    300509     * @action add_meta_box
    301      * @return null
     510     * @return void
    302511     */
    303512    public function action_add_meta_boxes() {
    304513        foreach ( $this->post_types as $post_type ) {
    305             add_meta_box( 'autopaging', __( 'Post Autopaging', 'autopaging' ), array( $this, 'meta_box_autopaging' ), $post_type, 'side' );
    306         }
    307     }
    308 
    309     /**
    310      * Render autopaging metabox
    311      *
    312      * @param object $post
     514            if (
     515                function_exists( 'use_block_editor_for_post_type' ) &&
     516                use_block_editor_for_post_type( $post_type )
     517            ) {
     518                continue;
     519            }
     520
     521            add_meta_box( 'autopaging', __( 'Autopaging', 'autopaging' ), array( $this, 'meta_box_autopaging' ), $post_type, 'side' );
     522        }
     523    }
     524
     525    /**
     526     * Render autopaging metabox.
     527     *
     528     * @param object $post Post object.
    313529     * @uses esc_attr, checked, _e, __, wp_nonce_field
    314      * @return string
     530     * @return void
    315531     */
    316532    public function meta_box_autopaging( $post ) {
    317     ?>
     533        ?>
    318534        <p>
    319             <input type="checkbox" name="<?php echo esc_attr( $this->meta_key_disable_autopaging ); ?>" id="<?php echo esc_attr( $this->meta_key_disable_autopaging ); ?>_checkbox" value="1"<?php checked( (bool) get_post_meta( $post->ID, $this->meta_key_disable_autopaging, true ) ); ?> /> <label for="<?php echo esc_attr( $this->meta_key_disable_autopaging ); ?>_checkbox">Disable autopaging for this post?</label>
     535            <input type="checkbox" name="<?php echo esc_attr( $this->meta_key_disable_autopaging ); ?>" id="<?php echo esc_attr( $this->meta_key_disable_autopaging ); ?>_checkbox" value="1"<?php checked( (bool) get_post_meta( $post->ID, $this->meta_key_disable_autopaging, true ) ); ?> />
     536            <label for="<?php echo esc_attr( $this->meta_key_disable_autopaging ); ?>_checkbox">
     537                <?php esc_html_e( 'Disable autopaging for this post?', 'autopaging' ); ?>
     538            </label>
    320539        </p>
    321         <p class="description"><?php _e( 'Check the box above to prevent this post from automatically being split over multiple pages.', 'autopaging' ); ?></p>
    322         <p class="description"><?php printf( __( 'Note that if the %1$s Quicktag is used to manually page this post, automatic paging won\'t be applied, regardless of the setting above.', 'autopaging' ), '<code>&lt;!--nextpage--&gt;</code>' ); ?></p>
    323     <?php
     540        <p class="description"><?php esc_html__( 'Check the box above to prevent this post from automatically being split over multiple pages.', 'autopaging' ); ?></p>
     541        <p class="description">
     542            <?php
     543                printf(
     544                    /* translators: 1. Quicktag code example. */
     545                    esc_html__(
     546                        'Note that if the %1$s Quicktag is used to manually page this post, automatic paging won\'t be applied, regardless of the setting above.',
     547                        'autopaging'
     548                    ),
     549                    // No need to escape a class constant.
     550                    // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
     551                    '<code>' . htmlentities( static::QUICKTAG, ENT_QUOTES ) . '</code>'
     552                );
     553            ?>
     554        </p>
     555
     556        <?php
    324557        wp_nonce_field( $this->meta_key_disable_autopaging, $this->meta_key_disable_autopaging . '_wpnonce' );
    325558    }
    326559
    327560    /**
    328      * Save autopaging metabox
    329      *
    330      * @param int $post_id
     561     * Save autopaging metabox.
     562     *
     563     * @param int $post_id Post ID.
    331564     * @uses DOING_AUTOSAVE, wp_verify_nonce, update_post_meta, delete_post_meta
    332565     * @action save_post
     
    334567     */
    335568    public function action_save_post( $post_id ) {
    336         if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
     569        if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
    337570            return;
     571        }
     572
     573        if (
     574            function_exists( 'use_block_editor_for_post' )
     575            && use_block_editor_for_post( $post_id )
     576        ) {
     577            return;
     578        }
    338579
    339580        if ( isset( $_POST[ $this->meta_key_disable_autopaging . '_wpnonce' ] ) && wp_verify_nonce( $_POST[ $this->meta_key_disable_autopaging . '_wpnonce' ], $this->meta_key_disable_autopaging ) ) {
    340             $disable = isset( $_POST[ $this->meta_key_disable_autopaging ] ) ? true : false;
    341 
    342             if ( $disable )
     581            $disable = isset( $_POST[ $this->meta_key_disable_autopaging ] );
     582
     583            if ( $disable ) {
    343584                update_post_meta( $post_id, $this->meta_key_disable_autopaging, true );
    344             else
     585            } else {
    345586                delete_post_meta( $post_id, $this->meta_key_disable_autopaging );
     587            }
    346588        }
    347589    }
     
    351593     * Only applied if the post type matches specified options and post doesn't already contain the Quicktag.
    352594     *
    353      * @param array $posts
     595     * @param array $posts Array of posts retrieved by WP_Query.
    354596     * @uses is_admin, get_post_meta, absint, apply_filters
    355597     * @filter the_posts
     
    357599     */
    358600    public function filter_the_posts( $posts ) {
    359         if ( ! is_admin() ) {
    360             foreach( $posts as $the_post ) {
    361                 if ( in_array( $the_post->post_type, $this->post_types ) && ! preg_match( '#<!--nextpage-->#i', $the_post->post_content ) && ! (bool) get_post_meta( $the_post->ID, $this->meta_key_disable_autopaging, true ) ) {
    362                     //In-time filtering of number of pages to break over, based on post data. If value is less than 2, nothing should be done.
    363                     $num_pages = absint( apply_filters( 'autopaging_num_pages', absint( $this->num_pages ), $the_post ) );
    364                     $num_words = absint( apply_filters( 'autopaging_num_words', absint( $this->num_words ), $the_post ) );
    365 
    366                     if ( $num_pages < 2 && empty( $num_words ) )
    367                         continue;
    368 
    369                     //Start with post content, but alias to protect the raw content.
    370                     $content = $the_post->post_content;
    371 
    372                     //Normalize post content to simplify paragraph counting and automatic paging. Accounts for content that hasn't been cleaned up by TinyMCE.
    373                     $content = preg_replace( '#<p>(.+?)</p>#i', "$1\r\n\r\n", $content );
    374                     $content = preg_replace( '#<br(\s*/)?>#i', "\r\n", $content );
    375 
    376                     //Count paragraphs
    377                     $count = preg_match_all( '#\r\n\r\n#', $content, $matches );
    378 
    379                     //Keep going, if we have something to count.
    380                     if ( is_int( $count ) && 0 < $count ) {
    381                         //Explode content at double (or more) line breaks
    382                         $content = explode( "\r\n\r\n", $content );
    383 
    384                         switch ( get_option( $this->option_name_paging_type, $this->paging_type_default ) ) {
    385                             case 'words' :
    386                                 $word_counter = 0;
    387 
    388                                 // Count words per paragraph and break after the paragraph that exceeds the set threshold
    389                                 foreach ( $content as $index => $paragraph ) {
    390                                     $paragraph_words = count( preg_split( '/\s+/', strip_tags( $paragraph ) ) );
    391                                     $word_counter += $paragraph_words;
    392 
    393                                     if ( $word_counter >= $num_words ) {
    394                                         $content[ $index ] .= '<!--nextpage-->';
    395                                         $word_counter = 0;
    396                                     } else {
    397                                         continue;
    398                                     }
    399                                 }
    400 
    401                                 unset( $word_counter );
    402                                 unset( $index );
    403                                 unset( $paragraph );
    404                                 unset( $paragraph_words );
    405 
    406                                 break;
    407 
    408                             case 'pages' :
    409                             default :
    410                                 //Count number of paragraphs content was exploded to
    411                                 $count = count( $content );
    412 
    413                                 //Determine when to insert Quicktag
    414                                 $insert_every = $count / $num_pages;
    415                                 $insert_every_rounded = round( $insert_every );
    416 
    417                                 //If number of pages is greater than number of paragraphs, put each paragraph on its own page
    418                                 if ( $num_pages > $count ) {
    419                                     $insert_every_rounded = 1;
    420                                 }
    421 
    422                                 //Set initial counter position.
    423                                 $i = $count - 1 == $num_pages ? 2 : 1;
    424 
    425                                 //Loop through content pieces and append Quicktag as is appropriate
    426                                 foreach ( $content as $key => $value ) {
    427                                     if ( $key + 1 == $count ) {
    428                                         break;
    429                                     }
    430 
    431                                     if ( ( $key + 1 ) == ( $i * $insert_every_rounded ) ) {
    432                                         $content[ $key ] = $content[ $key ] . '<!--nextpage-->';
    433                                         $i++;
    434                                     }
    435                                 }
    436 
    437                                 //Clean up
    438                                 unset( $count );
    439                                 unset( $insert_every );
    440                                 unset( $insert_every_rounded );
    441                                 unset( $key );
    442                                 unset( $value );
    443 
    444                                 break;
     601        if ( is_admin() ) {
     602            return $posts;
     603        }
     604
     605        $paging_type = get_option(
     606            $this->option_name_paging_type,
     607            $this->paging_type_default
     608        );
     609
     610        foreach ( $posts as &$the_post ) {
     611            if (
     612                ! in_array(
     613                    $the_post->post_type,
     614                    $this->post_types,
     615                    true
     616                )
     617            ) {
     618                continue;
     619            }
     620
     621            if (
     622                preg_match(
     623                    '#' . static::QUICKTAG . '#i',
     624                    $the_post->post_content
     625                )
     626            ) {
     627                continue;
     628            }
     629
     630            if (
     631                (bool) get_post_meta(
     632                    $the_post->ID,
     633                    $this->meta_key_disable_autopaging,
     634                    true
     635                )
     636            ) {
     637                continue;
     638            }
     639
     640            $num_pages = absint(
     641                apply_filters(
     642                    'autopaging_num_pages',
     643                    absint( $this->num_pages ),
     644                    $the_post
     645                )
     646            );
     647            $num_words = absint(
     648                apply_filters(
     649                    'autopaging_num_words',
     650                    absint( $this->num_words ),
     651                    $the_post
     652                )
     653            );
     654
     655            if ( $num_pages < 2 && empty( $num_words ) ) {
     656                continue;
     657            }
     658
     659            if (
     660                function_exists( 'has_blocks' )
     661                && has_blocks( $the_post )
     662            ) {
     663                $this->filter_block_editor_post(
     664                    $the_post,
     665                    $paging_type,
     666                    $num_words,
     667                    $num_pages
     668                );
     669            } else {
     670                $this->filter_classic_editor_post(
     671                    $the_post,
     672                    $paging_type,
     673                    $num_words,
     674                    $num_pages
     675                );
     676            }
     677        }
     678
     679        return $posts;
     680    }
     681
     682    /**
     683     * Add pagination Quicktag to post authored in the Classic Editor.
     684     *
     685     * @param WP_Post|object $the_post    Post object.
     686     * @param string         $paging_type How to split post.
     687     * @param int            $num_words   Number of words to split on.
     688     * @param int            $num_pages   Number of pages to split to.
     689     * @return void
     690     */
     691    protected function filter_classic_editor_post(
     692        &$the_post,
     693        $paging_type,
     694        $num_words,
     695        $num_pages
     696    ) {
     697        // Start with post content, but alias to protect the raw content.
     698        $content = $the_post->post_content;
     699
     700        // Normalize post content to simplify paragraph counting and automatic paging. Accounts for content that hasn't been cleaned up by TinyMCE.
     701        $content = preg_replace( '#<p>(.+?)</p>#i', "$1\r\n\r\n", $content );
     702        $content = preg_replace( '#<br(\s*/)?>#i', "\r\n", $content );
     703        $content = explode( "\r\n\r\n", $content );
     704
     705        // Count number of paragraphs content was exploded to.
     706        $count = count( $content );
     707
     708        // Nothing to do, goodbye.
     709        if ( $count <= 1 ) {
     710            return;
     711        }
     712
     713        switch ( $paging_type ) {
     714            case 'words':
     715                $word_counter = 0;
     716
     717                // Count words per paragraph and break after the paragraph that exceeds the set threshold.
     718                foreach ( $content as $index => $paragraph ) {
     719                    $word_counter += mb_strlen(
     720                        wp_strip_all_tags(
     721                            $paragraph
     722                        )
     723                    );
     724
     725                    if ( $word_counter >= $num_words ) {
     726                        $content[ $index ] .= static::QUICKTAG;
     727                        $word_counter = 0;
     728                    }
     729                }
     730
     731                // Prevent the last page from being empty.
     732                $last_page = array_pop( $content );
     733                if (
     734                    static::QUICKTAG ===
     735                        substr(
     736                            $last_page,
     737                            - static::QUICKTAG_LENGTH
     738                        )
     739                    ) {
     740                    $content[] = substr(
     741                        $last_page,
     742                        0,
     743                        strlen( $last_page ) - static::QUICKTAG_LENGTH
     744                    );
     745                } else {
     746                    $content[] = $last_page;
     747                }
     748
     749                break;
     750
     751            case 'pages':
     752            default:
     753                $frequency = $this->get_insertion_frequency_by_pages(
     754                    $count,
     755                    $num_pages
     756                );
     757
     758                $i = 1;
     759
     760                // Loop through content pieces and append Quicktag as is appropriate.
     761                foreach ( $content as $key => $value ) {
     762                    if ( $this->is_at_end_for_pages( $key, $count ) ) {
     763                        break;
     764                    }
     765
     766                    if (
     767                        $this->is_insertion_point_for_pages(
     768                            $key,
     769                            $i,
     770                            $frequency
     771                        )
     772                    ) {
     773                        $content[ $key ] .= static::QUICKTAG;
     774                        $i++;
     775                    }
     776                }
     777
     778                break;
     779        }
     780
     781        // Reunite content.
     782        $content = implode( "\r\n\r\n", $content );
     783
     784        // And, overwrite the original content.
     785        $the_post->post_content = $content;
     786    }
     787
     788    /**
     789     * Add pagination block to post authored in the Block Editor.
     790     *
     791     * @param WP_Post $the_post    Post object.
     792     * @param string  $paging_type How to split post.
     793     * @param int     $num_words   Number of words to split on.
     794     * @param int     $num_pages   Number of pages to split to.
     795     * @return void
     796     */
     797    protected function filter_block_editor_post(
     798        &$the_post,
     799        $paging_type,
     800        $num_words,
     801        $num_pages
     802    ) {
     803        $blocks     = parse_blocks( $the_post->post_content );
     804        $new_blocks = array();
     805
     806        switch ( $paging_type ) {
     807            case 'words':
     808                $word_count = 0;
     809
     810                foreach ( $blocks as $block ) {
     811                    $new_blocks[] = $block;
     812
     813                    if (
     814                        in_array(
     815                            $block['blockName'],
     816                            $this->supported_block_types_for_word_counts,
     817                            true
     818                        )
     819                    ) {
     820                        $word_count += mb_strlen(
     821                            trim(
     822                                wp_strip_all_tags(
     823                                    $block['innerHTML']
     824                                )
     825                            )
     826                        );
     827
     828                        if ( $word_count >= $num_words ) {
     829                            $new_blocks[] = $this->get_parsed_nextpage_block();
     830
     831                            $word_count = 0;
    445832                        }
    446 
    447                         //Reunite content
    448                         $content = implode( "\r\n\r\n", $content );
    449 
    450                         //And, overwrite the original content
    451                         $the_post->post_content = $content;
    452833                    }
    453 
    454                     //Lastly, clean up.
    455                     unset( $num_pages );
    456                     unset( $num_words );
    457                     unset( $content );
    458                     unset( $count );
    459834                }
    460             }
    461         }
    462 
    463         return $posts;
     835
     836                $last_block = array_pop( $new_blocks );
     837                if ( $this->get_parsed_nextpage_block() !== $last_block ) {
     838                    $new_blocks[] = $last_block;
     839                }
     840                break;
     841
     842            case 'pages':
     843            default:
     844                $count = count( $blocks );
     845
     846                $frequency = $this->get_insertion_frequency_by_pages(
     847                    $count,
     848                    $num_pages
     849                );
     850
     851                $i = 1;
     852
     853                foreach ( $blocks as $key => $block ) {
     854                    $new_blocks[] = $block;
     855
     856                    if ( $this->is_at_end_for_pages( $key, $count ) ) {
     857                        break;
     858                    }
     859
     860                    if (
     861                        $this->is_insertion_point_for_pages(
     862                            $key,
     863                            $i,
     864                            $frequency
     865                        )
     866                    ) {
     867                        $new_blocks[] = $this->get_parsed_nextpage_block();
     868                        $i++;
     869                    }
     870                }
     871                break;
     872        }
     873
     874        $the_post->post_content = serialize_blocks( $new_blocks );
     875    }
     876
     877    /**
     878     * Determine after how many paragraphs a page break should be inserted.
     879     *
     880     * @param int $count     Total number of paragraphs.
     881     * @param int $num_pages Desired number of pages.
     882     * @return int
     883     */
     884    protected function get_insertion_frequency_by_pages( $count, $num_pages ) {
     885        $frequency = (int) round( $count / $num_pages );
     886
     887        // If number of pages is greater than number of paragraphs, put each paragraph on its own page.
     888        if ( $num_pages > $count ) {
     889            $frequency = 1;
     890        }
     891
     892        return $frequency;
     893    }
     894
     895    /**
     896     * Determine if more page breaks should be inserted.
     897     *
     898     * @param int $key   Current position in array of blocks.
     899     * @param int $count Total number of paragraphs.
     900     * @return bool
     901     */
     902    protected function is_at_end_for_pages( $key, $count ) {
     903        return ( $key + 1 ) === $count;
     904    }
     905
     906    /**
     907     * Determine if current loop iteration is where a page break is expected.
     908     *
     909     * @param int $loop_key            Current position in array of blocks.
     910     * @param int $insertion_iterator  Current number of page breaks inserted.
     911     * @param int $insertion_frequency After this many blocks a should break be
     912     *                                 inserted.
     913     * @return bool
     914     */
     915    protected function is_insertion_point_for_pages(
     916        $loop_key,
     917        $insertion_iterator,
     918        $insertion_frequency
     919    ) {
     920        return ( $loop_key + 1 ) ===
     921            ( $insertion_iterator * $insertion_frequency );
     922    }
     923
     924    /**
     925     * Create parsed representation of block for insertion in list of post's
     926     * blocks.
     927     *
     928     * @return array
     929     */
     930    protected function get_parsed_nextpage_block() {
     931        static $block;
     932
     933        if ( ! $block ) {
     934            $_block = parse_blocks(
     935                '<!-- wp:nextpage -->
     936' . static::QUICKTAG . '
     937<!-- /wp:nextpage -->'
     938            );
     939
     940            $block = array_shift( $_block );
     941        }
     942
     943        return $block;
    464944    }
    465945}
    466 new Automatically_Paginate_Posts;
     946
     947new Automatically_Paginate_Posts();
    467948?>
  • automatically-paginate-posts/trunk/languages/automatically-paginate-posts.pot

    r2268447 r2749430  
    1 # Copyright (C) 2020 Erick Hitter & Oomph, Inc.
     1# Copyright (C) 2022 Erick Hitter & Oomph, Inc.
    22# This file is distributed under the same license as the Automatically Paginate Posts package.
    33msgid ""
    44msgstr ""
    5 "Project-Id-Version: Automatically Paginate Posts 0.2\n"
     5"Project-Id-Version: Automatically Paginate Posts 0.3\n"
    66"Report-Msgid-Bugs-To: "
    77"https://wordpress.org/support/plugin/automatically-paginate-posts\n"
    8 "POT-Creation-Date: 2020-03-26 17:10:56+00:00\n"
     8"POT-Creation-Date: 2022-06-29 04:16:26+00:00\n"
    99"MIME-Version: 1.0\n"
    1010"Content-Type: text/plain; charset=utf-8\n"
    1111"Content-Transfer-Encoding: 8bit\n"
    12 "PO-Revision-Date: 2020-MO-DA HO:MI+ZONE\n"
     12"PO-Revision-Date: 2022-MO-DA HO:MI+ZONE\n"
    1313"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
    1414"Language-Team: LANGUAGE <[email protected]>\n"
    15 "X-Generator: grunt-wp-i18n 0.5.4\n"
    16 "X-Poedit-KeywordsList: "
    17 "__;_e;_x:1,2c;_ex:1,2c;_n:1,2;_nx:1,2,4c;_n_noop:1,2;_nx_noop:1,2,3c;esc_"
    18 "attr__;esc_html__;esc_attr_e;esc_html_e;esc_attr_x:1,2c;esc_html_x:1,2c;\n"
    1915"Language: en\n"
    2016"Plural-Forms: nplurals=2; plural=(n != 1);\n"
    2117"X-Poedit-Country: United States\n"
    2218"X-Poedit-SourceCharset: UTF-8\n"
     19"X-Poedit-KeywordsList: "
     20"__;_e;_x:1,2c;_ex:1,2c;_n:1,2;_nx:1,2,4c;_n_noop:1,2;_nx_noop:1,2,3c;esc_"
     21"attr__;esc_html__;esc_attr_e;esc_html_e;esc_attr_x:1,2c;esc_html_x:1,2c;\n"
    2322"X-Poedit-Basepath: ../\n"
    2423"X-Poedit-SearchPath-0: .\n"
    2524"X-Poedit-Bookmarks: \n"
    2625"X-Textdomain-Support: yes\n"
     26"X-Generator: grunt-wp-i18n 1.0.3\n"
     27
     28#: automatically-paginate-posts.php:193
     29msgid "Post types can only be retrieved after the \"init\" hook."
     30msgstr ""
    2731
    2832#. Plugin Name of the plugin/theme
     
    3034msgstr ""
    3135
    32 #: automatically-paginate-posts.php:135
     36#: automatically-paginate-posts.php:327
    3337msgid "Supported post types:"
    3438msgstr ""
    3539
    36 #: automatically-paginate-posts.php:136
     40#: automatically-paginate-posts.php:328
    3741msgid "Split post by:"
    3842msgstr ""
    3943
    40 #: automatically-paginate-posts.php:210
    41 msgid "Total number of pages: "
     44#: automatically-paginate-posts.php:406
     45msgid "Total number of pages:"
    4246msgstr ""
    4347
    44 #: automatically-paginate-posts.php:211
    45 msgid "Approximate words per page: "
     48#: automatically-paginate-posts.php:407
     49msgid "Approximate words per page:"
    4650msgstr ""
    4751
    48 #: automatically-paginate-posts.php:275
     52#: automatically-paginate-posts.php:484
    4953msgid ""
    5054"If chosen, each page will contain approximately this many words, depending "
     
    5256msgstr ""
    5357
    54 #: automatically-paginate-posts.php:305
    55 msgid "Post Autopaging"
     58#: automatically-paginate-posts.php:521
     59msgid "Autopaging"
    5660msgstr ""
    5761
    58 #: automatically-paginate-posts.php:321
     62#: automatically-paginate-posts.php:537
     63msgid "Disable autopaging for this post?"
     64msgstr ""
     65
     66#: automatically-paginate-posts.php:540
    5967msgid ""
    6068"Check the box above to prevent this post from automatically being split "
     
    6270msgstr ""
    6371
    64 #: automatically-paginate-posts.php:322
     72#: automatically-paginate-posts.php:545
     73#. translators: 1. Quicktag code example.
    6574msgid ""
    6675"Note that if the %1$s Quicktag is used to manually page this post, "
    6776"automatic paging won't be applied, regardless of the setting above."
     77msgstr ""
     78
     79#: inc/class-block-editor.php:65
     80msgid "Whether or not to disable pagination for this post."
    6881msgstr ""
    6982
  • automatically-paginate-posts/trunk/readme.txt

    r2268447 r2749430  
    44Tags: paginate, nextpage, Quicktag
    55Requires at least: 3.4
    6 Tested up to: 5.4
    7 Stable tag: 0.2
     6Tested up to: 6.0
     7Stable tag: 0.3
    88License: GPLv2 or later
    99License URI: http://www.gnu.org/licenses/gpl-2.0.html
    1010
    11 Automatically paginate posts by inserting the &lt;!--nextpage--&gt; Quicktag into WordPress posts, pages, or custom post type content.
     11Automatically paginate posts by inserting the `<!--nextpage-->` Quicktag.
    1212
    13 == DESCRIPTION ==
     13== Description ==
    1414
    15 Automatically paginate WordPress content by inserting the &lt;!--nextpage--&gt; Quicktag.
     15Automatically paginate WordPress content by inserting the `<!--nextpage-->` Quicktag at intervals controlled by plugin's settings.
    1616
    17 Option is provided to control what post types are automatically paginated (default is just `post`). Supports `post`, `page`, and any public custom post types.
     17Option is provided to control which post types are automatically paginated (default is the "Post" post type). Supports any public custom post types (non-public types are supported via the `autopaging_post_types` filter).
    1818
    1919Option is also provided to specify how many pages content should be broken out over, or how many words should be included per page.
     
    2121== Installation ==
    2222
    23 1. Upload automatically-paginate-posts to /wp-content/plugins/.
     231. Upload automatically-paginate-posts to `/wp-content/plugins/`.
    24242. Activate plugin through the WordPress Plugins menu.
    25 3. Configure plugin by going to Settings > Reading.
     253. Configure plugin by going to **Settings > Reading**.
    2626
    2727== Frequently Asked Questions ==
    2828
    29 = Where do I set the plugin's options =
     29= Where do I set the plugin's options? =
    3030The plugin's options are added to the built-in **Reading** settings page in WordPress.
    3131
    32 = Can I disable the plugin's functionality for specific posts, pages, or custom post type objects? =
    33 Yes, the plugin adds a metabox to individual items in supported post types that allows the autopaging to be disabled on a per-post basis.
     32= Can I disable the plugin's functionality for specific content? =
     33Yes, the plugin adds a metabox (Classic Editor) and a sidebar component (Block Editor) to individual items in supported post types that allows the autopaging to be disabled on a per-post basis.
    3434
    3535= How can I add support for my custom post type? =
    36 Navigate to Settings > Reading in WP Admin to enable this plugin for your custom post type.
     36Navigate to **Settings > Reading** in WP Admin to enable this plugin for your custom post type.
    3737
    3838You can also use the filter `autopaging_post_types` to add support by appending your post type's name to the array.
     
    4545* `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.
    4646* `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.
     47* `autopaging_supported_block_types_for_word_counts` - specify which block types are considered when splitting a block-editor post by word count.
    4748
    4849== Changelog ==
     50
     51= 0.3 =
     52* Add support for content authored in block editor (Gutenberg).
     53* Add native block-editor control to replace legacy metabox.
     54* Fix bug that created empty pages.
     55
     56= 0.2 =
     57* Allow for number of words to be specified instead of number of pages.
    4958
    5059= 0.1 =
    5160* Initial release.
    5261
     62== Upgrade Notice ==
     63
     64= 0.3 =
     65Add support for block editor and fix bug that created empty pages.
     66
    5367= 0.2 =
    54 * Allow for number of words to be specified instead of number of pages.
    55 
    56 == Upgrade Notice ==
     68Allow for number of words to be specified instead of number of pages.
    5769
    5870= 0.1 =
    5971Initial release
    60 
    61 = 0.2 =
    62 * Allow for number of words to be specified instead of number of pages.
Note: See TracChangeset for help on using the changeset viewer.