| Server IP : www.new.bangkokfinder.com / Your IP : 172.69.166.34 Web Server : nginx/1.20.1 System : Linux new 4.15.0-159-generic #167-Ubuntu SMP Tue Sep 21 08:55:05 UTC 2021 x86_64 User : bangkokfinder ( 1000) PHP Version : 7.4.33 Disable Function : pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare, MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : ON Directory : /home/bangkokfinder/www/wp-content/plugins/generateblocks/includes/ |
Upload File : |
<?php
/**
* Handles option changes on plugin updates.
*
* @package GenerateBlocks
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
/**
* Process option updates if necessary.
*/
class GenerateBlocks_Dynamic_Content {
/**
* Class instance.
*
* @access private
* @var $instance Class instance.
*/
private static $instance;
/**
* For the excerpt we need to keep track of ids to prevent infinite loops.
*
* @var array $source_ids The current post id.
*/
private static $source_ids = [];
/**
* Initiator
*/
public static function get_instance() {
if ( ! isset( self::$instance ) ) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Constructor.
*/
public function __construct() {
add_filter( 'generateblocks_defaults', array( $this, 'add_block_defaults' ) );
add_filter( 'generateblocks_background_image_url', array( $this, 'set_dynamic_background_image' ), 10, 2 );
add_filter( 'generateblocks_button_count', array( $this, 'update_button_count' ), 10, 3 );
}
/**
* Get the requested dynamic content.
*
* @param array $attributes The block attributes.
* @param WP_Block $block Block instance.
*/
public static function get_content( $attributes, $block ) {
$content = '';
switch ( $attributes['dynamicContentType'] ) {
case 'post-title':
$content = self::get_post_title( $attributes );
break;
case 'post-excerpt':
$content = self::get_post_excerpt( $attributes );
// Once we have the excerpt content we are safe to clear the source ids.
// By doing so we avoid empty content for subsequent calls.
self::$source_ids = [];
break;
case 'post-date':
$content = self::get_post_date( $attributes );
break;
case 'post-meta':
$content = self::get_post_meta( $attributes );
break;
case 'comments-number':
$content = self::get_comments_number( $attributes );
break;
case 'terms':
$content = self::get_terms( $attributes );
break;
case 'author-meta':
$content = self::get_author_meta( $attributes );
break;
case 'author-email':
$content = self::get_user_data( self::get_source_author_id( $attributes ), 'user_email' );
break;
case 'author-name':
$content = self::get_user_data( self::get_source_author_id( $attributes ), 'display_name' );
break;
case 'author-nickname':
$content = self::get_user_data( self::get_source_author_id( $attributes ), 'nickname' );
break;
case 'author-first-name':
$content = self::get_user_data( self::get_source_author_id( $attributes ), 'first_name' );
break;
case 'author-last-name':
$content = self::get_user_data( self::get_source_author_id( $attributes ), 'last_name' );
break;
case 'pagination-numbers':
$content = self::get_paginate_links( $attributes, $block );
break;
case 'featured-image':
$content = self::get_dynamic_image( $attributes, $block );
break;
case 'caption':
$content = self::get_image_caption( $attributes, $block );
break;
case 'alt-text':
$content = self::get_image_alt_text( $attributes, $block );
break;
case 'image-description':
$content = self::get_image_description( $attributes, $block );
break;
}
return apply_filters(
'generateblocks_dynamic_content_output',
$content,
$attributes,
$block
);
}
/**
* Get the requested post title.
*
* @param array $attributes The block attributes.
*/
public static function get_post_title( $attributes ) {
return get_the_title( self::get_source_id( $attributes ) );
}
/**
* Get the post excerpt
*
* @param array $attributes The block attributes.
*
* @return string
*/
public static function get_post_excerpt( $attributes ) {
$source_id = self::get_source_id( $attributes );
$unique_id = $attributes['uniqueId'];
// This prevents endless loops by not rendering excerpts within themselves.
if ( ! $source_id || ( isset( self::$source_ids[ $unique_id ] ) && $source_id === self::$source_ids[ $unique_id ] ) ) {
return '';
}
self::$source_ids[ $unique_id ] = $source_id;
$filter_excerpt_length = function( $length ) use ( $attributes ) {
return isset( $attributes['excerptLength'] ) ? $attributes['excerptLength'] : $length;
};
add_filter(
'excerpt_length',
$filter_excerpt_length,
100
);
if ( isset( $attributes['useDefaultMoreLink'] ) && ! $attributes['useDefaultMoreLink'] ) {
$filter_more_text = function() use ( $attributes ) {
if ( empty( $attributes['customMoreLinkText'] ) ) {
return ' ...';
}
return apply_filters(
'generateblocks_dynamic_excerpt_more_link',
sprintf(
' ... <a class="gb-dynamic-read-more" href="%1$s" aria-label="%3$s">%2$s</a>',
esc_url( get_permalink( get_the_ID() ) ),
wp_kses_post( $attributes['customMoreLinkText'] ),
sprintf(
/* translators: Aria-label describing the read more button */
_x( 'More on %s', 'more on post title', 'generateblocks' ),
the_title_attribute( 'echo=0' )
)
)
);
};
add_filter(
'excerpt_more',
$filter_more_text,
100
);
}
$excerpt = get_the_excerpt( $source_id );
if ( isset( $filter_excerpt_length ) ) {
remove_filter(
'excerpt_length',
$filter_excerpt_length,
100
);
}
if ( isset( $filter_more_text ) ) {
remove_filter(
'excerpt_more',
$filter_more_text,
100
);
}
return $excerpt;
}
/**
* Get the requested post date.
*
* @param array $attributes The block attributes.
*/
public static function get_post_date( $attributes ) {
$id = self::get_source_id( $attributes );
if ( ! $id ) {
return;
}
$updated_time = get_the_modified_time( 'U', $id );
$published_time = get_the_time( 'U', $id ) + 1800;
$post_date = sprintf(
'<time class="entry-date published" datetime="%1$s">%2$s</time>',
esc_attr( get_the_date( 'c', $id ) ),
esc_html( get_the_date( '', $id ) )
);
$is_updated_date = isset( $attributes['dateType'] ) && 'updated' === $attributes['dateType'];
if ( ! empty( $attributes['dateReplacePublished'] ) || $is_updated_date ) {
if ( $updated_time > $published_time ) {
$post_date = sprintf(
'<time class="entry-date updated-date" datetime="%1$s">%2$s</time>',
esc_attr( get_the_modified_date( 'c', $id ) ),
esc_html( get_the_modified_date( '', $id ) )
);
} elseif ( $is_updated_date ) {
// If we're showing the updated date but no updated date exists, don't display anything.
return '';
}
}
return $post_date;
}
/**
* Get the requested post meta.
*
* @param array $attributes The block attributes.
*/
public static function get_post_meta( $attributes ) {
if ( isset( $attributes['metaFieldName'] ) ) {
$meta_value = get_post_meta( self::get_source_id( $attributes ), $attributes['metaFieldName'], true );
$value = (
is_string( $meta_value ) ||
is_integer( $meta_value ) ||
is_float( $meta_value )
) ? $meta_value : '';
add_filter( 'wp_kses_allowed_html', [ 'GenerateBlocks_Dynamic_Content', 'expand_allowed_html' ], 10, 2 );
$value = wp_kses_post( $value );
remove_filter( 'wp_kses_allowed_html', [ 'GenerateBlocks_Dynamic_Content', 'expand_allowed_html' ], 10, 2 );
return apply_filters(
'generateblocks_dynamic_content_post_meta',
$value,
self::get_source_id( $attributes ),
$attributes
);
}
}
/**
* Get the requested author meta.
*
* @param array $attributes The block attributes.
*/
public static function get_author_meta( $attributes ) {
if ( isset( $attributes['metaFieldName'] ) ) {
$id = self::get_source_id( $attributes );
if ( ! $id ) {
return;
}
$author_id = get_post_field( 'post_author', $id );
if ( ! $author_id ) {
return;
}
$value = self::get_user_data( $author_id, $attributes['metaFieldName'] );
return apply_filters(
'generateblocks_dynamic_content_author_meta',
$value,
$author_id,
$attributes
);
}
}
/**
* Get the number of comments.
*
* @param array $attributes The block attributes.
*/
public static function get_comments_number( $attributes ) {
$id = self::get_source_id( $attributes );
if ( ! $id ) {
return;
}
if ( ! isset( $attributes['noCommentsText'] ) ) {
$attributes['noCommentsText'] = __( 'No comments', 'generateblocks' );
}
if ( ! post_password_required( $id ) && ( comments_open( $id ) || get_comments_number( $id ) ) ) {
if ( '' === $attributes['noCommentsText'] && get_comments_number( $id ) < 1 ) {
return $attributes['noCommentsText'];
}
$comments_text = get_comments_number_text(
$attributes['noCommentsText'],
! empty( $attributes['singleCommentText'] ) ? $attributes['singleCommentText'] : __( '1 comment', 'generateblocks' ),
! empty( $attributes['multipleCommentsText'] ) ? $attributes['multipleCommentsText'] : __( '% comments', 'generateblocks' )
);
return $comments_text;
} else {
return $attributes['noCommentsText'];
}
}
/**
* Get a list of terms.
*
* @param array $attributes The block attributes.
*/
public static function get_terms( $attributes ) {
$id = self::get_source_id( $attributes );
if ( ! $id ) {
return;
}
$is_button = isset( $attributes['isButton'] );
$taxonomy = isset( $attributes['termTaxonomy'] ) ? $attributes['termTaxonomy'] : 'category';
$terms = get_the_terms( $id, $taxonomy );
$link_type = isset( $attributes['dynamicLinkType'] ) ? $attributes['dynamicLinkType'] : '';
if ( is_wp_error( $terms ) ) {
return;
}
$term_items = array();
foreach ( (array) $terms as $index => $term ) {
if ( ! isset( $term->name ) ) {
continue;
}
if ( $is_button ) {
$term_items[ $index ] = array(
'content' => $term->name,
'attributes' => array(
'class' => 'post-term-item post-term-' . $term->slug,
),
);
} else {
$term_items[ $index ] = sprintf(
'<span class="post-term-item term-%2$s">%1$s</span>',
$term->name,
$term->slug
);
}
if ( 'term-archives' === $link_type ) {
$term_link = get_term_link( $term, $taxonomy );
if ( ! is_wp_error( $term_link ) ) {
if ( $is_button ) {
$term_items[ $index ]['attributes']['href'] = esc_url( get_term_link( $term, $taxonomy ) );
} else {
$term_items[ $index ] = sprintf(
'<span class="post-term-item term-%3$s"><a href="%1$s">%2$s</a></span>',
esc_url( get_term_link( $term, $taxonomy ) ),
$term->name,
$term->slug
);
}
}
}
}
if ( empty( $term_items ) ) {
return '';
}
$sep = isset( $attributes['termSeparator'] ) ? $attributes['termSeparator'] : ', ';
$term_output = $is_button ? $term_items : implode( $sep, $term_items );
return $term_output;
}
/**
* Get the pagination numbers.
*
* @param array $attributes The block attributes.
* @param WP_Block $block Block instance.
*/
public static function get_paginate_links( $attributes, $block ) {
$page_key = isset( $block->context['generateblocks/queryId'] ) ? 'query-' . $block->context['generateblocks/queryId'] . '-page' : 'query-page';
$page = empty( $_GET[ $page_key ] ) ? 1 : (int) $_GET[ $page_key ]; // phpcs:ignore -- No data processing happening.
$max_page = isset( $block->context['generateblocks/query']['pages'] ) ? (int) $block->context['generateblocks/query']['pages'] : 0;
global $wp_query;
if ( isset( $block->context['generateblocks/inheritQuery'] ) && $block->context['generateblocks/inheritQuery'] ) {
// Take into account if we have set a bigger `max page`
// than what the query has.
$total = ! $max_page || $max_page > $wp_query->max_num_pages ? $wp_query->max_num_pages : $max_page;
$paginate_args = array(
'prev_next' => false,
'total' => $total,
);
$links = paginate_links( $paginate_args );
} else {
$query_args = apply_filters(
'generateblocks_query_loop_args',
GenerateBlocks_Query_Loop::get_query_args( $block, $page ),
$attributes,
$block
);
$block_query = new WP_Query( $query_args );
// `paginate_links` works with the global $wp_query, so we have to
// temporarily switch it with our custom query.
$prev_wp_query = $wp_query;
$wp_query = $block_query; // phpcs:ignore -- No way around overwriting core global.
$total = ! $max_page || $max_page > $wp_query->max_num_pages ? $wp_query->max_num_pages : $max_page;
$paginate_args = array(
'base' => '%_%',
'format' => "?$page_key=%#%",
'current' => max( 1, $page ),
'total' => $total,
'prev_next' => false,
);
if ( 1 !== $page ) {
/**
* `paginate_links` doesn't use the provided `format` when the page is `1`.
* This is great for the main query as it removes the extra query params
* making the URL shorter, but in the case of multiple custom queries is
* problematic. It results in returning an empty link which ends up with
* a link to the current page.
*
* A way to address this is to add a `fake` query arg with no value that
* is the same for all custom queries. This way the link is not empty and
* preserves all the other existent query args.
*
* @see https://developer.wordpress.org/reference/functions/paginate_links/
*
* The proper fix of this should be in core. Track Ticket:
* @see https://core.trac.wordpress.org/ticket/53868
*
* TODO: After two WP versions (starting from the WP version the core patch landed),
* we should remove this and call `paginate_links` with the proper new arg.
*/
$paginate_args['add_args'] = array( 'cst' => '' );
}
// We still need to preserve `paged` query param if exists, as is used
// for Queries that inherit from global context.
$paged = empty( $_GET['paged'] ) ? null : (int) $_GET['paged']; // phpcs:ignore -- No data processing happening.
if ( $paged ) {
$paginate_args['add_args'] = array( 'paged' => $paged );
}
$links = paginate_links( $paginate_args );
$wp_query = $prev_wp_query; // phpcs:ignore -- Restoring core global.
wp_reset_postdata(); // Restore original Post Data.
}
$doc = self::load_html( $links );
if ( ! $doc ) {
return;
}
$data = array();
$html_nodes = $doc->getElementsByTagName( '*' );
foreach ( $html_nodes as $index => $node ) {
$classes = $node->getAttribute( 'class' ) ? $node->getAttribute( 'class' ) : '';
if ( $node->getAttribute( 'aria-current' ) ) {
$classes = str_replace( 'current', 'gb-block-is-current', $classes );
}
// phpcs:ignore -- DOMDocument doesn't use snake-case.
if ( 'span' === $node->tagName || 'a' === $node->tagName ) {
$data[ $index ]['href'] = $node->getAttribute( 'href' ) ? $node->getAttribute( 'href' ) : '';
$data[ $index ]['aria-current'] = $node->getAttribute( 'aria-current' ) ? $node->getAttribute( 'aria-current' ) : '';
$data[ $index ]['class'] = $classes;
// phpcs:ignore -- DOMDocument doesn't use snake-case.
foreach ( $node->childNodes as $childNode ) {
$data[ $index ]['content'] = $doc->saveHTML( $childNode );
}
}
}
$paginate_links = array_values( $data );
$link_items = array();
foreach ( (array) $paginate_links as $index => $link ) {
$link_items[ $index ] = array(
'content' => $link['content'],
'attributes' => array(
'href' => $link['href'],
'aria-current' => $link['aria-current'],
'class' => $link['class'],
),
);
}
if ( empty( $link_items ) ) {
return '';
}
return $link_items;
}
/**
* Get the dynamic image.
*
* @param array $attributes The block attributes.
* @param WP_Block $block Block instance.
*/
public static function get_dynamic_image( $attributes, $block ) {
$id = self::get_dynamic_image_id( $attributes );
if ( ! $id ) {
$id = apply_filters( 'generateblocks_dynamic_image_fallback', '', $attributes, $block );
// If still empty return.
if ( ! $id ) {
return;
}
}
$classes = array(
'gb-image-' . $attributes['uniqueId'],
isset( $attributes['className'] ) ? $attributes['className'] : '',
);
if ( ! empty( $attributes['align'] ) ) {
$classes[] = 'align' . $attributes['align'];
}
$html_attributes = array(
'id' => isset( $attributes['anchor'] ) ? $attributes['anchor'] : '',
'class' => implode( ' ', $classes ),
);
$parsed_html_attributes = generateblocks_parse_attr( 'image', $html_attributes, $attributes, $block );
$parsed_html_attributes = array_map( 'trim', $parsed_html_attributes );
$parsed_html_attributes = array_filter( $parsed_html_attributes );
if ( ! empty( $attributes['dynamicContentType'] ) ) {
if ( 'author-avatar' === $attributes['dynamicContentType'] ) {
$author_id = self::get_source_author_id( $attributes );
return get_avatar(
$author_id,
$attributes['width'],
'',
'',
$parsed_html_attributes
);
}
}
if ( $id && ! is_numeric( $id ) ) {
// Our image ID isn't a number - must be a static URL.
$html_attributes['src'] = $id;
return sprintf(
'<img %s />',
generateblocks_attr( 'image', $html_attributes, $attributes, $block )
);
}
$dynamic_image = wp_get_attachment_image(
$id,
isset( $attributes['sizeSlug'] ) ? $attributes['sizeSlug'] : 'full',
false,
$parsed_html_attributes
);
if ( ! $dynamic_image ) {
return '';
}
return $dynamic_image;
}
/**
* Get our source ID.
*
* @param array $attributes The block attributes.
*/
public static function get_source_id( $attributes ) {
$id = get_the_ID();
if (
isset( $attributes['dynamicSource'] ) &&
'current-post' !== $attributes['dynamicSource'] &&
isset( $attributes['postId'] )
) {
$id = absint( $attributes['postId'] );
}
$image_content_types = array( 'caption', 'post-title', 'alt-text', 'image-description' );
if ( isset( $attributes['dynamicContentType'] ) ) {
if ( in_array( $attributes['dynamicContentType'], $image_content_types ) ) {
if ( isset( $attributes['dynamicImage'] ) ) {
$id = $attributes['dynamicImage'];
} elseif (
isset( $attributes['postId'] ) &&
isset( $attributes['postType'] ) &&
'attachment' === $attributes['postType']
) {
// Use the saved post ID if we're working with a static image.
$id = absint( $attributes['postId'] );
}
}
}
return apply_filters(
'generateblocks_dynamic_source_id',
$id,
$attributes
);
}
/**
* Get the source post author id.
*
* @param array $attributes The block attributes.
*
* @return int|boolean
*/
public static function get_source_author_id( $attributes ) {
$id = self::get_source_id( $attributes );
if ( ! $id ) {
return false;
}
$author_id = get_post_field( 'post_author', $id );
if ( ! $author_id ) {
return false;
}
return $author_id;
}
/**
* Get the dynamic image ID.
*
* @param array $attributes The block attributes.
*/
public static function get_dynamic_image_id( $attributes ) {
$id = self::get_source_id( $attributes );
if ( ! $id ) {
return;
}
if ( ! empty( $attributes['dynamicContentType'] ) ) {
if ( 'post-meta' === $attributes['dynamicContentType'] ) {
$id = self::get_post_meta( $attributes );
}
if ( 'featured-image' === $attributes['dynamicContentType'] ) {
$id = get_post_thumbnail_id( $id );
}
}
return $id;
}
/**
* Get the dynamic background image url.
*
* @param array $attributes The block attributes.
*
* @return int|boolean
*/
public static function get_dynamic_background_image_url( $attributes ) {
$id = self::get_dynamic_image_id( $attributes );
if ( ! $id ) {
return false;
}
if ( empty( $attributes['dynamicContentType'] ) ) {
return;
}
if ( $id && ! is_numeric( $id ) ) {
// Our image ID isn't a number - must be a static URL.
return $id;
}
$url = wp_get_attachment_image_url(
$id,
isset( $attributes['bgImageSize'] ) ? $attributes['bgImageSize'] : 'full'
);
return apply_filters(
'generateblocks_dynamic_background_image_url',
$url,
$attributes
);
}
/**
* Get our dynamic URL.
*
* @param array $attributes The block attributes.
* @param object $block The block object.
*/
public static function get_dynamic_url( $attributes, $block ) {
$id = self::get_source_id( $attributes );
$author_id = get_post_field( 'post_author', $id );
$link_type = isset( $attributes['dynamicLinkType'] ) ? $attributes['dynamicLinkType'] : '';
$url = '';
if ( 'single-post' === $link_type ) {
$url = get_permalink( $id );
}
if ( 'single-image' === $link_type ) {
if ( ! empty( $attributes['dynamicContentType'] ) ) {
$image_id = self::get_dynamic_image_id( $attributes );
if ( $image_id && ! is_numeric( $image_id ) ) {
// Our image ID isn't a number - must be a static URL.
return $image_id;
}
} else {
$image_id = ! empty( $attributes['mediaId'] ) ? $attributes['mediaId'] : false;
}
if ( $image_id ) {
$url = wp_get_attachment_url( $image_id );
} elseif ( ! empty( $attributes['mediaUrl'] ) ) {
$url = $attributes['mediaUrl'];
}
}
if ( isset( $attributes['linkMetaFieldName'] ) ) {
if ( 'post-meta' === $link_type ) {
$url = get_post_meta( $id, $attributes['linkMetaFieldName'], true );
$url = apply_filters(
'generateblocks_dynamic_url_post_meta',
$url,
self::get_source_id( $attributes ),
$attributes
);
if ( isset( $attributes['linkMetaFieldType'] ) ) {
$url = $attributes['linkMetaFieldType'] . $url;
}
}
if ( 'author-meta' === $link_type ) {
$url = self::get_user_data( $author_id, $attributes['linkMetaFieldName'] );
$url = apply_filters(
'generateblocks_dynamic_url_author_meta',
$url,
$author_id,
$attributes
);
if ( isset( $attributes['linkMetaFieldType'] ) ) {
$url = $attributes['linkMetaFieldType'] . $url;
}
}
}
if ( 'author-email' === $link_type ) {
$url = self::get_user_data( $author_id, 'user_email' );
if ( isset( $attributes['linkMetaFieldType'] ) ) {
$url = $attributes['linkMetaFieldType'] . $url;
}
}
if ( 'author-archives' === $link_type ) {
$url = get_author_posts_url( $author_id );
}
if ( 'comments-area' === $link_type ) {
$url = get_comments_link( $id );
}
if ( 'pagination-next' === $link_type ) {
$page_key = isset( $block->context['generateblocks/queryId'] ) ? 'query-' . $block->context['generateblocks/queryId'] . '-page' : 'query-page';
$page = empty( $_GET[ $page_key ] ) ? 1 : (int) $_GET[ $page_key ]; // phpcs:ignore -- No data processing happening.
$max_page = isset( $block->context['generateblocks/query']['pages'] ) ? (int) $block->context['generateblocks/query']['pages'] : 0;
if ( isset( $block->context['generateblocks/inheritQuery'] ) && $block->context['generateblocks/inheritQuery'] ) {
global $wp_query, $paged;
if ( ! $max_page || $max_page > $wp_query->max_num_pages ) {
$max_page = $wp_query->max_num_pages;
}
if ( ! $paged ) {
$paged = 1; // phpcs:ignore -- Need to overrite global here.
}
$nextpage = (int) $paged + 1;
if ( $nextpage <= $max_page ) {
$url = next_posts( $max_page, false );
}
} elseif ( ! $max_page || $max_page > $page ) {
$query_args = apply_filters(
'generateblocks_query_loop_args',
GenerateBlocks_Query_Loop::get_query_args( $block, $page ),
$attributes,
$block
);
$custom_query = new WP_Query( $query_args );
$custom_query_max_pages = (int) $custom_query->max_num_pages;
if ( $custom_query_max_pages && $custom_query_max_pages !== $page ) {
$url = esc_url( add_query_arg( $page_key, $page + 1 ) );
}
wp_reset_postdata(); // Restore original Post Data.
}
}
if ( 'pagination-prev' === $link_type ) {
$page_key = isset( $block->context['generateblocks/queryId'] ) ? 'query-' . $block->context['generateblocks/queryId'] . '-page' : 'query-page';
$page = empty( $_GET[ $page_key ] ) ? 1 : (int) $_GET[ $page_key ]; // phpcs:ignore -- No data processing happening.
if ( isset( $block->context['generateblocks/inheritQuery'] ) && $block->context['generateblocks/inheritQuery'] ) {
global $paged;
if ( $paged > 1 ) {
$url = previous_posts( false );
}
} elseif ( 1 !== $page ) {
$url = esc_url( add_query_arg( $page_key, $page - 1 ) );
}
}
return apply_filters(
'generateblocks_dynamic_url_output',
$url,
$attributes,
$block
);
}
/**
* Get user data.
*
* @param int $author_id The ID of the user.
* @param string|void $field The field to look up.
*/
public static function get_user_data( $author_id, $field ) {
if ( ! $author_id ) {
return;
}
$data = get_user_meta( $author_id, $field, true );
if ( ! $data ) {
$user_data_names = array(
'user_nicename',
'user_email',
'display_name',
);
if ( in_array( $field, $user_data_names ) ) {
$user_data = get_userdata( $author_id );
if ( $user_data ) {
switch ( $field ) {
case 'user_nicename':
$data = $user_data->user_nicename;
break;
case 'user_email':
$data = $user_data->user_email;
break;
case 'display_name':
$data = $user_data->display_name;
break;
}
}
}
}
return $data;
}
/**
* Run HTML through DOMDocument so we can use parts of it
* when needed.
*
* @param string $content The content to run through DOMDocument.
*/
public static function load_html( $content ) {
if ( ! class_exists( 'DOMDocument' ) ) {
return;
}
$doc = new DOMDocument();
// Enable user error handling for the HTML parsing. HTML5 elements aren't
// supported (as of PHP 7.4) and There's no way to guarantee that the markup
// is valid anyway, so we're just going to ignore all errors in parsing.
// Nested heading elements will still be parsed.
// The lack of HTML5 support is a libxml2 issue:
// https://bugzilla.gnome.org/show_bug.cgi?id=761534.
libxml_use_internal_errors( true );
// Parse the post content into an HTML document.
// Ensure UTF-8 encoding.
// https://stackoverflow.com/a/37834812.
$doc->loadHTML(
sprintf(
'<html><head><meta http-equiv="Content-Type" content="text/html; charset=%s"></head><body>%s</body></html>',
esc_attr( get_bloginfo( 'charset' ) ),
$content
)
);
// We're done parsing, so we can disable user error handling. This also
// clears any existing errors, which helps avoid a memory leak.
libxml_use_internal_errors( false );
return $doc;
}
/**
* Extracts the icon element from our content.
* This is useful when using icons in dynamic blocks.
*
* @param string $content The content to search through.
*/
public static function get_icon_html( $content ) {
$doc = self::load_html( $content );
if ( ! $doc ) {
return;
}
$icon_html = '';
$html_nodes = $doc->getElementsByTagName( 'span' );
foreach ( $html_nodes as $node ) {
if ( 'gb-icon' === $node->getAttribute( 'class' ) ) {
$icon_html = $doc->saveHTML( $node );
}
}
return $icon_html;
}
/**
* Get the dynamic image caption.
*
* @param array $attributes The block attributes.
* @param object $block The block object.
*/
public static function get_image_caption( $attributes, $block ) {
$id = self::get_source_id( $attributes );
if ( ! $id ) {
return;
}
return wp_get_attachment_caption( $id );
}
/**
* Get the image alt text.
*
* @param array $attributes The block attributes.
* @param object $block The block object.
*/
public static function get_image_alt_text( $attributes, $block ) {
$id = self::get_source_id( $attributes );
if ( ! $id ) {
return '';
}
return get_post_meta( $id, '_wp_attachment_image_alt', true );
}
/**
* Get the image description.
*
* @param array $attributes The block attributes.
* @param object $block The block object.
*/
public static function get_image_description( $attributes, $block ) {
$id = self::get_source_id( $attributes );
if ( ! $id ) {
return '';
}
$media = get_post( $id );
$status = $media->post_status ?? '';
if ( 'publish' !== $status && ! current_user_can( 'read_private_posts' ) ) {
return '';
}
return isset( $media ) ? $media->post_content : '';
}
/**
* Extracts the static content the user has entered.
* This is useful when using dynamic links with static content.
*
* @param string $content The content to search through.
*/
public static function get_static_content( $content ) {
$doc = self::load_html( $content );
if ( ! $doc ) {
return;
}
$static_content = '';
$html_nodes = $doc->getElementsByTagName( '*' );
foreach ( $html_nodes as $node ) {
$classes = explode( ' ', $node->getAttribute( 'class' ) );
if (
in_array( 'gb-button-text', $classes ) ||
in_array( 'gb-headline-text', $classes ) ||
in_array( 'gb-block-image', $classes )
) {
// Captions are added dynamically in class-image.php, so we can remove
// the static one here if it exists.
if ( in_array( 'gb-block-image', $classes ) ) {
$figcaptions = $node->getElementsByTagName( 'figcaption' );
if ( ! empty( $figcaptions ) ) {
foreach ( $figcaptions as $figcaption ) {
// phpcs:ignore -- DOMDocument doesn't use snake-case.
$figcaption->parentNode->removeChild( $figcaption );
}
}
}
// phpcs:ignore -- DOMDocument doesn't use snake-case.
foreach ( $node->childNodes as $childNode ) {
$static_content .= $doc->saveHTML( $childNode );
}
}
}
return $static_content;
}
/**
* Set our dynamic background image.
*
* @param string $url Existing background image URL.
* @param array $settings Block settings.
*/
public function set_dynamic_background_image( $url, $settings ) {
if ( $settings['useDynamicData'] && '' !== $settings['dynamicContentType'] ) {
$dynamic_image_url = self::get_dynamic_background_image_url( $settings );
if ( $dynamic_image_url ) {
$url = $dynamic_image_url;
}
}
return $url;
}
/**
* Add defaults for our Query settings.
*
* @param array $defaults Block defaults.
*/
public function add_block_defaults( $defaults ) {
$defaults['container']['useDynamicData'] = false;
$defaults['container']['dynamicContentType'] = '';
$defaults['container']['dynamicLinkType'] = '';
return $defaults;
}
/**
* Update button count depending on dynamic content.
*
* @param int $button_count How many buttons the block container has.
* @param array $attributes The block attributes.
* @param object $block The block data.
*/
public function update_button_count( $button_count, $attributes, $block ) {
$inner_blocks = $block->parsed_block['innerBlocks'];
foreach ( (array) $inner_blocks as $inner_block ) {
$block_attributes = $inner_block['attrs'];
// Remove button from count if it has no dynamic content.
if ( ! empty( $block_attributes['dynamicContentType'] ) && ! self::get_content( $block_attributes, $block ) ) {
$button_count--;
}
}
return $button_count;
}
/**
* Expand the wp_kses_post sanitization function to allow iframe HTML tags
*
* @param array $tags The allowed tags, attributes, and/or attribute values.
* @param string $context Context to judge allowed tags by. Allowed values are 'post'.
* @return array
*/
public static function expand_allowed_html( $tags, $context ) {
if ( ! isset( $tags['iframe'] ) ) {
$tags['iframe'] = [
'src' => true,
'height' => true,
'width' => true,
'frameborder' => true,
'allowfullscreen' => true,
'title' => true,
];
}
$tags = apply_filters( 'generateblocks_dynamic_content_allowed_html', $tags, $context );
return $tags;
}
/**
* Detect whether legacy v1 dynamic content attributes exist in serialized content.
*
* @since 2.2.0
*
* @param string $content Serialized post content.
* @return bool
*/
public static function content_has_dynamic_attribute_markers( $content ) {
$content = GenerateBlocks_Dynamic_Tag_Security::normalize_serialized_content( $content );
if ( '' === $content ) {
return false;
}
$markers = [
'"useDynamicData":true',
'"dynamicLinkType":"post-meta"',
'"dynamicLinkType":"author-meta"',
'"dynamicContentType":"author-email"',
'"dynamicLinkType":"author-email"',
];
foreach ( $markers as $marker ) {
if ( false !== strpos( $content, $marker ) ) {
return true;
}
}
return false;
}
/**
* Validate dynamic content block attributes (metaFieldName/linkMetaFieldName) for legacy v1 blocks.
*
* @since 2.2.0
*
* @param string $content Serialized post content.
* @return true|WP_Error
*/
public static function validate_dynamic_content_attributes( $content ) {
$violations = self::get_dynamic_attribute_violation_items( $content );
if ( empty( $violations ) ) {
return true;
}
$first = reset( $violations );
return $first['error'];
}
/**
* Retrieve dynamic attribute violation items.
*
* @since 2.2.0
*
* @param string $content Serialized post content.
* @return array<int, array{type:string,field:string,error:WP_Error}>
*/
public static function get_dynamic_attribute_violation_items( $content ) {
$content = GenerateBlocks_Dynamic_Tag_Security::normalize_serialized_content( $content );
if ( ! self::content_has_dynamic_attribute_markers( $content ) ) {
return [];
}
if ( ! function_exists( 'has_blocks' ) || ! has_blocks( $content ) ) {
return [];
}
if ( ! function_exists( 'parse_blocks' ) ) {
return [];
}
$blocks = parse_blocks( $content );
if ( empty( $blocks ) || ! is_array( $blocks ) ) {
return [];
}
return self::collect_dynamic_attribute_block_violations( $blocks );
}
/**
* Recursively collect parsed block violations for unsafe meta usage.
*
* @since 2.2.0
*
* @param array $blocks Parsed block list.
* @return array<int, array{type:string,field:string,error:WP_Error}>
*/
protected static function collect_dynamic_attribute_block_violations( $blocks ) {
$violations = [];
foreach ( $blocks as $block ) {
$violations = array_merge(
$violations,
self::collect_single_block_dynamic_attribute_violations( $block )
);
if ( ! empty( $block['innerBlocks'] ) && is_array( $block['innerBlocks'] ) ) {
$violations = array_merge(
$violations,
self::collect_dynamic_attribute_block_violations( $block['innerBlocks'] )
);
}
}
return $violations;
}
/**
* Validate a single block's dynamic attributes.
*
* @since 2.2.0
*
* @param array $block Parsed block data.
* @return array<int, array{type:string,field:string,error:WP_Error}>
*/
protected static function collect_single_block_dynamic_attribute_violations( $block ) {
$violations = [];
if ( empty( $block['attrs'] ) || ! is_array( $block['attrs'] ) ) {
return $violations;
}
$attrs = $block['attrs'];
$should_validate_user_meta = GenerateBlocks_Dynamic_Tag_Security::should_validate_user_meta_fields();
if ( ! empty( $attrs['useDynamicData'] ) ) {
$field_name = isset( $attrs['metaFieldName'] ) ? trim( (string) $attrs['metaFieldName'] ) : '';
$type = isset( $attrs['dynamicContentType'] ) ? (string) $attrs['dynamicContentType'] : '';
if ( 'author-email' === $type ) {
$field_name = 'user_email';
}
if ( $field_name ) {
if ( in_array( $type, [ 'author-meta', 'author-email' ], true ) ) {
$result = $should_validate_user_meta ? GenerateBlocks_Dynamic_Tag_Security::validate_user_meta_field_name( $field_name ) : true;
$type_key = 'user_meta';
} elseif ( 'post-meta' === $type ) {
$result = GenerateBlocks_Dynamic_Tag_Security::validate_post_meta_field_name( $field_name );
$type_key = 'post_meta';
} else {
$result = true;
$type_key = '';
}
if ( isset( $result ) && is_wp_error( $result ) && $type_key ) {
$violations[] = [
'type' => $type_key,
'field' => $field_name,
'error' => $result,
];
}
}
}
if ( isset( $attrs['linkMetaFieldName'] ) || ! empty( $attrs['dynamicLinkType'] ) ) {
$link_field = isset( $attrs['linkMetaFieldName'] ) ? trim( (string) $attrs['linkMetaFieldName'] ) : '';
$link_type = isset( $attrs['dynamicLinkType'] ) ? (string) $attrs['dynamicLinkType'] : '';
if ( 'author-email' === $link_type ) {
$link_field = 'user_email';
}
if ( $link_field ) {
if ( in_array( $link_type, [ 'author-meta', 'author-email' ], true ) ) {
$result = $should_validate_user_meta ? GenerateBlocks_Dynamic_Tag_Security::validate_user_meta_field_name( $link_field ) : true;
$type_key = 'user_meta';
} elseif ( 'post-meta' === $link_type ) {
$result = GenerateBlocks_Dynamic_Tag_Security::validate_post_meta_field_name( $link_field );
$type_key = 'post_meta';
} else {
$result = true;
$type_key = '';
}
if ( isset( $result ) && is_wp_error( $result ) && $type_key ) {
$violations[] = [
'type' => $type_key,
'field' => $link_field,
'error' => $result,
];
}
}
}
return $violations;
}
}
GenerateBlocks_Dynamic_Content::get_instance();