Jump to content

FieldtypeComments - how to customize


modifiedcontent
 Share

Recommended Posts

Render Comments with options is this:

Spoiler

    echo $page->comments->render(array(
    'headline' => '<h2>Comments</h2>',
    'commentHeader' => 'Posted by {cite} on {created}',
    'dateFormat' => 'l, F jS Y g:i a',
    'encoding' => 'UTF-8',
    'admin' => false, // shows unapproved comments if true
    ));

 

{cite} inserts the username. I want to display the commenter's Firstname Lastname instead - I have a field for that called 'fullname'. Where is {cite} defined? How can I change it?

This should be functionally the same (?) and would give me control to define and change lots of stuff, including "cite" and adding profile picture etc.:

Spoiler

foreach($page->comments as $comment) {
    if($comment->status < 1) continue; // skip unapproved or spam comments
    $commenter = $users->get(htmlentities($comment->cite));
    $cite = $commenter->fullname; // make sure output is entity encoded
    $text = htmlentities($comment->text);
    $date = date('l, F jS Y g:i a', $comment->created); // format the date
    echo "<p><strong>Posted by $cite on $date</strong><br />$text</p>";
}

 

But with this, the 'Reply' link is missing from the comment. How can I add that 'Reply' link and make sure those replies-to-comments or replies-to-replies-to-comments are stored in the proper way?

Or will that get me into a hopeless mess and should I just stick to the render method with a simple way to make {cite} render the full name instead of a username?

edit: I see the comments just end up on the same level anyway, with either method - Comment1 Comment2 Comment3. 'Reply Depth' is set to '2' in the Comments field settings. Does threaded comments not work?

 

Link to comment
Share on other sites

@modifiedcontent Not quite your question but in your template, where you are rendering the comments entry form, you can do this instead. This should set up the correct value for the cite field for new entries...

<?php
echo $page->comments->renderForm([
    'presets' => [
        'cite' => wire()->sanitizer->entities($user->fullname),
    ],
]);

For existing entries, I think you can iterate the comments and then set the cite attribute to the value you want.

  • Like 1
Link to comment
Share on other sites

Thanks @netcarver. So 'presets' is an array somewhere that contains 'cite' and other things?

Username is OK for the comment form, because comments will only be open to logged-in members. The module enters the logged-in users name and email address, so I can just hide those fields - or is there a way not to require them at all?

The updated second method in my original post also produces the result I want, minus the Reply link. That Reply link doesn't seem to do anything special anyway; comments are all created on the same level, Comment1, Comment2, Comment3. 

I am now mostly puzzled by how to make threaded comments work - 'Reply Depth', reply-to-comment. 

Edit: Another problem; where does the module get the name + email address that are prefilled in the comment form? They are not consistently the name + email from the logged-in user as I assumed.

When I test logged-in with different accounts, only the name + email of the first account I tested with show up in the comment form. Is there a way to just let the comment form take the name + email, or just ID, of the logged-in user? 

Edit 2: Javascript sets a persistant cookie for whoever posts a comment? I guess I should replace that with Javascript that enters the logged-in user's name+email then. Or is there any way via PHP without editing the module core files?

 

Link to comment
Share on other sites

Hi @modifiedcontent

It's really easy, and I suggest you to copy the MyCommentForm.php file from /wire/fieltype/fieldtypeComments, put it in your template directory then rename it to _MyCommentForm.php and modify this file to your need - for you it's the renderFormThread() function which is interesting and there to be tweaked.

Then in a template, you put the following code :

include("./_MyCommentForm.php");

CommentStars::setDefault('star', '<i class="fa fa-star"></i>'); //<= star item using fontawesome icon
		
$options = array(...); // options of your form, check `myCommentForm.php`
                                                                        
$myCommentsForm = new MyCommentForm($page, $page->comments, $options);                                                                       
echo $myCommentsForm->render();

 

You have also a good function to start here to control all the comments markup :

Spoiler


// Get comments threaded
    // use in template file: echo getComments($page->comments, $page);
function getComments($comments, $page, $parentID = 0, $reply = true, $child = null) {    
	$out = "";
	foreach($comments as $comment)
	{
		if($comment->parent_id == $parentID)
		{
			$reply = ($reply == true) ? "<a class='CommentActionReply comment-reply-link' data-comment-id='{$comment->id}' href='#Comment{$comment->id}'>". __('répondre') ."</a>" : "";
			if($comment->status < 1) continue;
			$cite = htmlentities($comment->cite);
			$text = htmlentities($comment->text);
			$userID = $comment->created_users_id;
			$u = wire("pages")->get($userID);
            $name = ($u->displayName) ? $u->displayName : $u->name;
            $date = date('m/d/y g:ia', $comment->created);
            $stars = ($comment->stars > 0) ? $comment->renderStars() : '';
            $emailHash = md5(strtolower(trim($comment->email)));
            //$http = new WireHttp();
            $imgGravatarUrl = false; "https://www.gravatar.com/avatar/". $emailHash ."/?r=g&s=85&r=g&d=404";
            //$response = $http->get($imgGravatarUrl);
            //if(strlen($response) < 14) $imgGravatarUrl = false;
            $avatar = ($u->avatar) ? $u->avatar->size(75, 75)->url : (($imgGravatarUrl) ? $imgGravatarUrl : wire('config')->urls->templates.'img/placeholder-avatar2.svg'); // 'http://placeskull.com/78/78/'. $colors[rand(0, 2)] .'/'. rand(1, 45); // wire('config')->urls->templates.'img/placeholder-avatar.svg';
            $out .= "<div id='comment-{$comment->id}' class='card {$child}' style='width: 100%;'>
                        <div class='card-header d-flex align-items-center px-0'>
                            <img class='avatar mr-3' src='{$avatar}' alt='avatar-{$cite}' style='border-radius: 50%;'>
                                <span class='card-title m-0 p-0'>{$cite}</span>
                                <small class='card-subtitle text-muted m-0 ml-2 p-0'><time datetime='comment_date'>". wireRelativeTimeStr($date, true) ."</time></small>
                                <span class='stars pull-right'>{$stars}</span>
                        </div>
                        <div class='card-body px-0 pt-0'>
                            <p class='card-text'>". nl2br($text) ."</p>
                    ";
            // nest child
            $out .= "   </div>";
            $out .=     getComments($comments, $page, $comment->id, false, "child-comment");
            $out .= "</div>";
            
		}
	}
	return $out;
}

> Credit :   @fbg13

An screenshot of what can be done (sorry for the screencast, I can't resize it.)

  • Like 2
Link to comment
Share on other sites

I am currently working on custom comment form output and custom comment list output. I copied `CommentForm.php` as `CommentFormUikit.php` and copied `CommentList.php` as `CommentListUikit.php`.

Renamed class names on these and extend base classes  files and removed not used codes and modified needed sections.

When i want to use my custom outputs :

<?php
// include customization classes
include __DIR__ . '/CommentListUikit.php';
include __DIR__ . '/CommentFormUikit.php';

// custom list output
echo $page->comments->render(['className' => 'CommentListUikit']);
// custom form output
echo $page->comments->renderForm(['className' => 'CommentFormUikit']);
?>

CommentListUikit.php

<?php

namespace ProcessWire;

class CommentListUikit extends CommentList
{
// do your customizations
}

CommentFormUikit.php

<?php

namespace ProcessWire;

class CommentFormUikit extends CommentForm
{
// do your customizations
}

Example output for uikit 3 frontend framework, still working on it, specially writing a javascript for comment form

425478768_EkranResmi2020-12-2218_26_31.thumb.png.3a57f88e62a1c95ade560619b57244f1.png

  • Like 1
Link to comment
Share on other sites

Thanks @ukyo. I'll try this in my next steps. 

In the meantime I have found out why my threaded comments - 'Reply Depth' etc. - didn't work. Threaded comments relies on jQuery in comments.min.js in wire/modules/Fieldtype/FieldtypeComments/

I load jQuery in my head with these lines:

Spoiler

<script type='text/javascript' src='https://code.jquery.com/jquery-3.5.1.min.js'></script>
<script type='text/javascript' src='https://code.jquery.com/jquery-migrate-3.3.1.min.js'></script>

 

I think Processwire has jQuery "built in", but have always been confused how to use it. When I just remove my lines from head, all my jQuery breaks. If I already have jQuery in my site, why doesn't the jQuery in the module work? Does Processwire require a specific version of jQuery?

The module's jQuery works fine when I copy it from comments.js to my template and replace jQuery with another var:

Spoiler

var jWhatever = jQuery.noConflict();

function CommentActionReplyClick() {
	
	var $this = jWhatever(this);
	var $item = $this.closest('.CommentListItem');
	...etc.

 

I have also removed all the cookie stuff from the module's javascript. I think without it the comment form name+email fields are prefilled with data from the logged-in user, which is what I needed.

Is there a way to add the Reply link with the foreach($page->comments as $comment) method? If not, I'll figure something out with @netcarver, @flydev 👊🏻 or @ukyo's suggestions - thanks!

 

Link to comment
Share on other sites

I can't figure this out. I have added a comment.php file in my templates/forms folder with the following:

Spoiler

<?php namespace ProcessWire;

class CustomComment extends CommentForm
{
	public function getFormMarkup() {
        echo '<p>Does this show up anywhere?</p>';
	}

}

?>

 

With this in the page's template:

Spoiler

    include_once $config->paths->templates . 'forms/comment.php';

	// comments form with all options specified (these are the defaults)
    echo $page->comments->renderForm(array(
    'className' => 'CustomComment',
    'headline' => '<h2>Share your thoughts</h2>',
    'successMessage' => '<p class=success>Thank you for your comment.</p>',
    'errorMessage' => '<p class=error>Your submission was not saved due to one or more errors. Please check that you have completed all fields before submitting again.</p>',
    'processInput' => true,
	...etc.

 

This doesn't do anything - the echo from comment.php doesn't show up anywhere. I am not an experienced/full-time PHP programmer. It is not obvious to me what is going on in these scripts. 

@ukyo, what does '// do your customizations ' look like? Could you or anyone else give a basic example?

Should I copy entire functions from CommentForm.php or CommentFormCustom.php (?), change a few things within those functions and then those customizations will replace the functions in /wire? Should I rename the functions?

Or does whatever I put in '// do your customizations ' run after CommentForm.php in /wire - adding not replacing?

I also tried to follow the instructions in CommentFormCustom.php, but did not understand any of it. I've copy/pasted different parts and functions from that file into my custom comment.php, but could not get a result with anything.

Continuing with this tomorrow... Any hints very much appreciated.

 

Link to comment
Share on other sites

@modifiedcontent Can you put these files under a folder something like : templates/extends or site/src. After do that can you add this path to wire classLoader.

You can do this on ready.php file or you can try it before apply your customizations (didn't try that).

<?php
// ready.php example

$template = $page->template->name;

if (in_array($template, ['template-with-comment-field'])) {
  wire('classLoader')->addNamespace('ProcessWire', wire('config')->paths->templates . '/extends');
  // or
  wire('classLoader')->addNamespace('ProcessWire', wire('config')->paths->site . '/src');
}

or (didn't tested)

<?php
wire('classLoader')->addNamespace('ProcessWire', wire('config')->paths->templates . '/extends');
// or
wire('classLoader')->addNamespace('ProcessWire', wire('config')->paths->site . '/src');

$page->comments->render(['className' => 'CommentListCustom']);
$page->comments->renderForm(['className' => 'CommentFormCustom']);

 

Link to comment
Share on other sites

Thanks @ukyo, but what is that supposed to do? I plan to have my custom files in templates/forms. What difference would putting them in templates/extend or site/src make? Why site/src - is adding folders outside templates a good idea?

Those classLoader lines apply to the entire folder, not a specific file?

Are the general principles how to work with classes and customize modules in Processwire explained anywhere? I haven't been able to find it. 

This produces a result:

Spoiler

include $config->paths->templates . 'inc/CommentListCustom.php';

echo $page->comments->render(array(
  'className' => 'CommentListCustom',
  'headline' => '<h2>Comments</h2>',
  'commentHeader' => 'Posted by {cite} on {created}',
  'dateFormat' => 'l, F jS Y g:i a',
  'encoding' => 'UTF-8',
  'admin' => false, // shows unapproved comments if true
));

 

CommentListCustom.php copied from the wire module into my templates/inc folder. The custom file is now used to display the comments. I can now make edits in that file to somehow change {cite} to the commenter's full name. 

Wtf is {cite} anyway? It's not a PHP variable. How is it defined? How can I redefine it? I can't do something like {cite} = $users->get({cite})->fullname; What syntax should I use? What rules apply to these {something} "thingies"?

Why does this produce Fatal Error  Uncaught Error: Call to a member function get() on null?

Spoiler

$cite = $comment->getFormatted('cite');
$cite = $users->get($cite)->fullname;

 

This seems to work though:

Spoiler

$cite = $comment->getFormatted('cite');
$cite = users()->get($cite)->fullname;

 

 

For the form it works the same of course:

Spoiler

include $config->paths->templates . 'forms/CommentFormCustom.php';

echo $page->comments->renderForm(array(
'className' => 'CommentFormCustom',
'headline' => '<h2>Share your thoughts</h2>',
'successMessage' => '<p class=success>Thank you for your comment.</p>',
...

 

Then make edits in CommentFormCustom.php as required. In my case I added 'hidden' to the cite and email input fields, so logged-in users only get a text field, don't have to enter any other info - the module enters logged-in user name and email in the hidden fields if you remove/turn off all the cookie stuff.

Two next issues to solve:

1. Is the upvote/downvote system cookie-based? What would it take to turn that into logged-in user ID-based? Or is that the default if I turn off cookies/remove cookie javascript?

2. Users will expect a way to delete and edit their comments. Has anyone done that? Suggestions welcome.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...