Last active
June 21, 2021 02:53
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 . "… <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