Skip to content

Instantly share code, notes, and snippets.

@kongondo
Last active June 21, 2021 02:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kongondo/c84b48fe9e1252c1a470 to your computer and use it in GitHub Desktop.
Save kongondo/c84b48fe9e1252c1a470 to your computer and use it in GitHub Desktop.
ProcessWire. MarkupBlog's renderPosts() as an independent reusable and editable function outside Blog
function renderPosts($posts, $small = false, Array $options = null) {
$blogConfigs = wire('modules')->getModuleConfigData('ProcessBlog');
//intialise some properties from ProcessBlog config
$commentsUse = $blogConfigs['commentsUse'];
$authorsPage = wire('pages')->get($blogConfigs['blog-authors']);
$settingsPage = wire('pages')->get($blogConfigs['blog-settings']);
if(!$posts instanceof PageArray) {
if($posts instanceof Page) {
// single page
$post = $posts;
$posts = new PageArray();
$posts->add($post);
}
elseif(is_string($posts)) {
// selector string
$selector = $posts;
$posts = wire('pages')->find("template=blog-post, sort=-blog_date, $selector");
}
else {
throw new WireException('renderPosts requires a PageArray, Page or selector string');
}
}//end if(!$posts instanceof PageArray)
//excerpt/post truncated length
$limit = $settingsPage->blog_small;
$summaryLimit = $limit ? $limit : 450;
//default options for various aspects of posts
$defaultOptions = array(
'post_count' => 1,//0=off, 1=on - for the count in: Posts 1 to 5 of 15
'post_count_text' =>__('Post'),//e.g. Posts 1 to 5 of 15
'post_not_found' => __('No posts found.'),//message when no posts found
'post_author' => 1,//display name of post author: 0=off,1=top(below post-headline),2=bottom(in post-foot)
'post_author_text' => __('Posted by'),//
'post_date' => 1,//display post's date: 0=off,1=top(below post-headline),2=bottom(in post-foot)
'post_date_text' => '',//e.g. Posted by author 'on' date
'post_more_text' => __('View More'),//for $small posts - link text to full post
'post_categories' => 2,//display post's categories: 0=off,1=top(below post-byline),2=bottom(in post-foot)
'post_categories_text' => __('Categories:'),//e.g. 'Categories', 'In', 'Filed under', etc
'post_tags' => 2,//display post's tags: 0=off,1=top(below post-byline),2=bottom(in post-foot)
'post_tags_text' => __('Tags:'),//e.g. 'Tagged', 'Related', etc
'post_small_allowable_tags' => '',//holds string of HTML tags for strip_tags $allowable_tags. Needs to be in format '<code><p><img>'
'post_small_headline_tag' => 'h4',
'post_large_headline_tag' => 'h2',
'post_small_tag' => 'p',
//post comments
'post_comments' => 1,//show comments info? 0=off,1=comments count top,2=comments count bottom,3=comments count top & bottom
'post_zero_comments_text' => __('No comments yet'),
'post_comments_text' => __('Comment,Comments'),//title in anchor comments icon + post-foot comments text, e.g. '2 Comments' or '1 Comment'. Must be in 'singular,plural' format
'post_comments_label' => __('Comments:'),//this appears in post-foot, e.g. 'Comments': 2 Comments
//## featured images ##
'post_image_alt' => 'description',//defaults to $image->description. Otherwise other stated field on the page, e.g. = 'title'
'post_image_tag' => 'featured',//string: image tag to look for in blog_images
//** small/truncated post featured image **
'post_small_image' => 0,//display post's featured image: 0=off,1=top(above post-headline),2=bottom(first item in post-body)
'post_small_image_width' => '',//no width manipulation of featured image if this is blank or 0
'post_small_image_height' => '',//no height manipulation if this is blank or 0. Note, if size is true and both width and height > 0, use size() instead
/*size:
- image will be resized to exact dimensions -> $img = $image->size($x, $y)
- where $x = 'width' and $y = 'height'*/
'post_small_image_size' => false,//if 'size' = true AND both width and height > 0, this kicks in
//** large/full post featured image **
'post_large_image' => 0,//display post's featured image: 0=off,1=top(above post-headline),2=bottom(first item in post-body)
'post_large_image_width' => '',//no width manipulation of featured image if this is blank or 0
'post_large_image_height' => '',//no height manipulation if this is blank or 0. Note, if size is true and both width and height > 0, use size() instead
'post_large_image_size' => false,//if 'size' = true AND both width and height > 0, this kicks in
);
//merge user options with default posts' options
if($options != null && is_array($options)) $options = array_merge($defaultOptions, $options);
else $options = $defaultOptions;
# ** prepare post-foot variables for later use. we need to do this earlier to determine how/if post-foot will be output ** #
//When $small = false, i.e. we want 'LARGE' POSTS [not-truncated]. NOTE: We don't show post categories and tags if $small = true
if(!$small) {
foreach($posts as $page) {
//if user wants to show categories in post
if($options['post_categories'] != 0) {
$page->categories = '';//overloading with a property
if(count($page->blog_categories)) {
$page->categories = "<p class='categories'><span>" . $options['post_categories_text'] . " " . "</span>";
foreach($page->blog_categories as $category) $page->categories .= "<a href='{$category->url}'>{$category->title}</a>, ";
$page->categories = rtrim($page->categories, ", ") . "</p>";
}
}
//if user wants to show tags in post
if($options['post_tags'] != 0) {
$page->tag = '';
if(count($page->blog_tags)) {
$page->tags = "<p class='tags'><span>" . $options['post_tags_text'] . " " . "</span>";
foreach($page->blog_tags as $tag) $page->tags .= "<a href='{$tag->url}'>{$tag->title}</a>, ";
$page->tags = rtrim($page->tags, ", ") . "</p>";
}
}
}//end foreach $posts as $page
}//END if(!$small) for post-foot
#----------------------------------------- END determine if/how post-foot will be output -----------------------------------------#
foreach($posts as $page) {
//Note:we don't have a summary field for 'post' pages but left code here just in case we need it in future
if(empty($page->summary)) {
//summary is blank so we auto-generate a summary from the body [note: blog body field is 'blog_body']
//note: second paramenter of strip_tags $allowable_tags is configurable!
$summary = strip_tags(substr($page->blog_body, 0, $summaryLimit), $options['post_small_allowable_tags']);
$page->summary = substr($summary, 0, strrpos($summary, ' '));
}//end if(empty($page->summary))
//set a couple new fields that our output will use
if($page->createdUser->get('title')) {
$authorTitle = $page->createdUser->get('title');
$page->set('authorName', $authorTitle);
$page->set('authorURL', $authorsPage->url . wire('sanitizer')->pageName($authorTitle) . '/');//use pageName sanitized author title in author page URL
}
else {
$page->set('authorName', 'Author Name');//use generic 'Author Name' if author title not set
$page->set('authorURL', '');//no link to author page until user sets author title
}
}//end foreach($posts as $page)
//start output
$out = '';
//Small means show truncated body text. 'Large' just means show the whole/full body text
if($small && $options['post_count'] !=0) {
//display a headline indicating quantities
$start = $posts->getStart()+1;
$end = $start + count($posts)-1;
$total = $posts->getTotal();
if($total) $out .= "<h3 class='posts-count'>" . $options['post_count_text'] . " " . sprintf(__('%1$d to %2$d of %3$d'), $start, $end, $total) . "</h3>";
}//end if($small)
#------------------------------------------- POSTS WRAPPER ------------------------------------------- #
$out .= $small ? "<div class='posts posts-small'>" : "<div class='posts'>";
//COMMENTS COUNT: for post comments count
$commentsCountTop = false;
$commentsCountBottom = false;
//post comments - only if commentsUse == 1
if($commentsUse == 1 && $options['post_comments'] !=0) {
//if we found comments
list($singular, $plural) = explode(',', $options['post_comments_text']);//come in the format 'singular,plural'
$comment = '%d ' . $singular;
$comments = '%d ' . $plural;
if($options['post_comments'] == 1 || $options['post_comments'] == 3) $commentsCountTop = true;
if($options['post_comments'] == 2 || $options['post_comments'] == 3) $commentsCountBottom = true;
}
//FEATURED IMAGE: determine if to output featured image in posts
$showFeaturedImage = false;
$featuredImageTop = false;//for positioning featured image (top/bottom)
//if featured image is to be output
if (($small && $options['post_small_image'] !=0) || (!$small && $options['post_large_image'] !=0)) $showFeaturedImage = true;//we will be outputting a featured image
//loop through and output posts
foreach($posts as $page) {
//post comments - only if commentsUse == 1
if($commentsCountTop == true || $commentsCountBottom == true) {
$numComments = $page->blog_comments->count();
if($numComments > 0) $numCommentsStr = sprintf(_n($comment, $comments, $numComments), $numComments);
else $numCommentsStr = $options['post_zero_comments_text'];//used as both title of icon anchor tag when no comments + in post-foot when no comments yet
}
#------------------------------------------- SINGLE POST START + POST HEAD ------------------------------------------- #
$out .= "<div class='post' id='{$page->id}'>
<div class='post-head'>";
//if($commentsCountTop == true) $out .= "<a class='num-comments-icon' href='{$page->url}#comments' title='$numCommentsStr'>$numComments</a>";//moved below $featuredImageTop
//headline size
$h = $small ? $options['post_small_headline_tag'] : $options['post_large_headline_tag'];
############################
$featuredImage = '';//will contain featured image string
//if featured image is to be output
if ($showFeaturedImage == true) {
########### if user specified they want to show a featured image we first attempt to find it in the page's blog_images. ###########
########### if that fails, we check for it in the post's first embedded image in blog_body ###########
//** featured image dimensions **
$size = $small ? $options['post_small_image_size'] : $options['post_large_image_size'];
$width = $small ? (int) $options['post_small_image_width'] : (int) $options['post_large_image_width'];
$height = $small ? (int) $options['post_small_image_height'] : (int) $options['post_large_image_height'];
//retrieve first image with the tag 'featured' or user-specified 'tag'
$image = $page->blog_images->getTag($options['post_image_tag']);
//if we found the image
if($image) {
$alt = $options['post_image_alt'] == 'description' ? $image->description : $page->{$options['post_image_alt']};
if ($height > 0 && $width > 0 && $size == true) $thumb = $image->size($width, $height);
elseif ($width > 0) $thumb = $image->width($width);
elseif ($height > 0) $thumb = $image->height($height);
else $thumb = $image;
$featuredImage .= "<img class='post-featured-image' src='{$thumb->url}' alt='{$alt}' width='{$thumb->width}' height='{$thumb->height}' />";
}//end if $image found
//if we didn't find an image in $page->blog_images, we check for the first embedded image in blog_body if blog_body is not blank!
//only for small posts! no need to get embedded image if large/full post! otherwise it will be displayed twice!
elseif($small && $page->blog_body !='') {
/*for each summarised post, we use PHP's DOMDocument class to find the first image and use that as the featured image*/
//parse the html string into a DOMDocument
$dom = new DOMDocument();
$dom->loadHTML($page->blog_body);
//this grabs just the nth img found. we want the first one so item(0)
//we grab the first img found in blog_body
$image = $dom->getElementsByTagName('img')->item(0);//returns an object
//if an image found, we grab its 'src' attribute
if ($image !=null) {
$imageURL = $image->getAttribute('src');//string;
$alt = $page->{$options['post_image_alt']};
$width = $width > 0 ? "width={$width}" : '';
$height = $height > 0 ? "height={$height}" : '';
$featuredImage .= "<img class='post-featured-image' src='{$imageURL}' alt='{$alt}' {$width} {$height} />";
}
}//end else grab image from first image embedded in post
//determine featured image position. in here we already know there is an image; we just don't know if user wants it at the top or bottom
if(($featuredImage !='' && $options['post_small_image'] == 1) || ($featuredImage !='' && $options['post_large_image'] == 1)) $featuredImageTop = true;
}//end if featured image specified
#------------------------------------------- POST HEADLINE ------------------------------------------- #
//if featured image to be output above post-headline
if($featuredImageTop == true) $out .= $featuredImage;
if($commentsCountTop == true) $out .= "<a class='num-comments-icon' href='{$page->url}#comments' title='$numCommentsStr'>$numComments</a>";
$out .= "<$h class='post-headline'><a href='{$page->url}'>{$page->title}</a></$h>";
//meta/byline post_author_text
$author = $options['post_author'] == 1 ? "<span class='author'>" . $options['post_author_text'] . " " . "<a href='{$page->authorURL}'>{$page->authorName}</a></span> " : '';
$date = $options['post_date'] == 1 ? "<span class='date'>" . $options['post_date_text'] . " " . $page->blog_date . "</span>" : '';
//if page is editable (i.e., appropriate person logged in), let's show an edit link to the post
$edit = $page->editable() ? "<span class='edit'>(<a href='" . wire('config')->urls->admin . "page/edit/?id={$page->id}'>" . __('edit') . "</a>)</span>" : '';
if(!empty($author) || !empty($date) || !empty($edit)) $out .= "<p class='post-byline'>" . $author . $date . $edit . "</p>";//end p.post-byline
//show post categories and tags if user wants them at the 'top'
if($options['post_categories'] == 1) $out .= $page->categories;
if($options['post_tags'] == 1) $out .= $page->tags;
$out .= "</div>";/*end div.post-head*/
#------------------------------------------- POST BODY ------------------------------------------- #
$out .= "<div class='post-body'>";
//if featured image to be output below post-body
if($featuredImageTop == false) $out .= $featuredImage;
//if to output 'View More' link (if post $small)
if($small) {
$tag = $options['post_small_tag'];
$out .= "<$tag class='post-small'>" . $page->summary . "&hellip; <a class='more' href='{$page->url}'>" . $options['post_more_text'] . "</a></$tag>";
}
else {
$out .= $page->blog_body;
}
//Note: Left here for posterity. We are not including a gallery in this version
//if the post has images and no <img> tags in the body, then make it a gallery
//if(count($page->images) && strpos($page->body, '<img ') === false) include("./gallery.php");
$out .= "</div>";/*end div.post-body*/
#------------------------------------------- POST FOOT ------------------------------------------- #
if(!$small) {
//if post author OR post date are to be displayed at the 'bottom' == 2
$author = $options['post_author'] == 2 ? $author = "<span class='author'>" . $options['post_author_text'] . " " . "<a href='{$page->authorURL}'>{$page->authorName}</a></span> " : '';
$date = $options['post_date'] == 2 ? $date = "<span class='date'>{$page->blog_date}</span>" : '';
//if post_categories OR post_tags are to be displayed at the 'bottom' == 2 + number of comments in 'large' posts
$categories = $options['post_categories'] == 2 ? $page->categories : '';
$tags = $options['post_tags'] == 2 ? $page->tags : '';
$comments = $commentsCountBottom == true ? "<p class='num-comments'><span>" . $options['post_comments_label'] . "</span> <a href='{$page->url}#comments'>$numCommentsStr</a></p>" : '';
if(!empty($author) || !empty($date) || !empty($categories) || !empty($tags) || !empty($comments)) {
$out .= "<div class='post-foot'>" . $author . $date . $categories . $tags . $comments . "</div>";//end div.post-foot
}
}//END if(!$small)
$out .= "</div>";/*end div.post => single post*/
}//end foreach($posts as $page)
if(!count($posts)) $out .= '<h4 id="no-posts">' . $options['post_not_found'] . '</h4>'; //<!--/.posts-->
$out .= "</div>";/*end div.posts => posts wrapper*/
#------------------------------------------- POST PAGINATION ------------------------------------------- #
// if there are more posts than the specified limit, then output pagination
if($posts->getLimit() < $posts->getTotal()) $out .= $posts->renderPager();//@@todo - consider making renderPager configurable?
return $out;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment