ProcessWire - Blog: Unterschied zwischen den Versionen
Aus Wikizone
(→Felder) |
|||
| (2 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt) | |||
| Zeile 10: | Zeile 10: | ||
== Beispiel mit PageReference für Kategorien == | == Beispiel mit PageReference für Kategorien == | ||
| + | |||
| + | === Paging === | ||
=== Module === | === Module === | ||
* Comments / Kommentare (Core) | * Comments / Kommentare (Core) | ||
| + | * InputfieldCommentsAdmin | ||
| + | * FieldtypeComments | ||
| + | https://processwire.com/docs/modules/guides/comments/ | ||
=== Felder === | === Felder === | ||
Aktuelle Version vom 26. Mai 2021, 16:12 Uhr
Wie erstellt man einen Blog oder eine News-Section in ProcessWire ?
ProcessBlog Modul von Kongondo[Bearbeiten]
Zu viel Zeug drin ;-)
https://processwire.com/modules/process-blog/ ProcessBlog
Eigenes Blog Modul erstellen[Bearbeiten]
Todo
Beispiel mit PageReference für Kategorien[Bearbeiten]
Paging[Bearbeiten]
Module[Bearbeiten]
- Comments / Kommentare (Core)
- InputfieldCommentsAdmin
- FieldtypeComments
https://processwire.com/docs/modules/guides/comments/
Felder[Bearbeiten]
- date (Datum des Blog-Eintrags)
- comments (Verwaltet Kommentare für eine Seite. Hier für einen Blog-Eintrag)
- tags (Legt die Tags/Kategorien für einen Blogeintrag fest) - Hier mußt du noch die Parent Page festlegen
- pr_single (Legt die Seite für die Einzelansicht in der Blog-Seite fest)
Templates[Bearbeiten]
- tag (steht für eine Blog-Kategorie)
- tags (unterhalb dieser Seite kann man nur Kategorien / Tags anlegen)
- blog (Gibt den Blog aus)
- blog-post (Steht für einen einzelnen Blogeintrag und für die Einzelansicht)
Rechte[Bearbeiten]
Benutzerrolle: editor
- category.add
- category.edit
- category.create
Kopiervorlage[Bearbeiten]
Felder[Bearbeiten]
{
"comments": {
"id": 134,
"name": "comments",
"label": "Comments",
"flags": 0,
"type": "FieldtypeComments",
"schemaVersion": 6,
"moderate": 1,
"redirectAfterPost": 1,
"quietSave": 1,
"deleteSpamDays": 3,
"useWebsite": 1,
"dateFormat": "relative",
"useGravatar": "g",
"tags": "blog",
"icon": "comment-o",
"notificationEmail": "",
"fromEmail": "",
"notifySpam": "",
"useNotify": 0,
"useAkismet": "",
"depth": 0,
"sortNewest": "",
"useVotes": 0,
"useStars": 0,
"collapsed": 0,
"showIf": "",
"themeOffset": "",
"themeBorder": "",
"themeColor": "",
"columnWidth": 100,
"required": "",
"requiredIf": ""
},
"date": {
"id": 133,
"name": "date",
"label": "Date",
"flags": 0,
"type": "FieldtypeDatetime",
"dateOutputFormat": "j.n.Y",
"size": 25,
"datepicker": 3,
"dateInputFormat": "d.m.Y",
"defaultToday": 1,
"placeholder": "yyyy/mm/dd",
"icon": "calendar",
"tags": "blog",
"inputType": "text",
"dateSelectFormat": "yMd",
"yearFrom": 1921,
"yearTo": 2041,
"htmlType": "date",
"collapsed": 0,
"timeInputSelect": 0,
"yearLock": 0,
"columnWidth": 20,
"showIf": "",
"themeOffset": "",
"themeBorder": "",
"themeColor": "",
"required": "",
"requiredAttr": "",
"requiredIf": "",
"dateMin": "",
"dateMax": "",
"timeStep": "",
"timeMin": "",
"timeMax": "",
"timeInputFormat": "",
"yearRange": ""
}
}
Templates[Bearbeiten]
{
"blog": {
"id": 76,
"name": "blog",
"fieldgroups_id": "blog",
"flags": 0,
"cache_time": 0,
"useRoles": 1,
"editRoles": [
"editor"
],
"addRoles": [
"editor"
],
"createRoles": [
"editor"
],
"rolesPermissions": [],
"noInherit": 0,
"childrenTemplatesID": 0,
"sortfield": "",
"noChildren": "",
"noParents": "",
"childTemplates": [],
"parentTemplates": [],
"allowPageNum": 1,
"allowChangeUser": 0,
"redirectLogin": 0,
"urlSegments": 1,
"https": 0,
"slashUrls": 1,
"slashPageNum": 0,
"slashUrlSegments": 0,
"altFilename": "",
"guestSearchable": 0,
"pageClass": "",
"childNameFormat": "",
"pageLabelField": "",
"noGlobal": 0,
"noMove": 0,
"noTrash": 0,
"noSettings": 0,
"noChangeTemplate": 0,
"noShortcut": 0,
"noUnpublish": 0,
"noLang": 0,
"compile": 3,
"nameContentTab": 0,
"noCacheGetVars": "",
"noCachePostVars": "",
"useCacheForUsers": 0,
"cacheExpire": 0,
"cacheExpirePages": [],
"cacheExpireSelector": "",
"label": "Blog",
"tags": "",
"titleNames": 0,
"noPrependTemplateFile": 0,
"noAppendTemplateFile": 0,
"prependFile": "",
"appendFile": "",
"pagefileSecure": false,
"tabContent": "",
"tabChildren": "",
"nameLabel": "",
"contentType": "",
"errorAction": 0,
"connectedFieldID": null,
"ns": "ProcessWire",
"_exportMode": true,
"roles": [
"guest",
"editor"
],
"fieldgroupFields": [
"title",
"menus",
"pr_single"
],
"fieldgroupContexts": {
"title": [],
"menus": [],
"pr_single": {
"columnWidth": 50,
"label": "Kategorien",
"notes": "Wähle die Seite aus, welche die Kategorien enthält."
}
}
},
"blog-post": {
"id": 74,
"name": "blog-post",
"fieldgroups_id": "blog-post",
"flags": 0,
"cache_time": -604800,
"useRoles": 0,
"noInherit": 1,
"childrenTemplatesID": 0,
"sortfield": "",
"noChildren": "",
"noParents": "",
"childTemplates": [],
"parentTemplates": [],
"allowPageNum": 0,
"allowChangeUser": 0,
"redirectLogin": 0,
"urlSegments": 0,
"https": 0,
"slashUrls": 1,
"slashPageNum": 0,
"slashUrlSegments": 0,
"altFilename": "",
"guestSearchable": 0,
"pageClass": "",
"childNameFormat": "",
"pageLabelField": "",
"noGlobal": 0,
"noMove": 0,
"noTrash": 0,
"noSettings": 0,
"noChangeTemplate": 0,
"noShortcut": 0,
"noUnpublish": 0,
"noLang": 0,
"compile": 3,
"nameContentTab": 0,
"noCacheGetVars": "",
"noCachePostVars": "",
"useCacheForUsers": 0,
"cacheExpire": 0,
"cacheExpirePages": [],
"cacheExpireSelector": "",
"label": "Blog-Post (News)",
"tags": "",
"titleNames": 0,
"noPrependTemplateFile": 0,
"noAppendTemplateFile": 0,
"prependFile": "",
"appendFile": "",
"pagefileSecure": false,
"tabContent": "",
"tabChildren": "",
"nameLabel": "",
"contentType": "",
"errorAction": 0,
"connectedFieldID": null,
"ns": "ProcessWire",
"_exportMode": true,
"fieldgroupFields": [
"title",
"date",
"body",
"images",
"files",
"categories",
"comments"
],
"fieldgroupContexts": {
"title": [],
"date": {
"columnWidth": 25
},
"body": [],
"images": [],
"files": [],
"categories": [],
"comments": []
}
},
"categories": {
"id": 77,
"name": "categories",
"fieldgroups_id": "categories",
"flags": 0,
"cache_time": 0,
"useRoles": 1,
"editRoles": [
"editor"
],
"addRoles": [
"editor"
],
"createRoles": [
"editor"
],
"rolesPermissions": [],
"noInherit": 0,
"childrenTemplatesID": 0,
"sortfield": "",
"noChildren": "",
"noParents": "",
"childTemplates": [
"category"
],
"parentTemplates": [],
"allowPageNum": 0,
"allowChangeUser": 0,
"redirectLogin": 0,
"urlSegments": 0,
"https": 0,
"slashUrls": 1,
"slashPageNum": 0,
"slashUrlSegments": 0,
"altFilename": "",
"guestSearchable": 0,
"pageClass": "",
"childNameFormat": "",
"pageLabelField": "",
"noGlobal": 0,
"noMove": 0,
"noTrash": 0,
"noSettings": 0,
"noChangeTemplate": 0,
"noShortcut": 0,
"noUnpublish": 0,
"noLang": 0,
"compile": 3,
"nameContentTab": 0,
"noCacheGetVars": "",
"noCachePostVars": "",
"useCacheForUsers": 0,
"cacheExpire": 0,
"cacheExpirePages": [],
"cacheExpireSelector": "",
"label": "Kategorien",
"tags": "",
"titleNames": 0,
"noPrependTemplateFile": 0,
"noAppendTemplateFile": 0,
"prependFile": "",
"appendFile": "",
"pagefileSecure": false,
"tabContent": "",
"tabChildren": "",
"nameLabel": "",
"contentType": "",
"errorAction": 0,
"connectedFieldID": null,
"ns": "ProcessWire",
"_exportMode": true,
"roles": [
"guest",
"editor"
],
"fieldgroupFields": [
"title"
],
"fieldgroupContexts": {
"title": []
}
},
"category": {
"id": 75,
"name": "category",
"fieldgroups_id": "category",
"flags": 0,
"cache_time": 0,
"useRoles": 1,
"editRoles": [
"editor"
],
"addRoles": [
"editor"
],
"createRoles": [
"editor"
],
"rolesPermissions": [],
"noInherit": 0,
"childrenTemplatesID": 0,
"sortfield": "",
"noChildren": "",
"noParents": "",
"childTemplates": [],
"parentTemplates": [
"categories"
],
"allowPageNum": 0,
"allowChangeUser": 0,
"redirectLogin": 0,
"urlSegments": 0,
"https": 0,
"slashUrls": 1,
"slashPageNum": 0,
"slashUrlSegments": 0,
"altFilename": "",
"guestSearchable": 0,
"pageClass": "",
"childNameFormat": "",
"pageLabelField": "",
"noGlobal": 0,
"noMove": 0,
"noTrash": 0,
"noSettings": 0,
"noChangeTemplate": 0,
"noShortcut": 0,
"noUnpublish": 0,
"noLang": 0,
"compile": 3,
"nameContentTab": 0,
"noCacheGetVars": "",
"noCachePostVars": "",
"useCacheForUsers": 0,
"cacheExpire": 0,
"cacheExpirePages": [],
"cacheExpireSelector": "",
"label": "",
"tags": "",
"titleNames": 0,
"noPrependTemplateFile": 0,
"noAppendTemplateFile": 0,
"prependFile": "",
"appendFile": "",
"pagefileSecure": false,
"tabContent": "",
"tabChildren": "",
"nameLabel": "",
"contentType": "",
"errorAction": 0,
"connectedFieldID": null,
"ns": "ProcessWire",
"_exportMode": true,
"roles": [
"guest",
"editor"
],
"fieldgroupFields": [
"title"
],
"fieldgroupContexts": {
"title": []
}
}
}
Beispiel (Anlehnung an Ryans Blog Beispiel)[Bearbeiten]
Templates[Bearbeiten]
blog.php
<?php namespace ProcessWire;
// v1.0
// This is the template file for main /blog/ page that lists blog post summaries.
// If there are more than 10 posts, it also paginates them.
include("./partials/layout-blocks.inc");
$layoutBlocks = renderLayoutBlocks($page,$additionalHeaderData);
$pagerOptions = array(
'listMarkup' => "<ul class='uk-pagination'>{out}</ul>",
);
?>
<main id='main' class='uk-container uk-margin uk-margin-large-bottom'>
<div class='uk-grid-large' uk-grid>
<div id='content' class='uk-width-expand'>
<?php
echo ukHeading1(page()->title, 'divider');
$posts = page()->children('limit=8,sort=-date');
$pagination = $posts->renderPager($pagerOptions);
echo($pagination);
echo ukBlogPosts($posts);
?>
</div>
<aside id='sidebar' class='uk-width-1-3@m'>
<?php
$categories = pages()->get('/categories/');
echo '<div class="uk-card uk-card-muted uk-card-hover uk-card-body uk-margin-medium-top">'.ukNav($categories->children, [ 'header' => $categories->title ]).'</div>';
?>
</aside>
</div>
</main>
Helper Functions[Bearbeiten]
_uikit.php (Auszug)
/*****************************************************************************************
* ProcessWire/Uikit functions for blog support
*
*/
/**
* Render a blog post using Uikit “article” component
*
* @param Page $page Blog post
* @param array|string $options Options to modify default behavior
* - `summarize` (bool): Display blog post summary rather than full post? (default=auto-detect).
* - `metaIcon` (string): Icon to use for blog meta info in header (default=info).
* - `moreIcon` (string): Icon to use for more link in summarized blog post (default=more).
* - `categoryIcon` (string): Icon to use for identification of categories in blog header (default=hashtag).
* - `bylineText` (string): Template for byline (default=“Posted by %1$s on %2$s”).
* @return string
*
*/
function ukBlogPost(Page $page, $options = array()) {
$defaults = array(
'summarize' => null, // Display blog post summary rather than full post? (null=auto-detect)
'metaIcon' => 'info',
'moreIcon' => 'arrow-right',
'moreText' => __('Read more'),
'categoryIcon' => 'hashtag',
//'bylineText' => __('Posted by %1$s on %2$s'),
'bylineText' => '%2$s',
);
$options = _ukMergeOptions($defaults, $options);
$title = $page->title;
$date = $page->date ? $page->date : $page->createdStr;
//$created = date('d.m.Y',$page->getUnformatted("date"));
//$created = date('d.m.Y',$page->get("modified"));
$name = $page->createdUser->name;
$body = $page->body;
$metaIcon = ukIcon($options['metaIcon']);
$moreIcon = ukIcon($options['moreIcon']);
$categoryIcon = ukIcon($options['categoryIcon']);
$n = $page->comments->count();
$numComments = $n ? "<a href='$page->url#comments'>" . ukIcon('comments') . " $n</a>" : "";
if($options['summarize'] === null) {
// auto-detect: summarize if current page is not the same as the blog post
$options['summarize'] = page()->id != $page->id;
}
$categories = $page->categories->each($categoryIcon .
"<a class='uk-button uk-button-text' href='{url}'>{title}</a> "
);
if($options['summarize']) {
// link to post in title, and use just the first paragraph in teaser mode
$title = "<a href='$page->url'>$title</a>";
$body = explode('</p>', $body);
$body = reset($body) . ' ';
$body .= "<br><a href='$page->url'>$options[moreText] $moreIcon</a></p>";
$class = 'blog-post-summary';
} else {
$class = 'blog-post-full';
}
if($options['summarize']) {
$heading = "<h2 class='uk-margin-remove'>$title</h2>";
} else {
$heading = "<h1 class='uk-article-title uk-margin-remove'>$title</h1>";
}
$byline = sprintf($options['bylineText'], $name, $date);
// return the blog post article markup
return "
<article class='uk-article blog-post $class'>
$heading
<p class='uk-margin-small'>
<span class='uk-article-meta'>
$metaIcon
$byline
</span>
<span class='categories'>
$categories
</span>
<span class='num-comments uk-margin-small-left uk-text-muted'>
$numComments
</span>
</p>
$body
</article>
<hr>
";
}
/**
* Render multiple blog posts summarized
*
* @param PageArray $posts
* @param array|string $options See the ukBlogPost() method for options, plus:
* - `paginate` (bool): Use pagination when applicable? (default=true)
* @return string
*
*/
function ukBlogPosts(PageArray $posts, $options = array()) {
if(!$posts->count) {
if(input()->pageNum > 1) {
// redirect to first pagination if accessed at an out-of-bounds pagination
session()->redirect(page()->url);
}
return '';
}
$defaults = array(
'paginate' => false
);
$options = _ukMergeOptions($defaults, $options);
$out = "<div class='blog-posts'>";
foreach($posts as $post) {
$out .= ukBlogPost($post, $options);
}
if($options['paginate'] && $posts->getTotal() > $posts->count()) {
$out .= ukPagination($posts);
}
$out .= "</div>";
return $out;
}
/*****************************************************************************************
* ProcessWire/Uikit functions for rendering comments and comment forms
*
* Note: comment threads (depth), stars and votes are not yet supported in here.
*
*/
/**
* Render a ProcessWire comment using Uikit markup
*
* (work in progress)
*
* @param Comment $comment
* @param array|string $options Coming soon
* @return string
*
*/
function ukComment(Comment $comment, $options = array()) {
$defaults = array(
'comments' => null, // instance of CommentArray when called from ukComments()
'depth' => 0,
);
// $options = _ukMergeOptions($defaults, $options);
$text = $comment->getFormatted('text');
$cite = $comment->getFormatted('cite');
$website = $comment->getFormatted('website');
$field = $comment->getField();
$page = $comment->getPage();
$classes = array();
$metas = array();
$gravatar = '';
$replies = '';
if($field->get('useGravatar')) {
$img = $comment->gravatar($field->get('useGravatar'), $field->get('useGravatarImageset'));
if($img) $gravatar = "<div class='uk-width-auto'><img class='uk-comment-avatar' src='$img' alt='$cite'></div>";
}
if($website) $cite = "<a href='$website' rel='nofollow' target='_blank'>$cite</a>";
$created = wireDate('relative', $comment->created);
if($field->get('usePermalink')) {
$permalink = $page->httpUrl;
$urlSegmentStr = $this->wire('input')->urlSegmentStr;
if($urlSegmentStr) $permalink .= rtrim($permalink, '/') . $urlSegmentStr . '/';
$permalink .= '#Comment' . $comment->id;
$permalink = "<a href='$permalink'>" . __('Permalink') . "</a>";
$metas[] = "<li>$permalink</li>";
}
$classes = implode(' ', $classes);
$metas = implode('', $metas);
$out = "
<article id='Comment$comment->id' class='$classes uk-comment uk-comment-primary' data-comment='$comment->id'>
<header class='uk-comment-header uk-grid-medium uk-flex-middle' uk-grid>
$gravatar
<div class='uk-width-expand'>
<h4 class='uk-comment-title uk-margin-remove'>$cite</h4>
<ul class='uk-comment-meta uk-subnav uk-subnav-divider uk-margin-remove-top'>
<li>$created</li>
$metas
</ul>
</div>
</header>
<div class='uk-comment-body'>
$text
</div>
</article>
$replies
";
return $out;
}
/**
* Render a list of ProcessWire comments using Uikit markup
*
* @param CommentArray $comments
* @param array|string $options Options to modify default behavior
* - `id` (string): HTML id attribute of the comments list (default='comments').
* - `parent_id` (int): Database id of the parent comment, when rendering a comment thread.
* @return string
*
*/
function ukComments(CommentArray $comments, $options = array()) {
$defaults = array(
'id' => 'comments',
'parent_id' => 0,
'comments' => $comments, // for ukComment() method only
);
if(!count($comments)) return '';
$options = _ukMergeOptions($defaults, $options);
$out = "<ul id='$options[id]' class='uk-comment-list'>";
foreach($comments as $comment) {
$out .= "<li class='uk-margin'>" . ukComment($comment, $options) . "</li>";
}
$out .= "</ul>";
return $out;
}
/**
* Render a comment posting form
*
* @param CommentArray $comments
* @param array $options See `CommentForm` class for all options.
* @return string
*
*/
function ukCommentForm(CommentArray $comments, array $options = array()) {
$defaults = array(
'headline' => "",
'successMessage' =>
__('Thank you, your comment has been posted.'),
'pendingMessage' =>
__('Your comment has been submitted and will appear once approved by the moderator.'),
'errorMessage' =>
__('Your comment was not saved due to one or more errors.') . ' ' .
__('Please check that you have completed all fields before submitting again.'),
);
$options = _ukMergeOptions($defaults, $options);
$options['successMessage'] = ukAlertSuccess($options['successMessage'], 'check');
$options['pendingMessage'] = ukAlertSuccess($options['pendingMessage'], 'check');
$options['errorMessage'] = ukAlertDanger($options['errorMessage'], 'warning');
if(!isset($options['attrs']) || !isset($options['attrs']['class'])) {
$options['attrs'] = array('class' => 'uk-comment uk-comment-primary');
}
$adjustments = array(
"<input type='text'" => "<input type='text' class='uk-input'",
"<p class='CommentForm" => "<p class='uk-margin-remove-top CommentForm",
"<textarea " => "<textarea class='uk-textarea' ",
"<button " => "<button class='uk-button uk-button-primary' ",
"<label " => "<label class='uk-form-label' ",
);
$out = $comments->renderForm($options);
$out = str_replace(array_keys($adjustments), array_values($adjustments), $out);
return $out;
}
_helpers.php
function truncateText($text,$characters=500){
$summary = strip_tags($text);
if(strlen($summary) > $characters) {
$summary = substr($summary, 0, $characters); // display no more than 500 chars
$trimToSentence = substr($summary, 0, strrpos($summary, ". ")+1); // and truncate to last sentence
if( strlen( $trimToSentence) > intval($characters/3) ) $summary = $trimToSentence; // use it if not too short
}
$summary = trim($summary);
return $summary;
}