'Your forum\'s recent posts.' ] );
$this->init_local_vars();
add_action( 'wp_ajax_wpforo_load_ajax_widget_RecentPosts', [ $this, 'load_ajax_widget' ] );
add_action( 'wp_ajax_nopriv_wpforo_load_ajax_widget_RecentPosts', [ $this, 'load_ajax_widget' ] );
if( is_admin() ) {
add_action( 'wp_ajax_wpforo_get_forum_tree', [ $this, 'get_forum_tree' ] );
}
}
private function init_local_vars() {
$this->default_instance = [
'boardid' => 0,
'title' => 'Recent Posts',
'forumids' => [],
'orderby' => 'created',
'order' => 'DESC',
'count' => 9,
'limit_per_topic' => 0,
'display_avatar' => true,
'forumids_filter' => false,
'current_forumid_filter' => false,
'exclude_firstposts' => false,
'display_only_unread' => false,
'display_new_indicator' => false,
'refresh_interval' => 0,
'excerpt_length' => 55,
];
$this->orderby_fields = [
'created' => __( 'Created Date', 'wpforo' ),
'modified' => __( 'Modified Date', 'wpforo' ),
];
$this->order_fields = [
'DESC' => __( 'DESC', 'wpforo' ),
'ASC' => __( 'ASC', 'wpforo' ),
'RAND' => __( 'Random', 'wpforo' ),
];
}
private function add_post_cache_filter( $post_args ) {
if( $post_args['order'] === 'RAND' ) {
add_filter( 'wpforo_cache_post', '__return_false' );
}
}
private function remove_post_cache_filter( $post_args ) {
if( $post_args['order'] === 'RAND' ) {
remove_filter( 'wpforo_cache_post', '__return_false' );
}
}
public function get_widget( $instance, $post_args ) {
$this->add_post_cache_filter( $post_args );
$is_user_logged_in = (bool) WPF()->current_userid;
$post_args['private'] = ( ! $is_user_logged_in || ! WPF()->usergroup->can( 'aum' ) ) ? 0 : null;
$post_args['status'] = ( ! $is_user_logged_in || ! WPF()->usergroup->can( 'aum' ) ) ? 0 : null;
$print_avatar = $instance['display_avatar'] && wpforo_setting( 'profiles', 'avatars' ) && WPF()->usergroup->can( 'va' );
ob_start();
if( $post_args['limit_per_topic'] ) {
if( $instance['display_only_unread'] && $is_user_logged_in ) {
$grouped_postids = WPF()->post->get_unread_posts( $post_args, $post_args['row_count'] );
} else {
$grouped_postids = WPF()->post->get_posts( $post_args );
}
if( ! empty( $grouped_postids ) ) {
$grouped_postids = implode( ',', $grouped_postids );
$postids = array_filter( array_map( 'wpforo_bigintval', explode( ',', $grouped_postids ) ) );
rsort( $postids );
foreach( $postids as $postid ) {
$class = '';
$post = wpforo_post( $postid );
if( ! wpfval( $post, 'forumid' ) ) continue;
if( ! WPF()->post->view_access( $post ) ) continue;
$current = $post['topicid'] == wpfval( WPF()->current_object, 'topicid' );
if( ! $current ) {
$class = 'class="' . ( $instance['display_only_unread'] ? 'wpf-unread-post' : wpforo_unread( $post['topicid'], 'post', false, $post['postid'] ) ) . '"';
}
$member = wpforo_member( $post );
?>
>
' . wpforo_phrase( $error_message, false ) . '';
}
} else {
if( $instance['display_only_unread'] && $is_user_logged_in ) {
$recent_posts = WPF()->post->get_unread_posts( $post_args, $post_args['row_count'] );
} else {
$recent_posts = WPF()->post->get_posts( $post_args );
}
if( ! empty( $recent_posts ) ) {
foreach( $recent_posts as $post ) {
$class = '';
$post_url = wpforo_post( $post['postid'], 'url' );
$member = wpforo_member( $post );
$current = $post['topicid'] == wpfval( WPF()->current_object, 'topicid' );
if( ! $current ) {
$class = 'class="' . ( $instance['display_only_unread'] ? 'wpf-unread-post' : wpforo_unread( $post['topicid'], 'post', false, $post['postid'] ) ) . '"';
}
?>
>
' . wpforo_phrase( $error_message, false ) . '';
}
}
$this->remove_post_cache_filter( $post_args );
return sprintf( '', ob_get_clean() );
}
public function load_ajax_widget() {
$_POST = wp_unslash( $_POST );
$instance = json_decode( (string) wpfval( $_POST, 'instance' ), true );
$post_args = json_decode( (string) wpfval( $_POST, 'post_args' ), true );
// SECURITY FIX: Sanitize and validate all user-controlled parameters
if( is_array( $post_args ) ) {
// Remove dangerous 'where' parameter
unset( $post_args['where'] );
// Force permission checks — prevents check_private=false injection
$post_args['check_private'] = true;
// Validate 'orderby' parameter against whitelist
if( isset( $post_args['orderby'] ) ) {
if( ! key_exists( $post_args['orderby'], $this->orderby_fields ) ) {
$post_args['orderby'] = $this->default_instance['orderby'];
}
}
// Validate 'order' parameter against whitelist
if( isset( $post_args['order'] ) ) {
if( ! key_exists( $post_args['order'], $this->order_fields ) ) {
$post_args['order'] = $this->default_instance['order'];
}
}
// SECURITY: coerce id-list fields to integer arrays so a serialized
// payload from an unauthenticated POST can never reach
// wpforo_parse_args() / unserialize() downstream. Defense in depth
// alongside the allowed_classes=>false hardening in wpforo_parse_args.
foreach( [ 'forumids', 'include', 'exclude', 'postids' ] as $idfield ) {
if( isset( $post_args[ $idfield ] ) ) {
$post_args[ $idfield ] = is_array( $post_args[ $idfield ] )
? array_map( 'intval', $post_args[ $idfield ] )
: [];
}
}
}
wp_send_json_success( [ 'html' => $this->get_widget( $instance, $post_args ) ] );
}
public function widget( $args, $instance ) {
wp_enqueue_script( 'wpforo-widgets-js' );
$is_user_logged_in = (bool) WPF()->current_userid;
$instance = wpforo_parse_args( $instance, $this->default_instance );
if( $instance['display_only_unread'] ) {
$display_widget = $is_user_logged_in;
$display_widget = apply_filters( 'wpforo_widget_display_recent_posts', $display_widget );
} else {
$display_widget = true;
}
if( ! $display_widget ) return;
if( $instance['current_forumid_filter'] && $instance['boardid'] === WPF()->board->get_current( 'boardid' ) && $current_forumid = wpfval(
WPF()->current_object,
'forumid'
) ) {
$instance['forumids'] = (array) $current_forumid;
}
$data = [
'boardid' => $instance['boardid'],
'action' => 'wpforo_load_ajax_widget_RecentPosts',
'instance' => $instance,
'post_args' => [
'forumids' => ( $instance['forumids'] ?: $this->default_instance['forumids'] ),
'orderby' => ( key_exists( $instance['orderby'], $this->orderby_fields ) ? $instance['orderby'] : $this->default_instance['orderby'] ),
'order' => ( key_exists( $instance['order'], $this->order_fields ) ? $instance['order'] : $this->default_instance['order'] ),
'row_count' => ( intval( $instance['count'] ) ?: $this->default_instance['count'] ),
'limit_per_topic' => ( intval( $instance['limit_per_topic'] ) ?: $this->default_instance['limit_per_topic'] ),
'is_first_post' => $instance['exclude_firstposts'] ? false : null,
'check_private' => true,
],
];
if( WPF()->board->get_current( 'boardid' ) === $instance['boardid'] ) {
$html = $this->get_widget( $data['instance'], $data['post_args'] );
$onload = false;
} else {
$html = '
';
$onload = true;
$data['referer'] = home_url();
}
$json = wp_json_encode( $data );
echo $args['before_widget'] . '' . $args['after_widget'];
}
public function form( $instance ) {
$instance = wpforo_parse_args( $instance, $this->default_instance );
$title = (string) $instance['title'];
$boardid = (int) $instance['boardid'];
$selected = array_unique( array_filter( array_map( 'intval', (array) $instance['forumids'] ) ) );
$orderby = (string) $instance['orderby'];
$order = (string) $instance['order'];
$count = (int) $instance['count'];
$limit_per_topic = (int) $instance['limit_per_topic'];
$display_avatar = (bool) $instance['display_avatar'];
$forumids_filter = (bool) $instance['forumids_filter'];
$current_forumid_filter = (bool) $instance['current_forumid_filter'];
$exclude_firstposts = (bool) $instance['exclude_firstposts'];
$display_only_unread = (bool) $instance['display_only_unread'];
$display_new_indicator = (bool) $instance['display_new_indicator'];
$refresh_interval = (int) $instance['refresh_interval'];
$excerpt_length = (int) $instance['excerpt_length'];
WPF()->change_board( $boardid );
?>
default_instance );
$instance = [];
$instance['title'] = strip_tags( (string) $new_instance['title'] );
$instance['boardid'] = (int) $new_instance['boardid'];
$instance['forumids_filter'] = (bool) (int) $new_instance['forumids_filter'];
$instance['forumids'] = array_unique( array_filter( array_map( 'intval', (array) $new_instance['forumids'] ) ) );
$instance['orderby'] = ( ! empty( $new_instance['orderby'] ) && key_exists(
$new_instance['orderby'],
$this->orderby_fields
) ) ? $new_instance['orderby'] : $this->default_instance['orderby'];
$instance['order'] = ( ! empty( $new_instance['order'] ) && key_exists(
$new_instance['order'],
$this->order_fields
) ) ? $new_instance['order'] : $this->default_instance['order'];
$instance['count'] = (int) $new_instance['count'];
$instance['display_avatar'] = (bool) (int) $new_instance['display_avatar'];
$instance['current_forumid_filter'] = (bool) (int) $new_instance['current_forumid_filter'];
$instance['limit_per_topic'] = (int) $new_instance['limit_per_topic'];
$instance['exclude_firstposts'] = (bool) (int) $new_instance['exclude_firstposts'];
$instance['display_only_unread'] = (bool) (int) $new_instance['display_only_unread'];
$instance['display_new_indicator'] = (bool) (int) $new_instance['display_new_indicator'];
$instance['refresh_interval'] = (int) $new_instance['refresh_interval'];
$instance['excerpt_length'] = (int) $new_instance['excerpt_length'];
return $instance;
}
public function get_forum_tree() {
ob_start();
WPF()->forum->tree( 'select_box', false, [] );
wp_send_json_success( [ 'html' => ob_get_clean() ] );
}
}