'Your forum\'s recent topics.' ] );
$this->init_local_vars();
add_action( 'wp_ajax_wpforo_load_ajax_widget_RecentTopics', [ $this, 'load_ajax_widget' ] );
add_action( 'wp_ajax_nopriv_wpforo_load_ajax_widget_RecentTopics', [ $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 Topics',
'forumids' => [],
'orderby' => 'created',
'order' => 'DESC',
'count' => 9,
'display_avatar' => true,
'forumids_filter' => false,
'current_forumid_filter' => false,
'goto_unread' => false,
'refresh_interval' => 0,
];
$this->orderby_fields = [
'created' => __( 'Created Date', 'wpforo' ),
'modified' => __( 'Modified Date', 'wpforo' ),
'posts' => __( 'Posts Count', 'wpforo' ),
'views' => __( 'Views Count', 'wpforo' ),
];
$this->order_fields = [
'DESC' => __( 'DESC', 'wpforo' ),
'ASC' => __( 'ASC', 'wpforo' ),
'RAND' => __( 'Random', 'wpforo' ),
];
}
private function add_topic_cache_filter( $topic_args ) {
if( $topic_args['order'] === 'RAND' ) {
add_filter( 'wpforo_cache_topic', '__return_false' );
}
}
private function remove_topic_cache_filter( $topic_args ) {
if( $topic_args['order'] === 'RAND' ) {
remove_filter( 'wpforo_cache_topic', '__return_false' );
}
}
public function get_widget( $instance, $topic_args ) {
$this->add_topic_cache_filter( $topic_args );
$is_user_logged_in = (bool) WPF()->current_userid;
$topic_args['private'] = ( ! $is_user_logged_in || ! WPF()->usergroup->can( 'aum' ) ) ? 0 : null;;
$topic_args['status'] = ( ! $is_user_logged_in || ! WPF()->usergroup->can( 'aum' ) ) ? 0 : null;
$row_count = (int) wpfval( $topic_args, 'row_count' );
$topics = [];
$topic_args['offset'] = 0;
while( $row_count && count( $topics ) < $row_count ) {
if( ! ( $_topics = WPF()->topic->get_topics( $topic_args ) ) ) break;
$topics = array_merge( $topics, $_topics );
$topic_args['offset'] += $row_count;
}
array_splice( $topics, $row_count );
$print_avatar = $instance['display_avatar'] && wpforo_setting( 'profiles', 'avatars' ) && WPF()->usergroup->can( 'va' );
$lis = '';
foreach( $topics as $topic ) {
$topic_url = wpforo_topic( $topic['topicid'], 'url' );
$member = wpforo_member( $topic );
$lis .= sprintf(
'
',
( $print_avatar ? sprintf( '%1$s
', wpforo_user_avatar( $member ) ) : '' ),
( ! $print_avatar ? 'style="width: 100%"' : '' ),
( wpfval( $instance, 'goto_unread' ) ?
wpforo_topic_title( $topic, $topic_url, '{p}{au}{t}{/a}', false ) .
( $topic['topicid'] != wpfval( WPF()->current_object, 'topicid' ) ? wpforo_unread_button( $topic['topicid'], $topic_url, false ) : '' )
:
wpforo_topic_title( $topic, $topic_url, '{p}{a}{t}{/a}', false )
),
wpforo_phrase( 'by', false ),
wpforo_member_link( $member, '', 30, '', false ),
esc_html( wpforo_date( $topic['created'], 'ago', false ) )
);
}
$this->remove_topic_cache_filter( $topic_args );
return sprintf( '', $lis );
}
public function load_ajax_widget() {
$_POST = wp_unslash( $_POST );
$instance = json_decode( (string) wpfval( $_POST, 'instance' ), true );
$topic_args = json_decode( (string) wpfval( $_POST, 'topic_args' ), true );
// SECURITY FIX: Sanitize and validate all user-controlled parameters
if( is_array( $topic_args ) ) {
// Remove dangerous 'where' parameter
unset( $topic_args['where'] );
// Validate 'orderby' parameter against whitelist
if( isset( $topic_args['orderby'] ) ) {
if( ! key_exists( $topic_args['orderby'], $this->orderby_fields ) ) {
$topic_args['orderby'] = $this->default_instance['orderby'];
}
}
// Validate 'order' parameter against whitelist
if( isset( $topic_args['order'] ) ) {
if( ! key_exists( $topic_args['order'], $this->order_fields ) ) {
$topic_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' ] as $idfield ) {
if( isset( $topic_args[ $idfield ] ) ) {
$topic_args[ $idfield ] = is_array( $topic_args[ $idfield ] )
? array_map( 'intval', $topic_args[ $idfield ] )
: [];
}
}
}
wp_send_json_success( [ 'html' => $this->get_widget( $instance, $topic_args ) ] );
}
public function widget( $args, $instance ) {
wp_enqueue_script( 'wpforo-widgets-js' );
$instance = wpforo_parse_args( $instance, $this->default_instance );
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_RecentTopics',
'instance' => $instance,
'topic_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' => ( ( $count = intval( $instance['count'] ) ) ? $count : $this->default_instance['count'] ),
],
];
if( WPF()->board->get_current( 'boardid' ) === $instance['boardid'] ) {
$html = $this->get_widget( $data['instance'], $data['topic_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'];
$display_avatar = (bool) $instance['display_avatar'];
$forumids_filter = (bool) $instance['forumids_filter'];
$current_forumid_filter = (bool) $instance['current_forumid_filter'];
$goto_unread = (bool) $instance['goto_unread'];
$refresh_interval = (int) $instance['refresh_interval'];
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['goto_unread'] = (bool) (int) $new_instance['goto_unread'];
$instance['refresh_interval'] = (int) $new_instance['refresh_interval'];
return $instance;
}
public function get_forum_tree() {
ob_start();
WPF()->forum->tree( 'select_box', false, [] );
wp_send_json_success( [ 'html' => ob_get_clean() ] );
}
}