/home/sylamedg/public_html/wp-content/plugins/cc-child-pages/includes/ccchildpages.php
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
/**
* ccchildpages
*/
class ccchildpages {
// Used to uniquely identify this plugin's menu page in the WP manager
const admin_menu_slug = 'ccchildpages';
// Plugin name
const plugin_name = 'CC Child Pages';
// Plugin version
const plugin_version = '1.43';
// ID Count
protected static $cc_id_counter;
// Initialise class
public static function init( $value = 0 ) {
self::$cc_id_counter = $value;
}
// Get unique ID
public static function get_unique_id() {
++self::$cc_id_counter;
return self::$cc_id_counter;
}
public static function load_plugin_textdomain() {
load_plugin_textdomain( 'cc-child-pages', false, dirname( dirname( plugin_basename( __FILE__ ) ) ) . '/languages/' );
}
public static function show_child_pages( $atts ) {
// Get unique id for this instance of CC Child Pages
$cc_uid = self::get_unique_id();
// Store current page ID
$cc_current_page_id = get_the_ID();
// Store image size details in case we need to output Video Thumbnails, etc. which may be external files
$img_sizes = get_intermediate_image_sizes();
$img_sizes[] = 'full'; // allow "virtual" image size ...
$default_atts = apply_filters(
'ccchildpages_defaults',
array(
'id' => get_the_ID(),
'page_ids' => '',
'posts_per_page' => -1,
'limit' => -1,
'page' => -1,
'cols' => '',
'depth' => '1',
'exclude' => '',
'exclude_tree' => '',
'skin' => 'simple',
'class' => '',
'orderby' => 'menu_order',
'order' => 'ASC',
'link_titles' => 'false',
'title_link_class' => 'ccpage_title_link',
'hide_title' => 'false',
'hide_more' => 'false',
'hide_excerpt' => 'false',
'show_page_content' => 'false',
'truncate_excerpt' => 'true',
'list' => 'false',
'link_thumbs' => 'false',
'thumbs' => 'false',
'lazy_load' => 'false',
'async_load' => 'false',
'more' => __( 'Read more ...', 'cc-child-pages' ),
'link' => '',
'siblings' => 'false',
'show_current_page' => 'false',
'hide_wp_more' => 'false',
'use_custom_excerpt' => '',
'use_custom_title' => '',
'use_custom_more' => '',
'use_custom_link' => 'cc_child_pages_link',
'use_custom_link_target' => 'cc_child_pages_link_target',
'use_custom_thumbs' => '',
'use_legacy_css' => 'false',
'ignore_sticky_posts' => 'true',
'offset' => 0,
'words' => 55,
'subpage_title' => '',
'link_target' => '',
'show_author' => 'false',
'show_date_created' => 'false',
'show_date_modified' => 'false',
'post_status' => '',
)
);
$a = shortcode_atts( $default_atts, $atts );
$a = apply_filters( 'ccchildpages_attributes', $a );
// If we are displaying siblings, set starting point to page parent and add current page to exclude list
if ( strtolower( trim( $a['siblings'] ) ) == 'true' ) {
$a['id'] = wp_get_post_parent_id( get_the_ID() ) ? wp_get_post_parent_id( get_the_ID() ) : 0;
if ( strtolower( trim( $a['show_current_page'] ) ) != 'true' ) {
if ( $a['exclude'] != '' ) {
$a['exclude'] .= ',';
}
$a['exclude'] .= get_the_ID();
}
}
$depth = intval( $a['depth'] );
if ( strtolower( trim( $a['list'] ) ) != 'true' && $a['cols'] == '' ) {
$a['cols'] = '3';
}
switch ( $a['cols'] ) {
case '6':
$class = 'sixcol';
$cols = 6;
break;
case '5':
$class = 'fivecol';
$cols = 5;
break;
case '4':
$class = 'fourcol';
$cols = 4;
break;
case '3':
$class = 'threecol';
$cols = 3;
break;
case '2':
$class = 'twocol';
$cols = 2;
break;
case '1':
$class = 'onecol';
$cols = 1;
break;
default:
$class = '';
$cols = 1;
}
$default_skins = self::default_skin_list();
$available_skins = self::skin_list();
$skin_param = trim( strtolower( $a['skin'] ) );
if ( array_key_exists( $skin_param, $available_skins ) ) {
$skin = ( $skin_param !== 'simple' && array_key_exists( $skin_param, $default_skins ) ) ? 'cc' . $skin_param : $skin_param;
} else {
$skin = 'simple';
}
if ( strtolower( trim( $a['list'] ) ) == 'true' ) {
$list = true;
} else {
$list = false;
}
if ( strtolower( trim( $a['truncate_excerpt'] ) ) == 'true' ) {
$truncate_excerpt = true;
} else {
$truncate_excerpt = false;
}
if ( strtolower( trim( $a['link_titles'] ) ) == 'true' ) {
$link_titles = true;
$title_link_class = self::sanitize_class_list( $a['title_link_class'] );
} else {
$link_titles = false;
}
if ( strtolower( trim( $a['hide_more'] ) ) == 'true' ) {
$hide_more = true;
} else {
$hide_more = false;
}
if ( strtolower( trim( $a['hide_title'] ) ) == 'true' ) {
$hide_title = true;
} else {
$hide_title = false;
}
if ( strtolower( trim( $a['hide_wp_more'] ) ) == 'true' ) {
$hide_wp_more = true;
} else {
$hide_wp_more = false;
}
if ( strtolower( trim( $a['hide_excerpt'] ) ) == 'true' ) {
$hide_excerpt = true;
} else {
$hide_excerpt = false;
}
if ( strtolower( trim( $a['show_page_content'] ) ) == 'true' ) {
$show_page_content = true;
} else {
$show_page_content = false;
}
if ( strtolower( trim( $a['ignore_sticky_posts'] ) ) == 'true' ) {
$ignore_sticky_posts = true;
} else {
$ignore_sticky_posts = false;
}
if ( strtolower( trim( $a['show_author'] ) ) == 'true' ) {
$show_author = true;
} else {
$show_author = false;
}
if ( strtolower( trim( $a['show_date_created'] ) ) == 'true' ) {
$show_date_created = true;
} else {
$show_date_created = false;
}
if ( strtolower( trim( $a['show_date_modified'] ) ) == 'true' ) {
$show_date_modified = true;
} else {
$show_date_modified = false;
}
$offset = ( intval( $a['offset'] ) > 0 ) ? intval( $a['offset'] ) : 0;
if ( $a['order'] == 'ASC' ) {
$order = 'ASC';
} else {
$order = 'DESC';
}
switch ( $a['orderby'] ) {
case 'post_id':
case 'id':
case 'ID':
$orderby = 'ID';
break;
case 'post_author':
case 'author':
if ( $list ) {
$orderby = 'post_author';
} else {
$orderby = 'author';
}
break;
case 'random':
case 'rand':
case 'RANDOM':
case 'RAND':
$orderby = 'rand';
break;
case 'post_date':
case 'date':
if ( $list ) {
$orderby = 'post_date';
} else {
$orderby = 'date';
}
break;
case 'post_modified':
case 'modified':
if ( $list ) {
$orderby = 'post_modified';
} else {
$orderby = 'modified';
}
break;
case 'post_title':
case 'title':
if ( $list ) {
$orderby = 'post_title';
} else {
$orderby = 'title';
}
break;
case 'post_name':
case 'name':
case 'slug':
if ( $list ) {
$orderby = 'post_name';
} else {
$orderby = 'name';
}
break;
default:
$orderby = 'menu_order';
}
if ( $a['post_status'] == '' ) {
$post_status = '';
} else {
$post_status = explode( ',', $a['post_status'] );
}
if ( strtolower( trim( $a['link_thumbs'] ) ) == 'true' ) {
$link_thumbs = true;
} else {
$link_thumbs = false;
}
if ( strtolower( trim( $a['thumbs'] ) ) == 'true' ) {
$thumbs = 'medium';
} elseif ( strtolower( trim( $a['thumbs'] ) ) == 'false' ) {
$thumbs = false;
} else {
$thumbs = strtolower( trim( $a['thumbs'] ) );
if ( ! in_array( $thumbs, $img_sizes ) ) {
$thumbs = 'medium';
}
}
$more = esc_html( trim( $a['more'] ) ); // default
// if class is specified, substitue value for skin class
if ( $a['class'] != '' ) {
$skin = self::sanitize_class_list( $a['class'] );
}
$css_version_class = self::css_version();
$use_legacy_css = trim( strtolower( $a['use_legacy_css'] ) );
if ( $use_legacy_css === 'true' ) {
$css_version_class = 'cclegacy';
}
$outer_template = str_replace( '{{class}}', $class, apply_filters( 'ccchildpages_outer_template', '<div id="ccchildpages-' . $cc_uid . '" class="ccchildpages ' . apply_filters( 'ccchildpages_css_version', $css_version_class, $a ) . ' {{class}} {{skin}} ccclearfix">{{ccchildpages}}</div>', $a ) );
$outer_template = str_replace( '{{skin}}', $skin, $outer_template );
$inner_template = apply_filters( 'ccchildpages_inner_template', '<div class="ccchildpage {{page_class}}">{{title_tag}}{{meta}}{{thumbnail}}{{excerpt}}{{more}}</div>', $a );
$title_template = apply_filters(
'ccchildpages_title_template',
'<h3{{title_class}}>{{title}}</h3>',
$a
);
$meta_template = apply_filters( 'ccchildpages_meta_template', '<p class="small cc-meta-info">{{meta}}</p>', $a );
// $return_html = '<div class="ccchildpages ' . $class .' ' . $skin . ' ccclearfix">';
$page_id = $a['id'];
if ( $list ) {
$args = array(
'title_li' => '',
'child_of' => $page_id,
'echo' => 0,
'depth' => $depth,
'exclude' => $a['exclude'],
'sort_order' => $order,
'sort_column' => $orderby,
);
if ( is_array( $post_status ) || $post_status != '' ) {
$args['post_status'] = $post_status;
}
$post_type = get_post_type( $page_id );
$args['post_type'] = $post_type;
$args = apply_filters( 'ccchildpages_list_pages_args', $args, $a );
$page_count = 0;
$return_html = '<ul class="ccchildpages_list ccclearfix">';
$page_list = trim( wp_list_pages( $args ) );
if ( $page_list == '' ) {
return '';
}
$return_html .= $page_list;
$return_html .= '</ul>';
} else {
$return_html = '';
$posts_array = explode( ',', $page_id ); // Allow for comma separated lists of IDs
$post_count = count( $posts_array );
$posts_per_page = intval( $a['posts_per_page'] );
$page = intval( $a['page'] );
$ccpage_var = ( is_front_page() ? 'page' : 'ccpage' . $cc_uid );
$ccpaged = ( get_query_var( $ccpage_var ) ) ? absint( get_query_var( $ccpage_var ) ) : 1;
$args = array(
// 'post_type' => 'page',
// 'post_type' => $post_type,
'posts_per_page' => $posts_per_page,
// 'post_parent' => $page_id,
'order' => $order,
'orderby' => $orderby,
// 'post__not_in' => explode(',', $a['exclude']),
'ignore_sticky_posts' => $ignore_sticky_posts,
);
if ( is_array( $post_status ) || $post_status != '' ) {
$args['post_status'] = $post_status;
}
if ( trim( $a['exclude'] ) != '' ) {
$args['post__not_in'] = explode( ',', $a['exclude'] );
}
if ( $posts_per_page > 0 ) {
$args['paged'] = $ccpaged;
// If page has been set manually, override any pagination
if ( $page > 0 ) {
$args['paged'] = $page;
}
} elseif ( intval( $a['limit'] ) > 0 ) {
// If limit is specified, show only that number of pages
$args['posts_per_page'] = intval( $a['limit'] );
$args['paged'] = 1;
}
if ( $offset > 0 ) {
$args['offset'] = $offset;
}
if ( $post_count > 1 ) {
// Multiple IDs specified, so set the post_parent__in parameter
$args['post_parent__in'] = $posts_array;
/*
// get post_type for each post specified ...
$post_type_array = array();
foreach ( $posts_array as $post_id ) {
// Get post_type
$post_type = get_post_type( $post_id );
if ( ! in_array($post_type, $post_type_array) ) $post_type_array[] = $post_type;
}
$args['post_type'] = $post_type_array; */
$args['post_type'] = 'any';
} else {
// Single ID specified, so set the post_parent parameter
$args['post_parent'] = $page_id;
$args['post_type'] = get_post_type( $page_id );
}
if ( $a['page_ids'] != '' ) {
// Multiple specific posts specified, so unset unwanted values in $args then build the lists of IDs
unset( $args['post_parent'] );
unset( $args['post_parent__in'] );
$posts_array = explode( ',', $a['page_ids'] );
$args['post__in'] = $posts_array;
$args['orderby'] = 'post__in';
/*
// get post_type for each post specified ...
$post_type_array = array();
foreach ( $posts_array as $post_id ) {
// Get post_type
$post_type = get_post_type( $post_id );
if ( ! in_array($post_type, $post_type_array) ) $post_type_array[] = $post_type;
}
$args['post_type'] = $post_type_array; */
$args['post_type'] = 'any';
}
$args['ccchildpages'] = 'true';
$args = apply_filters( 'ccchildpages_query_args', $args, $a );
$parent = new WP_Query( $args );
if ( ! $parent->have_posts() ) {
return '';
}
$page_count = 0;
while ( $parent->have_posts() ) {
$tmp_html = $inner_template;
$parent->the_post();
$id = get_the_ID();
++$page_count;
if ( $page_count % $cols == 0 && $cols > 1 ) {
$page_class = ' cclast';
} elseif ( $page_count % $cols == 1 && $cols > 1 ) {
$page_class = ' ccfirst';
} else {
$page_class = '';
}
if ( $page_count % 2 == 0 ) {
$page_class .= ' cceven';
} else {
$page_class .= ' ccodd';
}
$page_class .= ' ccpage-count-' . $page_count;
$page_class .= ' ccpage-id-' . $id;
$page_class .= ' ccpage-' . self::the_slug( $id );
// Check to see if this page has a parent, and if it has add classes for the id and slug
if ( $page_parent_id = wp_get_post_parent_id( $id ) ) {
$page_class .= ' ccpage-has-parent';
$page_class .= ' ccpage-pid-' . $page_parent_id;
$page_class .= ' ccpage-parent-' . self::the_slug( $page_parent_id );
} else {
$page_class .= ' ccpage-top-level';
$page_class .= ' ccpage-pid-0';
}
/* Check to see if link has been specified */
if ( $a['link'] == '' ) {
$link = get_permalink( $id );
} else {
$link = esc_url( $a['link'] );
}
/* Check to see if custom link has been specified */
$use_custom_link = sanitize_key( $a['use_custom_link'] );
if ( ! empty( $use_custom_link ) ) {
// Retrieve raw meta value (could be anything)
$raw_meta_link = get_post_meta( $id, $use_custom_link, true );
if ( ! empty( $raw_meta_link ) ) {
// Trim whitespace
$raw_meta_link = trim( $raw_meta_link );
// Sanitize URL safely for storage/use
$sanitized_link = esc_url_raw( $raw_meta_link );
// Only update $link if we have a valid-looking URL
if ( ! empty( $sanitized_link ) ) {
$link = $sanitized_link;
}
}
}
/* Check to see if target has been specified */
if ( $a['link_target'] == '' ) {
$link_target = '';
} else {
$link_target = sanitize_html_class( $a['link_target'] );
}
/* Check to see if custom target has been specified */
$use_custom_link_target = sanitize_key( $a['use_custom_link_target'] );
if ( ! empty( $use_custom_link_target ) ) {
$raw_meta_link_target = get_post_meta( $id, $use_custom_link_target, true );
if ( is_string( $raw_meta_link_target ) ) {
$raw_meta_link_target = trim( $raw_meta_link_target );
} else {
$raw_meta_link_target = '';
}
if ( $raw_meta_link_target !== '' ) {
// Base sanitisation for text
$sanitized_target = sanitize_text_field( $raw_meta_link_target );
// Option A: allow only the standard targets (strict & safest)
$allowed_targets = array( '_self', '_blank', '_parent', '_top' );
if ( in_array( $sanitized_target, $allowed_targets, true ) ) {
$link_target = $sanitized_target;
} else {
// Option B: in order to support custom named targets (frames),
// restrict to a safe character set so it can't break HTML.
$custom_target = preg_replace( '/[^A-Za-z0-9_\-]/', '', $sanitized_target );
if ( $custom_target !== '' ) {
$link_target = $custom_target;
}
// If it ends up empty, we silently keep the existing $link_target
}
}
}
if ( $id == $cc_current_page_id ) {
$page_class .= ' active current-page cccurrent';
}
$tmp_html = str_replace( '{{page_class}}', $page_class, $tmp_html );
$title_value = get_the_title(); // default
$use_custom_title = trim( $a['use_custom_title'] );
$meta_title = ''; // default - no meta_title
// If meta title field specified, get the value
if ( $use_custom_title != '' ) {
// Get value of custom field to be used as title
$meta_title = trim( get_post_meta( $id, $use_custom_title, true ) );
// If value from custom field is set, use that - otherwise use page title
if ( $meta_title != '' ) {
$title_value = esc_html( trim( $meta_title ) );
}
}
if ( ! $link_titles ) {
$title_html = $title_value;
$title_class = ' class="ccpage_title" title="' . esc_attr( $title_value ) . '"';
} else {
$title_html = '<a class="' . esc_attr( $title_link_class ) . '" href="' . esc_url( $link ) . '"';
if ( $link_target != '' ) {
$title_html .= ' target="' . esc_attr( $link_target ) . '"';
}
$title_html .= ' title="' . $title_value . '">' . $title_value . '</a>';
$title_class = ' class="ccpage_title ccpage_linked_title" title="' . esc_attr( $title_value ) . '"';
}
$tmp_title = ( $hide_title ) ? '' : $title_template; // if hide_title is true, our tmp title is empty
$tmp_html = str_replace( '{{title_tag}}', $tmp_title, $tmp_html ); // inject our tmp_title tag into the template
$tmp_html = str_replace( '{{title}}', $title_html, $tmp_html );
$tmp_html = str_replace( '{{title_class}}', $title_class, $tmp_html );
$meta = array();
if ( $show_author ) {
$meta[] = '<span class="cc-meta-data">' . __( 'Author: ', 'cc-child-pages' ) . get_the_author_link() . '</span>';
}
if ( $show_date_created ) {
$meta[] = '<span class="cc-meta-data">' . __( 'Created: ', 'cc-child-pages' ) . get_the_date() . '</span>';
}
if ( $show_date_modified ) {
$meta[] = '<span class="cc-meta-data">' . __( 'Modified: ', 'cc-child-pages' ) . get_the_date() . '</span>';
}
if ( count( $meta ) > 0 ) {
$tmp_meta = implode( ', ', $meta );
$meta_html = str_replace( '{{meta}}', $tmp_meta, $meta_template );
} else {
$meta_html = '';
}
$tmp_html = str_replace( '{{meta}}', $meta_html, $tmp_html );
$thumb_url = '';
$thumbs_html = '';
if ( $thumbs != false ) {
$thumbnail = '';
$thumb_attr = array(
'class' => 'cc-child-pages-thumb',
'alt' => $title_value,
'title' => $title_value,
);
/* Check to see if custom thumbnails has been specified */
$use_custom_thumbs = ! empty( $a['use_custom_thumbs'] )
? sanitize_key( $a['use_custom_thumbs'] )
: '';
if ( ! empty( $use_custom_thumbs ) ) {
$custom_thumb = get_post_meta( $id, $use_custom_thumbs, true );
if ( ! empty( $custom_thumb ) ) {
// Attachment ID stored in meta
if ( is_numeric( $custom_thumb ) ) {
$thumbnail = wp_get_attachment_image(
(int) $custom_thumb,
$thumbs,
false,
$thumb_attr
);
} else {
// URL stored in meta
// Trim and sanitise the raw URL
$raw_thumb_url = trim( (string) $custom_thumb );
$sanitised_url = esc_url_raw( $raw_thumb_url );
if ( ! empty( $sanitised_url ) ) {
// Make sure $title_value is plain text before we escape it
$title_text = sanitize_text_field( $title_value );
// Build the <img> tag with proper escaping
$thumbnail = sprintf(
'<img src="%1$s" alt="%2$s" title="%2$s" class="cc-child-pages-thumb" />',
esc_url( $sanitised_url ),
esc_attr( $title_text )
);
}
}
}
}
// Get the thumbnail code ...
if ( $thumbnail == '' ) {
$thumbnail = get_the_post_thumbnail( $id, $thumbs, $thumb_attr );
}
if ( $thumbnail != '' ) {
// Thumbnail found, so set thumb_url to actual URL of thumbnail
$tmp_thumb_id = get_post_thumbnail_id( $id );
$tmp_thumb_url_array = wp_get_attachment_image_src( $tmp_thumb_id, 'thumbnail-size', true );
$thumb_url = $tmp_thumb_url_array[0];
}
// If no thumbnail found, request a "Video Thumbnail" (if plugin installed)
// to try and force generation of thumbnail
if ( $thumbnail == '' ) {
// Check whether Video Thumbnail plugin is installed.
// If so, call get_video_thumbnail() to make sure that thumnail is generated.
if ( class_exists( 'Video_Thumbnails' ) && function_exists( 'get_video_thumbnail' ) ) {
// Call get_video_thumbnail to generate video thumbnail
$video_img = get_video_thumbnail( $id );
// If we got a result, display the image
if ( $video_img != '' ) {
// First, try to pick up the thumbnail in case it has been regenerated (may be the case if automatic featured image is turned on)
$thumbnail = get_the_post_thumbnail( $id, $thumbs, $thumb_attr );
// If thumbnail hasn't been regenerated, use Video Thumbnail (may be the full size image)
if ( $thumbnail == '' ) {
// First, try and find the attachment ID from the URL
$attachment_id = self::get_attachment_id( $video_img );
$thumb_url = $video_img;
if ( $attachment_id != false ) {
// Attachment found, get thumbnail
$thumbnail = wp_get_attachment_image( $attachment_id, $thumbs );
} else {
$thumbnail .= '<img src="' . $video_img . '" alt="' . $title_value . '" title="' . $title_value . '" class="cc-child-pages-thumb" />';
}
}
}
}
}
// If thumbnail is found, display it.
if ( ! empty( $thumbnail ) ) {
if ( $link_thumbs && ! empty( $link ) ) {
// Make sure title text is clean before using in an attribute.
$title_text = sanitize_text_field( $title_value );
$thumbs_html = '<a class="ccpage_linked_thumb" href="' . esc_url( $link ) . '"';
if ( ! empty( $link_target ) ) {
$thumbs_html .= ' target="' . esc_attr( $link_target ) . '"';
// Hardening for _blank links:
if ( '_blank' === $link_target ) {
$thumbs_html .= ' rel="noopener noreferrer"';
}
}
$thumbs_html .= ' title="' . esc_attr( $title_text ) . '">' . $thumbnail . '</a>';
} else {
$thumbs_html = $thumbnail;
}
}
}
$tmp_html = str_replace( '{{thumbnail}}', $thumbs_html, $tmp_html );
$tmp_html = str_replace( '{{thumbnail_url}}', $thumb_url, $tmp_html );
$page_excerpt = '';
$excerpt_template = apply_filters( 'ccchildpages_excerpt_template', '<div class="ccpages_excerpt">{{page_excerpt}}</div>', $a );
if ( $show_page_content ) {
if ( $hide_wp_more ) {
$page_excerpt = get_the_content( '' );
} else {
$hide_more = true;
$page_excerpt = get_the_content();
}
// Remove any [child_pages] shortcodes to avoid creating an infinite loop
$page_excerpt = self::strip_shortcode( $page_excerpt );
$page_excerpt = do_shortcode( $page_excerpt );
$page_excerpt = apply_filters( 'the_content', $page_excerpt );
$page_excerpt = str_replace( '{{page_excerpt}}', $page_excerpt, $excerpt_template );
} elseif ( ! $hide_excerpt ) {
$words = ( intval( $a['words'] ) > 0 ? intval( $a['words'] ) : 55 );
// Shortcode attribute: which meta key to use for the excerpt.
$use_custom_excerpt = ! empty( $a['use_custom_excerpt'] )
? sanitize_key( $a['use_custom_excerpt'] )
: '';
$meta_excerpt = ''; // default - no meta_excerpt
// If a meta excerpt field is specified, get and sanitise the value.
if ( ! empty( $use_custom_excerpt ) ) {
$raw_meta_excerpt = get_post_meta( $id, $use_custom_excerpt, true );
// Make sure we’re dealing with a string.
if ( is_string( $raw_meta_excerpt ) ) {
$raw_meta_excerpt = trim( $raw_meta_excerpt );
} else {
$raw_meta_excerpt = '';
}
if ( $raw_meta_excerpt !== '' ) {
// Allow safe HTML similar to normal post content.
// Allows things like <strong>, <em>, <a>, <p>, etc.
$meta_excerpt = wp_kses_post( $raw_meta_excerpt );
}
}
// If value from custom field is set, use that - otherwise use page content
if ( $meta_excerpt != '' ) {
$page_excerpt = trim( $meta_excerpt );
} elseif ( has_excerpt() ) {
$page_excerpt = get_the_excerpt();
if ( str_word_count( strip_tags( $page_excerpt ) ) > $words && $truncate_excerpt ) {
$page_excerpt = wp_trim_words( $page_excerpt, $words, '...' );
}
} else {
if ( $hide_wp_more ) {
$page_excerpt = get_the_content( '' ); // get full page content without continue link
} else {
$page_excerpt = get_the_content(); // get full page content including continue link
}
// Remove any [child_pages] shortcodes to avoid creating an infinite loop
$page_excerpt = self::strip_shortcode( $page_excerpt );
$page_excerpt = do_shortcode( $page_excerpt );
if ( str_word_count( wp_trim_words( $page_excerpt, $words + 10, '' ) ) > $words ) {
// If page content is longer than allowed words,
$trunc = '...';
} else {
// If page content is within allowed word count, do not add anything to the end of it
$trunc = '';
}
$page_excerpt = wp_trim_words( $page_excerpt, $words, $trunc );
}
$page_excerpt = str_replace( '{{page_excerpt}}', $page_excerpt, $excerpt_template );
}
$child_list_html = '';
if ( $depth != 1 ) {
$child_depth = ( $depth > 1 ) ? $depth - 1 : $depth;
$child_args = array(
'depth' => $child_depth,
'child_of' => $id,
'echo' => false,
'title_li' => '',
);
$child_list_title = apply_filters( 'ccchildpages_child_list_title', '<h4 class="ccsubpages_title">{{subpage_title}}</h4>', $a );
$child_list_title = ( trim( $a['subpage_title'] ) == '' ) ? '' : str_replace( '{{subpage_title}}', esc_html( trim( $a['subpage_title'] ) ), $child_list_title );
$child_list_template = apply_filters( 'ccchildpages_child_list_template', '<div class="ccsubpages">{{child_list_title}}<ul>{{child_list}}</ul></div>', $a );
$child_list = wp_list_pages( $child_args );
if ( trim( $child_list ) != '' ) {
$child_list_html = str_replace( '{{child_list_title}}', $child_list_title, $child_list_template );
$child_list_html = str_replace( '{{child_list}}', $child_list, $child_list_html );
}
}
$tmp_html = str_replace( '{{excerpt}}', $page_excerpt, $tmp_html );
$more_html = '';
$use_custom_more = trim( $a['use_custom_more'] );
$more_text = $more; // default
// If meta more field specified, get the value
if ( $use_custom_more != '' ) {
// Get value of custom field to be used as excerpt
$meta_more = trim( get_post_meta( $id, $use_custom_more, true ) );
// If value from custom field is set, use that - otherwise use page title
if ( $meta_more != '' ) {
$more_text = esc_html( trim( $meta_more ) );
}
}
if ( ! $hide_more ) {
$more_html = str_replace( '{{more}}', $more_text, apply_filters( 'ccchildpages_more_template', '<p class="ccpages_more"><a href="{{link}}" {{link_target}} title="{{more}}">{{more}}</a></p>', $a ) );
}
$more_html .= $child_list_html;
$tmp_html = str_replace( '{{more}}', $more_html, $tmp_html );
$tmp_html = str_replace( '{{link}}', esc_url( $link ), $tmp_html );
if ( $link_target != '' ) {
$link_target = 'target="' . $link_target . '"';
}
$tmp_html = str_replace( '{{link_target}}', $link_target, $tmp_html );
$return_html .= $tmp_html;
}
if ( $posts_per_page > 0 && $page < 1 ) {
$cc_link_format = '?' . $ccpage_var . '=%#%';
$cc_num_results = $parent->found_posts;
$cc_num_pages = intval( ( $cc_num_results - $offset ) / $posts_per_page );
if ( ( $cc_num_results - $offset ) % $posts_per_page > 0 ) {
++$cc_num_pages;
}
$return_html .= '<div id="ccpages_nav-' . $cc_uid . '" class="ccpages_nav">' . paginate_links(
array(
'format' => $cc_link_format,
'current' => $ccpaged,
'total' => $cc_num_pages,
)
) . '</div>';
}
// Reset global post query
wp_reset_postdata();
}
$return_html = str_replace( '{{ccchildpages}}', $return_html, $outer_template );
$return_html = apply_filters( 'ccchildpages_before_shortcode', '', $a ) . $return_html . apply_filters( 'ccchildpages_after_shortcode', '', $a );
// wp_reset_query(); // Should not be required
return $return_html;
}
public static function enqueue_styles() {
$css_file = plugins_url( 'css/styles.css', __FILE__ );
$css_skin_file = plugins_url( 'css/skins.css', __FILE__ );
if ( $options = get_option( 'cc_child_pages' ) ) {
if ( empty( $options['link_skins'] ) ) {
// undefined - so set to true for backward compatibility
$link_skins = true;
} elseif ( $options['link_skins'] == 'true' ) {
$link_skins = true;
} else {
$link_skins = false;
}
} else {
$link_skins = true;
}
if ( ! is_admin() ) {
// Load main styles
wp_register_style(
'ccchildpagescss',
$css_file,
false,
self::plugin_version
);
wp_enqueue_style( 'ccchildpagescss' );
// Load skins
if ( $link_skins ) {
wp_register_style(
'ccchildpagesskincss',
$css_skin_file,
false,
self::plugin_version
);
wp_enqueue_style( 'ccchildpagesskincss' );
}
// Load custom CSS
$custom_css = self::custom_css();
if ( $custom_css != '' ) {
wp_add_inline_style( 'ccchildpagesskincss', $custom_css );
}
}
}
private static function the_slug( $id ) {
$post_data = get_post( $id, ARRAY_A );
$slug = $post_data['post_name'];
return $slug;
}
/** */
public static function dashboard_widgets() {
if ( current_user_can( 'update_plugins' ) ) {
if ( get_user_meta( get_current_user_id(), 'ccchildpages_hide_dash_widget', true ) ) {
return;
}
wp_add_dashboard_widget( 'cc-child-pages-dashboard', 'CC Child Pages', 'ccchildpages::dashboard_widget_feed' );
}
}
public static function dashboard_widget_feed() {
// Compute/cached stats for speed.
$stats = self::dashboard_get_stats();
// Dismiss URL (admin-post handler below).
$dismiss_url = wp_nonce_url(
admin_url( 'admin-post.php?action=ccchildpages_dismiss_widget' ),
'ccchildpages_dismiss_widget'
);
// Settings / Docs links.
$settings_url = admin_url( 'options-general.php?page=cc-child-pages' );
$docs_url = 'https://docs.ccplugins.co.uk/plugins/cc-child-pages/';
$examples_url = 'https://ccplugins.co.uk/examples/cc-child-pages/';
// Optional: filter to allow owners to change the upgrade URL.
$upgrade_url = apply_filters( 'ccchildpages_upgrade_url', 'https://ccplugins.co.uk/wordpress-plugins/cc-child-pages-pro/' );
echo '<div class="cccp-widget" style="line-height:1.5">';
// a) Quick usage summary
echo '<p><strong>' . esc_html__( 'Usage summary', 'cc-child-pages' ) . '</strong></p>';
echo '<ul style="margin:0 0 12px 18px">';
echo '<li>' . esc_html__( 'Published pages:', 'cc-child-pages' ) . ' ' . esc_html( number_format_i18n( $stats['total_pages'] ) ) . '</li>';
echo '<li>' . esc_html__( 'Pages with child pages:', 'cc-child-pages' ) . ' ' . esc_html( number_format_i18n( $stats['parents_with_children'] ) ) . '</li>';
echo '<li>' . esc_html__( 'Pages using CC Child Pages (block or shortcode):', 'cc-child-pages' ) . ' ' . esc_html( number_format_i18n( $stats['pages_using_plugin'] ) ) . '</li>';
echo '</ul>';
// b) Recently updated parent pages (with children)
if ( ! empty( $stats['recent_parents'] ) ) {
echo '<p><strong>' . esc_html__( 'Recently updated parent pages', 'cc-child-pages' ) . '</strong></p>';
echo '<ol style="margin:0 0 12px 18px">';
foreach ( $stats['recent_parents'] as $p ) {
$title = get_the_title( $p );
$link = get_edit_post_link( $p );
echo '<li><a href="' . esc_url( $link ) . '">' . esc_html( $title ) . '</a></li>';
}
echo '</ol>';
}
// c) Quick links
echo '<p style="margin-top:12px">';
echo '<a class="button" href="' . esc_url( $settings_url ) . '">' . esc_html__( 'Settings', 'cc-child-pages' ) . '</a> ';
echo '<a class="button" href="' . esc_url( $docs_url ) . '" target="_blank" rel="noopener noreferrer">' . esc_html__( 'Documentation', 'cc-child-pages' ) . '</a> ';
echo '<a class="button" href="' . esc_url( $examples_url ) . '" target="_blank" rel="noopener noreferrer">' . esc_html__( 'Examples', 'cc-child-pages' ) . '</a>';
echo '</p>';
// d) Footer with discreet upgrade + dismiss
echo '<p style="margin-top:8px; font-size:12px; opacity:.85">';
echo esc_html__( 'Need more skins and customisation options?', 'cc-child-pages' ) . ' ';
echo '<a href="' . esc_url( $upgrade_url ) . '" target="_blank" rel="noopener noreferrer">' . esc_html__( 'Upgrade to Pro', 'cc-child-pages' ) . '</a></p>';
echo '<p style="margin-top:8px; font-size:12px; opacity:.85"><a href="' . esc_url( $dismiss_url ) . '">' . esc_html__( 'Hide this widget', 'cc-child-pages' ) . '</a>';
echo '</p>';
echo '</div>';
}
/**
* Compute and cache lightweight stats for the widget.
*
* @return array {
* @type int total_pages
* @type int parents_with_children
* @type int pages_using_plugin
* @type int[] recent_parents Post IDs
* }
*/
private static function dashboard_get_stats() {
$cache_key = 'ccchildpages_dash_stats';
$cached = get_transient( $cache_key );
if ( is_array( $cached ) ) {
return $cached;
}
// 1) Total published pages
$total_pages = (int) ( wp_count_posts( 'page' )->publish ?? 0 );
// 2) Pages that have children (parents)
global $wpdb;
$parents_with_children = (int) $wpdb->get_var(
"SELECT COUNT(DISTINCT p.post_parent)
FROM {$wpdb->posts} p
WHERE p.post_type = 'page'
AND p.post_status = 'publish'
AND p.post_parent > 0"
);
// 3) Pages using the plugin (either shortcode or block)
// Allow site owners (or your Pro add-on) to declare exact block names used.
$block_slugs = apply_filters(
'ccchildpages_block_slugs',
array(
// If your registered block name differs, filter this.
'caterhamcomputing/cc-child-pages',
'cc/child-pages',
)
);
// Build a LIKE set for block comments: <!-- wp:block/name -->
$like_blocks = array();
foreach ( $block_slugs as $slug ) {
$like_blocks[] = $wpdb->prepare( 'post_content LIKE %s', '%<!-- wp:' . $wpdb->esc_like( $slug ) . ' %' );
}
// Shortcode usage
$like_shortcode = $wpdb->prepare( 'post_content LIKE %s', '%[child_pages%' );
$where_fragments = array_merge( array( $like_shortcode ), $like_blocks );
$where_sql = implode( ' OR ', $where_fragments );
$pages_using_plugin = (int) $wpdb->get_var(
"SELECT COUNT(ID)
FROM {$wpdb->posts}
WHERE post_type = 'page'
AND post_status = 'publish'
AND ( {$where_sql} )"
);
// 4) Recently updated parent pages (IDs, max 5)
// Filterable args so power users can tweak.
$recent_args = apply_filters(
'ccchildpages_dashboard_parent_query_args',
array(
'post_type' => 'page',
'post_status' => 'publish',
'posts_per_page' => 5,
'orderby' => 'modified',
'order' => 'DESC',
'fields' => 'ids',
)
);
// Select parents that actually have at least one child.
$recent_parents = get_posts( $recent_args );
if ( ! empty( $recent_parents ) ) {
$recent_parents = array_values(
array_filter(
$recent_parents,
static function ( $pid ) use ( $wpdb ) {
$count = (int) $wpdb->get_var(
$wpdb->prepare(
"SELECT COUNT(1) FROM {$wpdb->posts}
WHERE post_type = 'page'
AND post_status = 'publish'
AND post_parent = %d",
$pid
)
);
return $count > 0;
}
)
);
// Keep top 5 just in case filter expanded list.
$recent_parents = array_slice( $recent_parents, 0, 5 );
}
$stats = array(
'total_pages' => $total_pages,
'parents_with_children' => $parents_with_children,
'pages_using_plugin' => $pages_using_plugin,
'recent_parents' => $recent_parents,
);
// Cache for 12 hours.
set_transient( $cache_key, $stats, 12 * HOUR_IN_SECONDS );
return $stats;
}
/**
* Handle per-user dismissal of the widget.
*/
public static function dashboard_handle_dismiss() {
// Capability for dismiss (can be stricter than view).
$cap = apply_filters( 'ccchildpages_dashboard_dismiss_capability', 'edit_pages' );
if ( ! current_user_can( $cap ) ) {
wp_die( esc_html__( 'You are not allowed to do this.', 'cc-child-pages' ) );
}
check_admin_referer( 'ccchildpages_dismiss_widget' );
update_user_meta( get_current_user_id(), 'ccchildpages_hide_dash_widget', 1 );
wp_safe_redirect( admin_url() );
exit;
}
/**
* Helper to clear cached stats (e.g. after settings save).
* Call self::dashboard_clear_cache() when you know content changed drastically.
*/
public static function dashboard_clear_cache() {
delete_transient( 'ccchildpages_dash_stats' );
}
public static function tinymce_buttons() {
if ( $options = get_option( 'cc_child_pages' ) ) {
if ( empty( $options['show_button'] ) ) {
// undefined - so set to true for backward compatibility
$show_button = true;
} elseif ( $options['show_button'] == 'true' ) {
$show_button = true;
} else {
$show_button = false;
}
} else {
$show_button = true;
}
if ( $show_button ) {
add_filter( 'mce_external_plugins', 'ccchildpages::add_childpages_buttons' );
add_filter( 'mce_buttons', 'ccchildpages::register_childpages_buttons' );
}
}
public static function add_childpages_buttons( $plugin_array ) {
$plugin_array['ccchildpages'] = plugins_url( 'js/ccchildpages-plugin.js', __FILE__ );
return $plugin_array;
}
public static function register_childpages_buttons( $buttons ) {
array_push( $buttons, 'ccchildpages' );
return $buttons;
}
/*
* Add options page ...
*/
// Set default values on activation ...
public static function options_activation() {
$options = array();
$options['show_button'] = 'true';
$options['link_skins'] = 'true';
$options['customcss'] = '';
$options = apply_filters( 'ccchildpages_options', $options );
add_option( 'cc_child_pages', $options, '', 'yes' );
}
// Register settings ...
public static function register_options() {
register_setting( 'cc_child_pages', 'cc_child_pages' );
}
// Add submenu
public static function options_menu() {
$page_title = apply_filters( 'ccchildpages_menu_page_title', __( 'CC Child Pages', 'cc-child-pages' ) );
$menu_title = apply_filters( 'ccchildpages_menu_title', __( 'CC Child Pages', 'cc-child-pages' ) );
$function = apply_filters( 'ccchildpages_menu_function', array( 'ccchildpages', 'options_page' ) );
add_options_page( $page_title, $menu_title, 'manage_options', 'cc-child-pages', $function );
}
// Display options page
public static function options_page() {
// Get options with sane defaults (keeps existing behaviour)
$options = get_option( 'cc_child_pages', array() );
$options = wp_parse_args(
$options,
array(
'show_button' => 'true', // default true (back-compat)
'link_skins' => 'true', // default true (back-compat)
'customcss' => '',
)
);
$show_button = ( 'true' === $options['show_button'] );
$link_skins = ( 'true' === $options['link_skins'] );
$customcss = (string) $options['customcss'];
?>
<div class="wrap">
<h1 class="wp-heading-inline"><?php esc_html_e( 'CC Child Pages options', 'cc-child-pages' ); ?></h1>
<hr class="wp-header-end" />
<?php
do_action( 'ccchildpages_options_before_form', $options ); // allow extension of settings form
?>
<form method="post" id="cc_child_page_form" action="options.php">
<?php settings_fields( 'cc_child_pages' ); ?>
<table class="form-table" role="presentation">
<tbody>
<?php
do_action( 'ccchildpages_options_form_top', $options ); // allow extension of settings form
?>
<tr>
<th scope="row">
<label for="cccp-show-button"><?php esc_html_e( 'Add button to the visual editor (Classic Editor)', 'cc-child-pages' ); ?></label>
</th>
<td>
<fieldset>
<legend class="screen-reader-text"><?php esc_html_e( 'Add button to the visual editor (Classic Editor)', 'cc-child-pages' ); ?></legend>
<label>
<input
type="radio"
id="cccp-show-button"
name="cc_child_pages[show_button]"
value="true"
<?php checked( true, $show_button ); ?>
/>
<?php esc_html_e( 'Yes', 'cc-child-pages' ); ?>
</label>
<br />
<label>
<input
type="radio"
name="cc_child_pages[show_button]"
value="false"
<?php checked( false, $show_button ); ?>
/>
<?php esc_html_e( 'No', 'cc-child-pages' ); ?>
</label>
</fieldset>
</td>
</tr>
<tr>
<th scope="row">
<label for="cccp-link-skins"><?php esc_html_e( 'Enqueue Skins CSS', 'cc-child-pages' ); ?></label>
</th>
<td>
<fieldset>
<legend class="screen-reader-text"><?php esc_html_e( 'Enqueue Skins CSS', 'cc-child-pages' ); ?></legend>
<label>
<input
type="radio"
id="cccp-link-skins"
name="cc_child_pages[link_skins]"
value="true"
<?php checked( true, $link_skins ); ?>
aria-describedby="cccp-link-skins-desc"
/>
<?php esc_html_e( 'Yes', 'cc-child-pages' ); ?>
</label>
<br />
<label>
<input
type="radio"
name="cc_child_pages[link_skins]"
value="false"
<?php checked( false, $link_skins ); ?>
aria-describedby="cccp-link-skins-desc"
/>
<?php esc_html_e( 'No', 'cc-child-pages' ); ?>
</label>
<p class="description" id="cccp-link-skins-desc">
<?php esc_html_e( 'If you are providing your own CSS for the styling of the child pages, you can opt to not load the CSS for the Skins.', 'cc-child-pages' ); ?>
</p>
</fieldset>
</td>
</tr>
<?php if ( '' !== $customcss ) : ?>
<tr>
<th scope="row">
<label for="cccp-customcss"><?php esc_html_e( 'Custom CSS', 'cc-child-pages' ); ?></label>
</th>
<td>
<div class="notice notice-warning inline">
<p>
<span class="dashicons dashicons-warning" aria-hidden="true" style="vertical-align: text-bottom;"></span>
<strong><?php esc_html_e( 'Deprecated:', 'cc-child-pages' ); ?></strong>
<?php esc_html_e( 'This function is deprecated and may be removed in future releases. It is strongly recommended that all custom CSS is moved to the theme customiser.', 'cc-child-pages' ); ?>
</p>
</div>
<textarea
name="cc_child_pages[customcss]"
id="cccp-customcss"
class="large-text code"
rows="10"
><?php echo esc_textarea( $customcss ); ?></textarea>
<?php
/**
* Preserve original behaviour: only fire this hook when custom CSS exists.
* Add-ons that print extra fields can hook here and render their own markup.
*/
?>
</td>
</tr>
<?php endif; ?>
<?php
do_action( 'ccchildpages_options_form', $options ); // allow extension of settings form
?>
</tbody>
</table>
<?php submit_button( __( 'Save Changes', 'cc-child-pages' ) ); ?>
</form>
</div>
<?php
}
/*
* CSS Version
*/
public static function css_version() {
$legacy_css = '';
if ( $options = get_option( 'cc_child_pages' ) ) {
if ( ! empty( $options['legacy_css'] ) ) {
if ( trim( $options['legacy_css'] ) != '' ) {
$legacy_css = trim( $options['legacy_css'] );
}
}
}
$css_version_class = ( $legacy_css === 'true' ) ? 'cclegacy' : 'ccflex';
return $css_version_class;
}
/*
* Output Custom CSS
*/
public static function custom_css() {
$custom_css = '';
if ( $options = get_option( 'cc_child_pages' ) ) {
if ( ! empty( $options['customcss'] ) ) {
if ( trim( $options['customcss'] ) != '' ) {
$custom_css = trim( $options['customcss'] );
}
}
}
return self::sanitize_css( $custom_css );
}
/*
* Sanitize CSS output
*/
public static function sanitize_css( $css ) {
$search = array(
'@<script[^>]*?>.*?</script>@si', // Strip out javascript
'@<[\/\!]*?[^<>]*?>@si', // Strip out HTML tags
'@<style[^>]*?>.*?</style>@siU', // Strip style tags properly
'@<![\s\S]*?--[ \t\n\r]*>@', // Strip multi-line comments
);
$output = preg_replace( $search, '', $css );
return $output;
}
/*
* Show Excerpt for Pages ...
*/
public static function show_page_excerpt() {
add_post_type_support( 'page', 'excerpt' );
}
/*
* Get Attachment ID from URL
*/
public static function get_attachment_id( $url ) {
$dir = wp_upload_dir();
// baseurl never has a trailing slash
if ( false === strpos( $url, $dir['baseurl'] . '/' ) ) {
// URL points to a place outside of upload directory
return false;
}
$file = basename( $url );
$query = array(
'post_type' => 'attachment',
'fields' => 'ids',
'meta_query' => array(
array(
'value' => $file,
'compare' => 'LIKE',
),
),
);
$query['meta_query'][0]['key'] = '_wp_attached_file';
// query attachments
$ids = get_posts( $query );
if ( ! empty( $ids ) ) {
foreach ( $ids as $id ) {
// first entry of returned array is the URL
$tmp_url = wp_get_attachment_image_src( $id, 'full' );
if ( $url === array_shift( $tmp_url ) ) {
return $id;
}
}
}
return false;
}
/*
* Get size information for thumbnail by size
*/
private static function get_image_dimensions( $thumbs ) {
global $_wp_additional_image_sizes;
$dimensions = array();
// If a default image size, use get options method
if ( in_array( $thumbs, array( 'thumbnail', 'medium', 'large' ) ) ) {
$dimensions['height'] = get_option( $thumbs . '_size_h' );
$dimensions['width'] = get_option( $thumbs . '_size_w' );
} elseif ( isset( $_wp_additional_image_sizes[ $thumbs ] ) ) {
$dimensions['height'] = $_wp_additional_image_sizes[ $thumbs ]['height'];
$dimensions['width'] = $_wp_additional_image_sizes[ $thumbs ]['width'];
}
return $dimensions;
}
/*
* Show plugin links
*/
public static function plugin_action_links( $links ) {
$cc_links = array( '<a href="https://docs.ccplugins.co.uk/plugins/cc-child-pages/" target="_blank">' . __( 'Documentation', 'cc-child-pages' ) . '</a>' );
$links = array_merge( (array) $links, $cc_links );
return $links;
}
public static function plugin_row_meta( $links, $file ) {
$current_plugin = basename( dirname( $file ) );
$cc_links = array();
if ( $current_plugin == 'cc-child-pages' ) {
$cc_links[] = '<a href="options-general.php?page=cc-child-pages">' . __( 'Settings...', 'cc-child-pages' ) . '</a>';
$cc_links[] = '<a href="https://wordpress.org/support/view/plugin-reviews/cc-child-pages" target="_blank"><strong>' . __( 'Rate this plugin...', 'cc-child-pages' ) . '</strong></a>';
}
$links = array_merge( (array) $links, $cc_links );
return $links;
}
public static function add_query_strings( $vars ) {
// Register query strings for paging ...
for ( $i = 1; $i < 25; $i++ ) {
$vars[] = 'ccpage' . $i;
}
$vars[] = 'ccchildpages';
return $vars;
}
public static function query_offset( &$query ) {
// Check that query was called from CC Child Pages
if ( ! isset( $query->query_vars['ccchildpages'] ) ) {
return;
}
if ( $query->query_vars['ccchildpages'] != 'true' ) {
return;
}
// Check whether offset has been specified
$offset = ( isset( $query->query_vars['offset'] ) ) ? intval( $query->query_vars['offset'] ) : -1;
if ( $offset < 1 ) {
return;
}
// If we made it this far, the query is from CC Child Pages and an Offset has been specified!
$posts_per_page = ( isset( $query->query_vars['posts_per_page'] ) ) ? intval( $query->query_vars['posts_per_page'] ) : -1;
if ( $query->is_paged ) {
$paged = intval( $query->query_vars['paged'] );
if ( $paged > 0 ) {
$page_offset = $offset + ( ( $paged - 1 ) * $posts_per_page );
} else {
$page_offset = $offset;
}
} else {
$page_offset = $offset;
}
$query->set( 'offset', $page_offset );
// By default, if posts_per_page is set to -1 offset is ignored.
// To get around this, if posts_per_page is set to -1 we will set it to something large
if ( $posts_per_page < 1 ) {
$query->set( 'posts_per_page', 1000000 );
}
}
public static function exempt_from_wptexturize( $shortcodes ) {
$shortcodes[] = 'child_pages';
return $shortcodes;
}
// public static function strip_shortcode( $page_excerpt ) {
// Remove any [child_pages] shortcodes to avoid the possibility creating a loop,
// and also to avoid the mess that may be created by having nested child pages displayed
// $page_excerpt = str_replace( '[child_pages]', '', $page_excerpt ); // remove basic shortcode
// $page_excerpt = preg_replace( '~(?:\[child_pages/?)[^/\]]+/?\]~s', '', $page_excerpt ); // remove shortcode with parameters
// return $page_excerpt;
// }
public static function strip_shortcode( $content ) {
// 1) Remove [child_pages] shortcode in any form using WP's official pattern
if ( function_exists( 'get_shortcode_regex' ) ) {
// Limit to just this shortcode so we don't strip other shortcodes the user may want.
$pattern = get_shortcode_regex( array( 'child_pages' ) );
$content = preg_replace( '/' . $pattern . '/s', '', $content );
} else {
// Fallback if get_shortcode_regex is unavailable for some reason.
// Matches [child_pages ...] and optional closing [/child_pages]
$content = preg_replace(
'/\[\s*child_pages\b[^\]]*\](?:.*?\[\/\s*child_pages\s*\])?/si',
'',
$content
);
}
// 2) Remove the Gutenberg block form (self-closing and paired)
// Self-closing block: <!-- wp:caterhamcomputing/cc-child-pages {...} /-->
$content = preg_replace(
'/<!--\s*wp:caterhamcomputing\/cc-child-pages\b[^>]*?\/\s*-->/is',
'',
$content
);
// Paired block:
// <!-- wp:caterhamcomputing/cc-child-pages {...} -->
// ... inner HTML ...
// <!-- /wp:caterhamcomputing/cc-child-pages -->
$content = preg_replace(
'/<!--\s*wp:caterhamcomputing\/cc-child-pages\b[^>]*?-->(.*?)<!--\s*\/wp:caterhamcomputing\/cc-child-pages\s*-->/is',
'',
$content
);
// Optional: also catch the bare "[child_pages]" without attrs (covered by regex, but harmless to leave)
// $content = str_replace( '[child_pages]', '', $content );
return $content;
}
public static function sanitize_class_list( $classes ) {
$class_array = explode( ' ', $classes );
$class_list = '';
foreach ( $class_array as $class ) {
$clean_class = trim( sanitize_html_class( $class ) );
if ( $clean_class != '' ) {
if ( $class_list != '' ) {
$class_list .= ' ';
}
$class_list .= $clean_class;
}
}
return $class_list;
}
public static function default_skin_list() {
$css_version_class = self::css_version();
if ( $css_version_class == 'ccflex' ) {
// Default skins
return array(
'simple' => __( 'Simple', 'cc-child-pages' ),
'red' => __( 'Red', 'cc-child-pages' ),
'green' => __( 'Green', 'cc-child-pages' ),
'blue' => __( 'Blue', 'cc-child-pages' ),
'sleek' => __( 'Sleek', 'cc-child-pages' ),
'bold' => __( 'Bold', 'cc-child-pages' ),
);} else { // Legacy skins
return array(
'simple' => __( 'Simple', 'cc-child-pages' ),
'red' => __( 'Red', 'cc-child-pages' ),
'green' => __( 'Green', 'cc-child-pages' ),
'blue' => __( 'Blue', 'cc-child-pages' ),
);}
}
public static function skin_list() {
$default_skins = self::default_skin_list();
return apply_filters( 'cc_child_pages_editor_skins', $default_skins );
}
public static function enqueue_block_editor_assets() {
// Your block name exactly as in block.json
$block_name = 'caterhamcomputing/cc-child-pages';
// Get the block type to see which handles WP registered for it
$block_type = WP_Block_Type_Registry::get_instance()->get_registered( $block_name );
if ( ! $block_type ) {
return; // not registered yet (shouldn't happen if you register on init)
}
// Collect the relevant script handles that might be loaded in the editor
$handles = array();
// editor_script is the one we want for the block editor UI
if ( ! empty( $block_type->editor_script ) ) {
$handles = array_merge( $handles, (array) $block_type->editor_script );
}
if ( empty( $handles ) ) {
return;
}
$data = array(
'skins' => self::skin_list(), // your single source of truth, filterable
'proPresent' => self::show_upgrade_notice(),
'docsUrl' => 'https://docs.ccplugins.co.uk/plugins/cc-child-pages/',
'proUrl' => 'https://ccplugins.co.uk/plugins/cc-child-pages-pro/',
);
foreach ( array_unique( $handles ) as $handle ) {
// Make sure the script is at least registered before localizing
if ( wp_script_is( $handle, 'registered' ) ) {
wp_localize_script( $handle, 'CCChildPagesEditorData', $data );
if ( function_exists( 'wp_set_script_translations' ) ) {
wp_set_script_translations(
$handle,
'cc-child-pages',
dirname( __DIR__ ) . '/languages'
);
}
}
}
}
public static function show_upgrade_notice() {
$pro_present = defined( 'CCCP_PRO_VER' )
|| class_exists( '\CaterhamComputing\CCChildPagesPro\Plugin' )
|| apply_filters( 'ccchildpages/pro_present', false );
return $pro_present;
}
}
/*EOF*/