'tag',
'category/$Category!/$Rss' => 'category',
'archive/$Year!/$Month/$Day' => 'archive',
'profile/$URLSegment!' => 'profile'
];
/**
* @var array
*/
private static $casting = [
'MetaTitle' => 'Text',
'FilterDescription' => 'Text'
];
/**
* If enabled, blog author profiles will be turned off for this site
*
* @config
* @var bool
*/
private static $disable_profiles = false;
/**
* The current Blog Post DataList query.
*
* @var DataList
*/
protected $blogPosts;
/**
* @return string
*/
public function index(HTTPRequest $request)
{
/**
* @var Blog $dataRecord
*/
$dataRecord = $this->dataRecord;
$this->blogPosts = $dataRecord->getBlogPosts();
return $this->render();
}
/**
* Renders a Blog Member's profile.
*
* @throws HTTPResponse_Exception
*
* @return string
*/
public function profile()
{
if ($this->config()->get('disable_profiles')) {
$this->httpError(404, 'Not Found');
}
$profile = $this->getCurrentProfile();
if (!$profile) {
return $this->httpError(404, 'Not Found');
}
$this->blogPosts = $this->getCurrentProfilePosts();
return $this->render();
}
/**
* Get the Member associated with the current URL segment.
*
* @return null|Member
*/
public function getCurrentProfile()
{
$urlSegment = $this->request->param('URLSegment');
if ($urlSegment) {
$filter = URLSegmentFilter::create();
// url encode unless it's multibyte (already pre-encoded in the database)
// see https://github.com/silverstripe/silverstripe-cms/pull/2384
if (!$filter->getAllowMultibyte()) {
$urlSegment = rawurlencode($urlSegment ?? '');
}
return Member::get()
->filter('URLSegment', $urlSegment)
->first();
}
return null;
}
/**
* Get posts related to the current Member profile.
*
* @return null|DataList
*/
public function getCurrentProfilePosts()
{
$profile = $this->getCurrentProfile();
if ($profile) {
return $profile->BlogPosts()->filter('ParentID', $this->ID);
}
return null;
}
/**
* Renders an archive for a specified date. This can be by year or year/month.
*
* @return null|string
*/
public function archive()
{
/**
* @var Blog $dataRecord
*/
$dataRecord = $this->dataRecord;
$year = $this->getArchiveYear();
$month = $this->getArchiveMonth();
$day = $this->getArchiveDay();
if ($this->request->param('Month') && !$month) {
$this->httpError(404, 'Not Found');
}
if ($month && $this->request->param('Day') && !$day) {
$this->httpError(404, 'Not Found');
}
if ($year) {
$this->blogPosts = $dataRecord->getArchivedBlogPosts($year, $month, $day);
return $this->render();
}
$this->httpError(404, 'Not Found');
return null;
}
/**
* Fetches the archive year from the url.
*
* @return int
*/
public function getArchiveYear()
{
if ($this->request->param('Year')) {
if (preg_match('/^[0-9]{4}$/', $year = $this->request->param('Year'))) {
return (int) $year;
}
} elseif ($this->request->param('Action') == 'archive') {
return DBDatetime::now()->Year();
}
return null;
}
/**
* Fetches the archive money from the url.
*
* @return null|int
*/
public function getArchiveMonth()
{
$month = $this->request->param('Month');
if (preg_match('/^[0-9]{1,2}$/', $month ?? '')) {
if ($month > 0 && $month < 13) {
if (checkdate($month ?? 0, 01, $this->getArchiveYear() ?? 0)) {
return (int) $month;
}
}
}
return null;
}
/**
* Fetches the archive day from the url.
*
* @return null|int
*/
public function getArchiveDay()
{
$day = $this->request->param('Day');
if (preg_match('/^[0-9]{1,2}$/', $day ?? '')) {
if (checkdate($this->getArchiveMonth() ?? 0, $day ?? 0, $this->getArchiveYear() ?? 0)) {
return (int) $day;
}
}
return null;
}
/**
* Renders the blog posts for a given tag.
*
* @return null|string
*/
public function tag()
{
$tag = $this->getCurrentTag();
if ($tag) {
$this->blogPosts = $tag->BlogPosts();
if ($this->isRSS()) {
return $this->rssFeed($this->blogPosts, $tag->getLink());
} else {
return $this->render();
}
}
$this->httpError(404, 'Not Found');
return null;
}
/**
* Tag Getter for use in templates.
*
* @return null|BlogTag
*/
public function getCurrentTag()
{
/**
* @var Blog $dataRecord
*/
$dataRecord = $this->dataRecord;
$tag = $this->request->param('Tag');
if ($tag) {
$filter = URLSegmentFilter::create();
// url encode unless it's multibyte (already pre-encoded in the database)
// see https://github.com/silverstripe/silverstripe-cms/pull/2384
if (!$filter->getAllowMultibyte()) {
$tag = rawurlencode($tag ?? '');
}
return $dataRecord->Tags()
->filter('URLSegment', $tag)
->first();
}
return null;
}
/**
* Renders the blog posts for a given category.
*
* @return null|string
*/
public function category()
{
$category = $this->getCurrentCategory();
if ($category) {
$this->blogPosts = $category->BlogPosts();
if ($this->isRSS()) {
return $this->rssFeed($this->blogPosts, $category->getLink());
}
return $this->render();
}
$this->httpError(404, 'Not Found');
return null;
}
/**
* Category Getter for use in templates.
*
* @return null|BlogCategory
*/
public function getCurrentCategory()
{
/**
* @var Blog $dataRecord
*/
$dataRecord = $this->dataRecord;
$category = $this->request->param('Category');
if ($category) {
$filter = URLSegmentFilter::create();
// url encode unless it's multibyte (already pre-encoded in the database)
// see https://github.com/silverstripe/silverstripe-cms/pull/2384
if (!$filter->getAllowMultibyte()) {
$category = rawurlencode($category ?? '');
}
return $dataRecord->Categories()
->filter('URLSegment', $category)
->first();
}
return null;
}
/**
* Get the meta title for the current action.
*
* @return string
*/
public function getMetaTitle()
{
$title = $this->data()->getTitle();
$filter = $this->getFilterDescription();
if ($filter) {
$title = sprintf('%s - %s', $title, $filter);
}
$this->extend('updateMetaTitle', $title);
return $title;
}
/**
* Returns a description of the current filter.
*
* @return string
*/
public function getFilterDescription()
{
$items = [];
$list = $this->PaginatedList();
$currentPage = $list->CurrentPage();
if ($currentPage > 1) {
$items[] = _t(
'SilverStripe\\Blog\\Model\\Blog.FILTERDESCRIPTION_PAGE',
'Page {page}',
null,
[
'page' => $currentPage
]
);
}
if ($author = $this->getCurrentProfile()) {
$items[] = _t(
'SilverStripe\\Blog\\Model\\Blog.FILTERDESCRIPTION_AUTHOR',
'By {author}',
null,
[
'author' => $author->Title
]
);
}
if ($tag = $this->getCurrentTag()) {
$items[] = _t(
'SilverStripe\\Blog\\Model\\Blog.FILTERDESCRIPTION_TAG',
'Tagged with {tag}',
null,
[
'tag' => $tag->Title
]
);
}
if ($category = $this->getCurrentCategory()) {
$items[] = _t(
'SilverStripe\\Blog\\Model\\Blog.FILTERDESCRIPTION_CATEGORY',
'In category {category}',
null,
[
'category' => $category->Title
]
);
}
if ($this->owner->getArchiveYear()) {
if ($this->owner->getArchiveDay()) {
$date = $this->owner->getArchiveDate()->Nice();
} elseif ($this->owner->getArchiveMonth()) {
$date = $this->owner->getArchiveDate()->format('MMMM, y');
} else {
$date = $this->owner->getArchiveDate()->format('y');
}
$items[] = _t(
'SilverStripe\\Blog\\Model\\Blog.FILTERDESCRIPTION_DATE',
'In {date}',
null,
[
'date' => $date,
]
);
}
$result = '';
if ($items) {
$result = implode(', ', $items);
}
$this->extend('updateFilterDescription', $result);
return $result;
}
/**
* Returns a list of paginated blog posts based on the BlogPost dataList.
*
* @return PaginatedList
*/
public function PaginatedList()
{
$allPosts = $this->blogPosts ?: ArrayList::create();
$posts = PaginatedList::create($allPosts);
// Set appropriate page size
if ($this->PostsPerPage > 0) {
$pageSize = $this->PostsPerPage;
} elseif ($count = $allPosts->count()) {
$pageSize = $count;
} else {
$pageSize = 99999;
}
$posts->setPageLength($pageSize);
// Set current page
$start = max(0, (int)$this->request->getVar($posts->getPaginationGetVar()));
$posts->setPageStart($start);
return $posts;
}
/**
* Returns the absolute link to the next page for use in the page meta tags. This helps search engines
* find the pagination and index all pages properly.
*
* @example "<% if $PaginationAbsoluteNextLink %><% end_if %>"
*
* @return string|null
*/
public function PaginationAbsoluteNextLink()
{
$posts = $this->PaginatedList();
if ($posts->NotLastPage()) {
return Director::absoluteURL($posts->NextLink());
}
return null;
}
/**
* Returns the absolute link to the previous page for use in the page meta tags. This helps search engines
* find the pagination and index all pages properly.
*
* @example "<% if $PaginationAbsolutePrevLink %><% end_if %>"
*
* @return string|null
*/
public function PaginationAbsolutePrevLink()
{
$posts = $this->PaginatedList();
if ($posts->NotFirstPage()) {
return Director::absoluteURL($posts->PrevLink());
}
return null;
}
/**
* Displays an RSS feed of blog posts.
*
* @return string
*/
public function rss()
{
/**
* @var Blog $dataRecord
*/
$dataRecord = $this->dataRecord;
$this->blogPosts = $dataRecord->getBlogPosts();
return $this->rssFeed($this->blogPosts, $this->Link());
}
/**
* Returns the current archive date.
*
* @return null|DBDatetime
*/
public function getArchiveDate()
{
$year = $this->getArchiveYear();
$month = $this->getArchiveMonth();
$day = $this->getArchiveDay();
if ($year) {
if ($month) {
$date = sprintf('%s-%s-01', $year, $month);
if ($day) {
$date = sprintf('%s-%s-%s', $year, $month, $day);
}
} else {
$date = sprintf('%s-01-01', $year);
}
$obj = DBDatetime::create('date');
$obj->setValue($date);
return $obj;
}
return null;
}
/**
* Returns a link to the RSS feed.
*
* @return string
*/
public function getRSSLink()
{
return $this->Link('rss');
}
/**
* Displays an RSS feed of the given blog posts.
*
* @param DataList $blogPosts
* @param string $link
*
* @return string
*/
protected function rssFeed($blogPosts, $link)
{
$rss = RSSFeed::create($blogPosts, $link, $this->MetaTitle, $this->MetaDescription);
$this->extend('updateRss', $rss);
return $rss->outputToBrowser();
}
/**
* Returns true if the $Rss sub-action for categories/tags has been set to "rss"
*
* @return bool
*/
protected function isRSS()
{
$rss = $this->request->param('Rss');
return (is_string($rss) && strcasecmp($rss ?? '', 'rss') == 0);
}
}