$taxonomyRelation]; if ( 'post' === $postType && count( $selectedCategories ) ) { $termsQuery[] = [ 'taxonomy' => 'category', 'field' => 'term_id', 'terms' => $selectedCategories, ]; } $postsAuthors = Functions::filterNaN( $queryAttr['postsAuthors'] ?? [] ); $author__in = !empty( $postsAuthors ) ? [ 'author__in' => $postsAuthors ] : []; $query = array_merge( [ 'post_type' => $postType, 'posts_per_page' => $isPostsPerPageAll ? -1 : (int) $postsPerPage, 'orderby' => $postsOrderBy, 'order' => $postsOrder, 'tax_query' => count( $termsQuery ) > 1 ? $termsQuery : [], 'has_password' => false, 'post_status' => 'publish' ], $author__in ); // Query Presets are available in the premium version. return $query; } /** * Fetches posts based on attributes and page number. * * @param array $queryAttr Block attributes. * @param int $pageNumber Current page number. * @return array Arranged posts data. */ public static function getPosts( $queryAttr, $pageNumber = 1 ){ $isPostsPerPageAll = $queryAttr['isPostsPerPageAll'] ?? false; $postsPerPage = $queryAttr['postsPerPage'] ?? 12; $postType = $queryAttr['postType'] ?? 'post'; $excerptLength = $queryAttr['excerptLength'] ?? 25; $isExcerptFromContent = $queryAttr['isExcerptFromContent'] ?? false; $queryAttr['isPostsPerPageAll'] = true === $isPostsPerPageAll || 'true' === $isPostsPerPageAll; // Ensure numeric values to avoid PHP type errors and handle "all" mode $postsPerPage = (int) $postsPerPage; $pageNumber = (int) $pageNumber; // Extract excerptFrom with fallback to legacy isExcerptFromContent $excerptFrom = $queryAttr['excerptFrom'] ?? ( isset( $queryAttr['excerpt']['from'] ) ? $queryAttr['excerpt']['from'] : 'excerpt' ); $excerptFrom = ( 'content' === $excerptFrom || $isExcerptFromContent ) ? 'content' : 'excerpt'; $offset = ( $postsPerPage * max( 0, $pageNumber - 1 ) ); $newArgs = wp_parse_args( [ 'offset' => $offset ], self::arrangeQuery( $queryAttr ) ); $posts = Functions::arrangedPosts( get_posts( $newArgs ), $postType, $excerptFrom, $excerptLength ?? 25 ); return $posts; } /** * Generates a skeleton article HTML for loading state. * * @param string $prefix CSS class prefix. * @return string Skeleton article HTML. */ public static function skeletonArticle( $prefix ){ $articleEl = ""; return wp_kses( $articleEl, [ 'article' => [ 'class' => [], 'aria-hidden' => [] ], 'div' => [ 'class' => [] ], 'span' => [ 'class' => [] ] ] ); } /** * Generates a loading placeholder HTML based on layout and attributes. * * @param array $attributes Block attributes. * @param string $prefix CSS class prefix. * @return string Loading placeholder HTML. */ public static function loadingPlaceholder( $attributes, $prefix ){ $countQuery = new \WP_Query( Posts::arrangeQuery( $attributes ?? [] ) ); $postCount = $countQuery->found_posts; $layout = $attributes['layout'] ?? ''; $columns = $attributes['columns'] ?? [ 'desktop' => 3, 'tablet' => 2, 'mobile' => 1 ]; $sliderHeight = $attributes['sliderHeight'] ?? '350px'; $sliderIsPage = $attributes['sliderIsPage'] ?? true; $sliderIsPrevNext = $attributes['sliderIsPrevNext'] ?? true; $tickerVisible = $attributes['tickerVisible'] ?? 3; $colD = $columns['desktop']; $colT = $columns['tablet']; $colM = $columns['mobile']; $gridClass = $prefix ."GridPosts columns-$colD columns-tablet-$colT columns-mobile-$colM"; $placeholderId = wp_unique_id( $prefix .'LoadingPlaceholder-' ); $sliderStyles = "#$placeholderId .$prefix" . "SliderSkeleton article{ min-height: $sliderHeight; }"; $loadingLabel = esc_html__( 'Loading posts…', 'advanced-post-block' ); ob_start(); ?>