Neuigkeiten:

Privates MODX und LINUX BLOG, User Registrierung ist deaktiviert! Fragen oder Tipps? Bitte per Matrix: @jolichter:tchncs.de

Hauptmenü

MODX Guestbook

Begonnen von Jo, 2013-01-18 | 12:38:15

« vorheriges - nächstes »

Jo

Hier stelle ich euch ein Gästebuch für MODx Revolution zum Nachbauen vor
*** getestet mit MODx Revo 2.2.6-pl ***

Merkmale V13.02.23 (Jahr.Monat.Edition):
+ soviel Felder anlegen wie ihr wollt
+ eMail Benachrichtigung
+ eMail Syntax-Überprüfung
+ eMail Anzeigen ja/nein
+ eMail Maskierung
+ Spamschutz
+ Icon Set und BBCode
+ Seitenbewertung
+ Kommentare im Frontend ändern und de- bzw. aktivieren*
+ deaktivierte Kommentare endgültig löschen*
+ IP wird gespeichert (das erfolgt zur Sicherheit des Anbieters, falls jemand in Beiträgen widerrechtlichen Inhalt schreibt)

* nur User mit ID1 - wenn mehr User diese Berechtigung haben sollen - einfach die Output Filter !+modx.user.id:eq=`1` durch ein !+modx.user.id:memberof=`Administrator` ersetzen (oder einer anderen Gruppe).

Vorwort:
Danke an Jako der ein Gästebuch für Evo per JOT vorstellt. Ohne ihn wäre das alles viel schwerer geworden. Ebenso will ich mich hiermit für die tolle Unterstützung von Sam und Bruno aus dem MODx-Forum bedanken.

Da QUIP meiner Meinung nicht wirklich als Gästebuch tauglich ist (keine zusätzliche Felder möglich) - aber eine sehr gute Kommentarkomponente ist - habe ich mir ein Gästebuch mit FormIt und formit2db zusammen gestellt.



#### Vorbereitungen ####

Folgende drei Packages werden benötigt:
(in Klammer stehen meine Versionen)
- FormIt (2.1.2-pl) - Form Eingabefeld
- rowboat (1.1.0-pl) - DB lesen
- getPage (1.2.3-pl) - Paginierung

wenn ihr das installiert habt, müssen zwei snippets -
db2formit und formit2db - erstellt werden: formit2db with autocreate schema&classes.

und los geht es:

1) V11.09.4 - eine custom SQL-Tabelle für formit2db anlegen
(z.B. mit phpMyAdmin importieren)
CREATE TABLE `modx_custom_guestbook`(
  `id` int(10) NOT NULL auto_increment,
  `gbip` varchar(50) NOT NULL default '0:0:0:0:0:0:0:0',
  `gbname` varchar(50) NOT NULL default '',
  `gbemail` varchar(60) NOT NULL default '',
  `gbemailshow` tinyint(1) NOT NULL default '0',
  `gbhome` varchar(50) NOT NULL default '',
  `gbwebsite` varchar(100) NOT NULL default '',
  `gbvote` int(1) NOT NULL default '0',
  `gbtext` text NOT NULL,
  `gbdate` timestamp NOT NULL default CURRENT_TIMESTAMP,
  `gbactive` tinyint(1) NOT NULL default '1',
PRIMARY KEY (`id`)
);
Wichtig: bei mir ist der PREFIX 'modx_' (Standard), evt. müsst ihr das anpassen. Hinweis: ich habe 'gbwebsite' hier nur optional in die DB geschrieben und kann dieses Feld daher bei Wunsch später verwenden.


#### snippets erstellen ####

2) V11.10.2 - 'myIP'
<?php
# IP von der Anfrage auf dem Server
if (isset($_SERVER['REMOTE_ADDR'])) $ipCode=$_SERVER['REMOTE_ADDR'];
  else 
$ipCode='0:0:0:0:0:0:0:0';

return 
$ipCode;

3) V11.09.6 - 'guestbookQty'
<?php
# zähle aktivierte Einträge [[!guestbookQty?active=`1`]]
$stmt $modx->query('SELECT * FROM `modx_custom_guestbook` WHERE `gbactive`='.$active);
$count=0;
$count $stmt->rowCount();

return 
$count;

4) V11.09.2 - 'smilies'
(passende Smilie-Grafiken unter 'assets/images/icons/smilies/' nicht vergessen - freie findet ihr im www ; -)
<?php
# Output-Filter zur Darstellung der Smilies in den Gästebucheinträgen
# z.B.: # [[+gbtext:nl2br:smilies]]
#
// Path where the smilies are stored
$basepath $modx->config['site_url'].'assets/images/smilies/';
// Mapping of text to imagename
$smilies = array(':biggrin:' => 'biggrin.gif',':-)' => 'smile.gif',':-(' => 'mad.gif',':eek:' => 'bigeek.gif',':-P' => 'razz.gif',':oops:' => 'upset.gif',':cry:' => 'cry.gif',':evil:' => 'sigh.gif',':dead:' => 'dead.gif',':roll:' => 'rolleyes.gif',';-)' => 'wink.gif','8-)' => 'cool.gif',':-?' => 'confused.gif',':sleep:' => 'sleep.gif');

// Convert imagenames to html tags here, just to keep the structure above
// easy to maintain, especially when I want to change the generated HTML.
  
foreach ($smilies as $key => $value)
  {
  
$smilies[$key] = "<img src='".$basepath.$value."' class='smilie' alt='$key' />";
  }

return 
str_replace(array_keys($smilies), array_values($smilies), $input);

5) V11.10.1 - 'bbcode'
Output-Filter zur Darstellung von BBCode in den Gästebucheinträgen
z.B.: [[+gbtext:bbcode]]
<?php
$string 
preg_replace("/&amp;(#[0-9]+|[a-z]+);/i""&$1;"htmlspecialchars($input));
$string preg_replace('~\[b\](.+?)\[/b\]~is''<b>\1</b>'$string);
$string preg_replace('~\[i\](.+?)\[/i\]~is''<i>\1</i>'$string);
$string preg_replace('~\[u\](.+?)\[/u\]~is''<span style="text-decoration: underline;">\1</span>'$string);
$string preg_replace('~\[center\](.+?)\[/center\]~is''<div style="text-align:center;">\1</div>'$string);
$string preg_replace('~\[link\]www.(.+?)\[/link\]~is''<a href="https://www.\1" target="_blank">www.\1</a>'$string);
$string preg_replace('~\[link\](.+?)\[/link\]~is''<a href="\1" target="_blank">\1</a>'$string);
$string preg_replace('~\[link=(.+?)\](.+?)\[/link\]~is''<a href="\1" target="_blank">\2</a>'$string);
$string preg_replace('~\[url\]www.(.+?)\[/url\]~is''<a href="https://www.\1" target="_blank">www.\1</a>'$string);
$string preg_replace('~\[url\](.+?)\[/url\]~is''<a href="\1" target="_blank">\1</a>'$string);
$string preg_replace('~\[url=(.+?)\](.+?)\[/url\]~is''<a href="\1" target="_blank">\2</a>'$string);
$string str_replace(array("[","]","`"),array("[","]","`"),$string);
 
return 
$string;

6) V11.09.1 - 'vote'
<?php
# Output-Filter zur Darstellung der Vote-Icons in den Gästebucheinträgen
# z.B.:
# [[+gbvote:vote]]

$vote '';
  for (
$i 1$i <= $input$i++) {
  
$vote .= '<img src="assets/images/icons/vote.png" class="vote" alt="Bewertung" />';
  }

return 
$vote;

7) V11.10.1 - 'emailMask'
<?php
# email-Adressen vor bösen bots durch Maskierung verbergen
  
$hiddenEmail '';
  
$length strlen($input);
  for(
$i 0;$i<$length;$i++){
       
$hiddenEmail .= '&#'.ord($input[$i]).';';
  }

return 
$hiddenEmail;


#### chunks erstellen ####

8 ) V11.09.1 - 'guestbookAddSmile'
(javascript)
<script type="text/javascript">
function AddSmile(x,D,F){D=document;F=D.getElementById('gbtext');D.selection?(F.focus(),D.selection.createRange().text=x):(F.selectionStart||F.selectionStart===0)?F.value=F.value.substring(0,F.selectionStart)+x+F.value.substring(F.selectionEnd,F.value.length):F.value+=x}
</script>
Achtung: Das Javascript setzt den Smilie-Text in ein textarea mit der ID 'gbtext' ein. Auf der Seite darf es deshalb kein anderes Element mit dieser ID geben.

9) V11.09.1 - 'guestbookSmilies'
(evt. müsst ihr das anpassen)
<div class="smilies">
<div class="smilieSelect"><img src="assets/images/icons/smilies/biggrin.gif" alt="biggrin" onclick="AddSmile(':biggrin:')" /></div>
<div class="smilieSelect"><img src="assets/images/icons/smilies/smile.gif" alt=":-)" onclick="AddSmile(':-)')" /></div>
<div class="smilieSelect"><img src="assets/images/icons/smilies/mad.gif" alt=":-(" onclick="AddSmile(':-(')" /></div>
<div class="smilieSelect"><img src="assets/images/icons/smilies/bigeek.gif" alt=":eek:" onclick="AddSmile(':eek:')" /></div>
<div class="smilieSelect"><img src="assets/images/icons/smilies/razz.gif" alt=":-P" onclick="AddSmile(':-P')" /></div>
<div class="smilieSelect"><img src="assets/images/icons/smilies/upset.gif" alt=":oops:" onclick="AddSmile(':oops:')" /></div>
<div class="smilieSelect"><img src="assets/images/icons/smilies/cry.gif" alt=":cry:" onclick="AddSmile(':cry:')" /></div>
<div class="smilieSelect"><img src="assets/images/icons/smilies/sigh.gif" alt=":evil:" onclick="AddSmile(':evil:')" /></div>
<div class="smilieSelect"><img src="assets/images/icons/smilies/dead.gif" alt="dead" onclick="AddSmile(':dead:')" /></div>
<div class="smilieSelect"><img src="assets/images/icons/smilies/rolleyes.gif" alt=":roll:" onclick="AddSmile(':roll:')" /></div>
<div class="smilieSelect"><img src="assets/images/icons/smilies/wink.gif" alt=";-)" onclick="AddSmile(';-)')" /></div>
<div class="smilieSelect"><img src="assets/images/icons/smilies/cool.gif" alt="8-)" onclick="AddSmile('8-)')" /></div>
<div class="smilieSelect"><img src="assets/images/icons/smilies/confused.gif" alt=":-?" onclick="AddSmile(':-?')" /></div>
<div class="smilieSelect"><img src="assets/images/icons/smilies/sleep.gif" alt=":sleep:" onclick="AddSmile(':sleep:')" /></div>
</div>

10) V13.02.10 - 'tplGuestbookEntry'
<div class="guestbook_top">
<span class="guestbook_big">
[[+gbname:htmlent]]
</span>
<span class="guestbook_small">
am [[+gbdate:strtotime:date=`%d-%m-%Y, %H:%M:%S Uhr`]] aus [[+gbhome:htmlent]]
</span>
<span class="guestbook_vote">
[[+gbvote:vote]]
</span>
</div>

<div [[+_alt:is=`0`:then=`class="guestbook_content"`:else=`class="guestbook_content_b"`]]>
<span class="gbemail">
[[+gbemailshow:eq=`1`:then=`<a href="mailto:[[+gbemail:htmlent:emailMask]]">eMail</a>`:else=``]]
[[+gbemailshow:eq=`1`:then=`<a href="[[emailMask? &input=`mailto:[[+gbemail:htmlent]]`]]">eMail</a>`:else=``]]
[[!+modx.user.id:eq=`1`:then=`<br />[[+gbemail:htmlent:emailMask]]`:else=``]]
</span>
[[+gbtext:htmlent:bbcode:nl2br:smilies]]
[[!+modx.user.id:eq=`1`:then=`
<br /><a href="[[~42? &resId=`[[+id]]`]]">Eintrag ändern</a><br />
IP: <a href="https://apps.db.ripe.net/search/query.html?searchtext=[[+gbip]]" target="_blank">[[+gbip]]</a><br />
[[+gbactive:eq=`1`:then=``:else=`<font color=#990000>Kommentar ist deaktiviert!</font>`]]
`:else=``]]
</div>
ID der resource 'Gästebuch' anpassen, z.B. 42

11) V11.09.5 - 'guestbookEntry'
(getPage für die Paginierung; Rowboat liest die Kommentare aus der DB)
[[!getPage:default=`Fehler oder kein aktivier Eintrag vorhanden!`?
  &element=`Rowboat`
  &table=`modx_custom_guestbook`
  &sortBy=`id`
  &sortDir=`DESC`
  &where=`[[!+modx.user.id:eq=`1`:then=`{"gbactive:=":"1","OR:gbactive":"0"}`:else=`{"gbactive:=":"1"}`]]`
  &totalVar=`rowboat.total`
  &cacheResults=`0`
  &tpl=`tplGuestbookEntry`
  &limit=`10`
  &pageFirstTpl=`<li class="control"><a[[+classes]][[+title]] href="[[+href]]">Erste</a></li>`
  &pageLastTpl=`<li class="control"><a[[+classes]][[+title]] href="[[+href]]">Letzte</a></li>`
]]
[[!+page.nav:notempty=`
<div class="paging">
<ul class="pageList">
  [[!+page.nav]]
</ul></div>`]]
Wichtig: &cacheResults=`0` !

12) V11.10.2 - 'guestbookEmail'
Gesendet vom MODx-Gästebuch<br />
<br />[[+gbname:htmlent]] ([[+gbemail:htmlent]]) hat als Eintrag geschrieben: <br /><br />
[[+gbtext:htmlent:nl2br]]
<br /><br />
Bewertung: [[+gbvote]]<br />
Ort: [[+gbhome:htmlent]]<br />
IP: [[+gbip]]<br />

13) V12.03.11 - 'guestbookForm'
[[!FormIt?
  &hooks=`math,spam,email,formit2db,redirect`
  &preHooks=`db2formit`
  &prefix=`modx_custom_`
  &tablename=`guestbook`
  &packageName=`guestbook`
  &emailTpl=`guestbookEmail`
  &emailTo=`DeineEMail@deutschland.de`
  &emailUseFieldForSubject=`1`
  &emailSubject=`Neuer MODx Gästebucheintrag`
  &redirectTo=`42`
  &mathMinRange=`10`
  &mathMaxRange=`50`
  &validate=`gbname:required:maxLength=`50`,
   gbemail:email:required:maxLength=`60`,
   gbhome:required:maxLength=`50`,
   gbtext:required:stripTags:maxLength=`3000`,
   gbvote:required,
   confirm:blank`
]]
[[$guestbookAddSmile]]
<h3>Gästebucheintrag</h3>
[[!+fi.error.error_message:notempty=`<p>[[!+fi.error.error_message]]</p>`]]
<form action="[[~[[*id]]]]" method="post" class="form">
<input type="hidden" name="confirm" value="" />
<input name="resource_id" type="hidden" value="[[+fi.id]]" />
[[!+modx.user.id:eq=`1`:then=``:else=`<input type="hidden" name="gbip" value="[[!myIP?]]" />`]]

[[!+modx.user.id:eq=`1`:then=`
<tr><th align="left">Aktiv:</th>
<th align="left">
<input type="hidden" name="gbactive[]" value="0" />
<input type="checkbox" name="gbactive[]" id="gbactive" value="1" [[!+fi.gbactive:FormItIsChecked=`1`]] />
Kommentar veröffentlichen? <br /><br />
</th></tr>
`:else=``]]

<table border="0" cellspacing="4" cellpadding="4">
<tr><th align="left"><label for="gbname">Name:</label></th>
<th align="left"><input type="text" name="gbname" id="gbname" maxlength="50" value="[[!+fi.gbname:htmlent]]" />
<span class="error">[[+fi.error.gbname]]</span>
</th></tr>

<tr><th align="left"><label for="gbhome">Wohnort:</label></th>
<th align="left"><input type="text" name="gbhome" id="gbhome" maxlength="50" value="[![+fi.gbhome:htmlent]]" />
<span class="error">[[+fi.error.gbhome]]</span>
</th></tr>

<tr><th align="left" valign="top"><label for="gbemail">eMail:</label></th>
<th align="left"><input type="text" name="gbemail" id="gbemail" maxlength="50" value="[[!+fi.gbemail:htmlent]]" />
<span class="error">[[+fi.error.gbemail]]</span><div class="smallfont">
<input type="hidden" name="gbemailshow[]" value="0" />
<input type="checkbox" name="gbemailshow[]" id="gbemailshow" value="1" [[!+fi.gbemailshow:FormItIsChecked=`1`]] /> eMail veröffentlichen? <br /><br /></div>
</th></tr>

<tr><th align="left"><label for="gbvote">Bewertung:</label></th>
<th align="left">
<select tabindex="0" name="gbvote" id="gbvote">
<option value="[[+fi.gbvote]]">Bitte bewerten</option>
<option value="5">sehr gut</option>
<option value="4">gut</option>
<option value="3">geht so</option>
<option value="2">schlecht</option>
<option value="1">sehr schlecht</option>
</select>
<span class="error">[[+fi.error.gbvote]]</span>
</th></tr>

<tr><th align="left" valign="top" ></th>
<th align="left" class="smallfont">Erlaubter BBCode: xxxxxxxx
</th></tr>

<tr><th align="left" valign="top" ><label for="gbtext">Kommentar:</label></th>
<th align="left"><textarea name="gbtext" id="gbtext" cols="50" rows="6">[![+fi.gbtext:htmlent]]</textarea>
<span class="error">[[+fi.error.gbtext]]</span>
</th></tr>

<tr><th align="left" valign="top" ></th>
<th align="left"> [[$guestbookSmilies]]
</th></tr>

<tr>
<th align="left" valign="top"><label>[[!+fi.op1]] [[!+fi.operator:is=`-`:then=`minus`:else=`plus`]] [[!+fi.op2]]?</label></th>
<th align="left">
<input type="text" id="gbmath" maxlength="5" name="math:required" value="[[!+fi.math]]" />
<input type="hidden" name="op1" value="[[!+fi.op1]]" />
<input type="hidden" name="op2" value="[[!+fi.op2]]" />
<input type="hidden" name="operator" value="[[!+fi.operator]]" />
<span class="error">[[+fi.error.math]]</span>
<div class="smallfont">Spamschutz</div>
</th></tr>

<tr><th align="left"></th>
<th align="left"><br />
<div class="form-buttons">
<input type="submit" value="Eintrag senden [[+fi.id]]" />
</div>
</th></tr>

</table>
</form>
emailTo + redirectTo anpassen!


#### Resources erstellen ####

14) V11.09.1 - 'Gästebuch Eintrag Danke'
(siehe chunk 'guestbookForm': redirectTo)
Vielen Dank
für Deinen
Gästebucheintrag
'Hide From Menus' aktivieren und im Page Settings das 'Searchable' deaktivieren.

15) V11.09.3 - 'Gästebuch'
Herzlich Willkommen in unserem Gästebuch.<br />
[[!$guestbookForm]]
[[!guestbookQty?active=`1`]] Kommentare
[[!$guestbookEntry]]


#### optional ####

16) V11.10.2 - deaktivierte Kommentare endgültig löschen
Um deaktivierte Kommentare endgültig zu löschen könnt ihr dieses snippet erstellen ('guestbookEntryDel'):
<?php
$table 
'modx_custom_guestbook';
$where 'gbactive=0';
$count $modx->exec("DELETE FROM $table WHERE $where");

return 
$count' Kommentare wurden gelöscht.';

dann 2 Resources (versteckt + nicht veröffentlicht!) erstellen:

res1
<a href="[[~IDvonRes2]]">Wirklich [[!guestbookQty?active=`0`]] Kommentar(e) löschen?</a>res2
[[!+modx.user.id:eq=`1`:then=`[[!guestbookEntryDel]]`:else=``]]
PS: Wer will kann sich per getPage und Rowboat in res1 die deaktivierten Anzeigen lassen. Ungefähr so:
&where=`[[!+modx.user.id:eq=`1`:then=`{"gbactive:=":"0"}`:else=`{"gbactive:=":"9"}`]]`
Ich rufe die res1 im chunk tplGuestbookEntry auf. Ersetze:
[[+gbactive:eq=`1`:then=``:else=`<font color=#990000>Kommentar ist deaktiviert!</font>`]] mit:[[+gbactive:eq=`1`:then=``:else=`<font color=#990000>Kommentar ist deaktiviert || <a href="[[~IDres1]]">alle deaktivierte löschen!</a></font>`]]
17) V11.10.7 - CSS Zeilen für das Seitentemplate (Beispiel)
/* Guestbook */
#gbtext, #gbname, #gbhome, #gbemail, #gbmath { padding: 2px; clear: right }
.smilie { vertical-align: sub }
.smilies { margin: 5px 2px 40px 0px }
.smilieSelect { float: left; margin-right: 5px }
.guestbook_top { background-color: #123; height: 26px; color: #fff; margin-right: 10px; padding: 2px 5px 2px 5px }
.guestbook_big { float: left; font-size: 16px; font-weight: bold; margin-right: 10px; padding-top: 1px}
.guestbook_small { float: left; font-size: 10px; font-weight: bold; padding: 6px 0 0 0}
.guestbook_content { margin: 0 10px 20px 0; padding: 5px; clear: right; background: #fff; border-width: 1px; border-style: solid; border-color: #123 }
.guestbook_content_b { margin: 0 10px 20px 0; padding: 5px; clear: right; background: #fafafa; border-width: 1px; border-style: solid; border-color: #123 }
.guestbook_content .gbemail, .guestbook_content_b .gbemail { float: right; margin: 0 5px 0 40px; color: green; font-size: 10px }
.guestbook_vote { float: right; padding: 5px 5px 5px }
.guestbook_vote .vote { padding: 0px 1px 0px; width: 16px; height: 16px; }
.pageList {
display:block;
background-color: rgb(255,255,255);
width: auto;
height: auto;
margin: 2px 10px 0 0;
padding: 2px 10px 2px 0;
border-color: #123;
border-width: 2px;
border-style: outset;
text-align: center;
list-style: none;
}
.pageList li {
display: inline;
margin: 2px 10px 2px 0;
padding: 0;
}
.pageList a:hover, .pageList .active {
background: #123;
color: #FFFFFF;
}


#### Wenn das Gästebuch läuft und ihr alles getestet habt ####

Damit kein unbefugter nachträglich ein Kommentar ändert, solltet ihr das db2formit-snippet wie folgt ändern. Ersetze:
$hook->setValues($dataobject->toArray());mit:
# only if
# if ($modx->user->isMember(array('Administrator'))){
# or
if ($modx->user->get('id') == '1'){
    $hook->setValues($dataobject->toArray());
}


Bei mir rennt das Gästebuch xhtm-valide und es gibt keine Meldung im Error-Log. Natürlich alles ohne Gewähr!

VIEL ERFOLG!   :bounce:


Jo

#1
Gravatar ist ein Bild, das euch überall begleitet, von Seite zu Seite. Es erscheint neben dem Namen, wenn ihr Kommentare oder Artikel in Blogs schreibt. Also warum nicht einfach per Snippet ein getGravatar einbauen?

Hier das Snippet:
<?php
// Example of use
// [[!getGravatar? &email=`[[+gbemail:htmlent]]` &size=`40` &default=`[[++site_url]]/assets/content/images/noGravatar.jpg`]]
// or
// [[!getGravatar? &email=`[[+gbemail:htmlent]]` &size=`40` &default=``]]

$grav_url="https://www.gravatar.com/avatar/".md5(strtolower(trim($email)))."?d=".urlencode($default)."&amp;s=".$size;

return 
'<img src="'.$grav_url.'" alt="" title="Gravatar" />';