Jump to content

Best way to feature comments


alan
 Share

Recommended Posts

I've written the chunk of code below to retrieve then display the three most recent comments from blogpost Pages.

I am worried that in places I may be failing to use the power of the PW API (overusing generic PHP instead). Do you see a 'tighter' / more powerful PW-API-way of doing this?

Also I don't see how to retrieve the URL of the blogpost that a comments belongs to, in pseudo code I feel I want to do:

$comment->parent()->url;

Here's the code:

$blogposts = $pages->get( "/blog/" )->children;
$comments = array();
foreach($blogposts as $blogpost) {

foreach($blogpost->comment as $comment) {
	if($comment->isApproved()) {
		array_push($comments, $comment); // Build an array of comments
	}
}
}
if($comments) {
$out = "<h2>Last three blog comments</h2>";
$out .= "<dl>";
arsort($comments);
$num_comments = 0;
foreach($comments as $comment) {
	$cite = htmlentities($comment->cite);
	$text = htmlentities($comment->text);
	$date = date("j M 'y ", $comment->created);
	$out .= "<dt>{$date}</dt>";
	$out .= "<dd>{$cite}</dd>";
	$out .= "<dd>{$text}</dd>";
	$num_comments++;
	if($num_comments == 3) break;
}
$out .= "</dl>";
echo $out;

} else {
echo "<p>No comments.</p>";
}

Any comments gratefully received, cheers, -Alan

Link to comment
Share on other sites

I did not test it, but I looked around in Ryans BlogProfile and saw some interesting methods in BlogTools.php:

/**
 * Find comments from the given selector string
 *
 * @param string $selector
 * @return CommentArray
 *
 */
public function findComments($selector) {
 $comments = FieldtypeComments::findComments($this->commentsField, $selector);
 foreach($comments as $comment) {
  if(!$comment->page->viewable()) $comments->remove($comment);
 }
 return $comments;
}
/**
 * Find $limit recent comments
 *
 * @param int $limit Number of recent comments to find
 * @param int $start Where to start, like 0 (default: null = automatic, based on page number)
 * @param bool $admin Include non-approved and spam comments? (default: null = determine automatically)
 * @return CommentArray
 *
 */
public function findRecentComments($limit = 3, $start = null, $admin = null) {
 $limit = (int) $limit;
 $_limit = is_null($start) ? $limit : $limit+1;
 $out = '';
 $pageNum = $this->input->pageNum;
 // auto-determine $start if not specified
 if(is_null($start)) {
  if($pageNum > 1) $start = $pageNum * $limit;
else $start = 0;
 }
 // we show pending and spam comments when page is editable
 if(is_null($admin)) $admin = $this->page->editable();
 // build selector to locate comments
 $selector = "limit=$_limit, start=$start, sort=-created, ";
 if($admin) $selector .= "status>=" . Comment::statusSpam . ", ";
  else $selector .= "status>=" . Comment::statusApproved . ", ";
 // find the comments we want to output
 $comments = $this->findComments($selector);
 return $comments;
}

I think FieldtypeComments::findComments is a new addition to PW, so you might need the lastet version from github.

It looks like instead of

$comment->parent()->url;

you can use

$comment->page;
  • Like 2
Link to comment
Share on other sites

Thanks @interrobang, I've not even seen that resource :D

For the dev work I'm doing here I keep up-to-date with github so I'll go test. Cheers!

Update:

$comment->page;

appears to be showing the ID of the page where the comment list is being viewed rather than the pages the comments belonged to. But thanks this looks promising.

Edited by alan
Link to comment
Share on other sites

Alan the $comment->page will only point to the actual comment's page if the comment was retrieved with FieldtypeComments::findComments. Part of what that function does is populate the appropriate $page variable to all the comments it finds. However, you can still get it even if you don't have the latest PW or aren't using that findComments function:

$page = wire('pages')->get($comment->pages_id); 
  • Like 1
Link to comment
Share on other sites

Thanks Ryan, I was off in the kitchen making Tea and suddenly did a mental forehead-slap when I realized I probably needed to use the fn rather than my own code. Thanks also for extremely useful reminder how the API can be used, pearls of wisdom I keep pumping into pinboard.in :)

Link to comment
Share on other sites

Drat, I am managing to fail to solve this even with the help. I modified my first foreach to include the $page = wire(... line:

foreach( $blogposts as $blogpost ) {

foreach($blogpost->comment as $comment) {
	if($comment->isApproved()) {
		array_push($comments, $comment); // Build an array of comments
		$page = wire('pages')->get($comment->pages_id);
	}
}
}

...and then later to check I am seeing the ID of each comments parent page I added the $comment_parent code:

foreach($comments as $comment) {
$cite = htmlentities($comment->cite);
$text = htmlentities($comment->text);
$date = date("j M 'y ", $comment->created);
$comment_parent_id = $comment->page;
$out .= "<dt>{$date}</dt>";
$out .= "<dd>{$cite}</dd>";
$out .= "<dd>{$text}</dd>";
$out .= "<dd>{$comment_parent_id}</dd>";
$num_comments++;
if($num_comments == 3) break;
}

But the ID returned is the same each time and is the ID of the page where the list is being shown—if I understood you rightly Ryan the edit

$page = wire('pages')->get($comment->pages_id);

in the first foreach should have stopped that—did I do something wrong?

PS: If the use of FieldtypeComments::findComments is documented I'll try that also, I tried adding and using these functions but got errors and don't want to cloud this post so I'll ignore for now.

Thanks in advance for any more pointers.

Link to comment
Share on other sites

I think you have to store the $page in your $comment. $comment->page should now be the actual page, and not only the page_id.

foreach( $blogposts as $blogpost ) {
foreach($blogpost->comment as $comment) {
	if($comment->isApproved()) {

		$page = $pages->get($comment->pages_id);
		$comment->page = $page;
           array_push($comments, $comment); // Build an array of comments

	}
}
}
Link to comment
Share on other sites

Thanks @interrobang. I tried it but it seems to produce no output (no errors but no output). This is what I had:

foreach( $blogposts as $blogpost ) {

   foreach($blogpost->comment as $comment) {
    if($comment->isApproved()) {
	    array_push($comments, $comment); // Build an array of comments
	    $page = $pages->get($comment->pages_id);
	    $comment->page = $page;
	    // $page = wire('pages')->get($comment->pages_id); // tried with this line in and out but same result
    }
   }
}

PS: I'm using echo $comment->page; to see the ID of each comments page.

Link to comment
Share on other sites

I think you have to change the line order like in my example. Otherwise the $comment you push into your array doesnt't have the page variable set. Maybe there are other and better ways to do this, I am still new to php.

Btw, echo $comment->page shows the ID, but nevertheless $comment->page should be the real page, so things like $comment->page->url should work.

Link to comment
Share on other sites

Thanks again @interrobang for your patience, I should have spotted that the line order mattered, but I'm not so good at PHP ;)

But sadly I've changed the order to match your order and it still produces nothing.

Link to comment
Share on other sites

Sorry, I have no idea whats wrong. But maybe this works better, instead of storing the $page in the $comment:

foreach($comments as $comment) {
	$cite = htmlentities($comment->cite);
	$text = htmlentities($comment->text);
	$date = date("j M 'y ", $comment->created);

	$comment_parent_id = $comment->pages_id; // Get the page_id

	$out .= "<dt>{$date}</dt>";
	$out .= "<dd>{$cite}</dd>";
	$out .= "<dd>{$text}</dd>";
	$out .= "<dd>{$comment_parent_id}</dd>";
	$num_comments++;
	if($num_comments == 3) break;
}
Link to comment
Share on other sites

Alan, maybe this is not the best way of doing it, but at least it works :)

$blogposts = $pages->get( "/blog/" )->children;
$comments = array();

foreach( $blogposts as $blogpost ) {
foreach ($blogpost->article_comments as $comment) {
	if($comment->isApproved()) {
		array_push($comments, array("comment"=>$comment, "post"=>$blogpost));
	}
}

}
foreach ($comments as $c) {
echo $c["comment"]->text . "<br>";
echo $c["post"]->url . "<br>";
}
Edited by diogo
Link to comment
Share on other sites

Thanks again for trying so much to help me @interrobang, I can't seem to find the answer this way either. And thanks @diogo, I wondered about a two dimension array but I was already getting PHP-lost ;) so I bailed on that. Your code does indeed work, thanks, and I'll edit my code to use it.

Thanks everyone, I'll post back the final version.

I'd love to know where/when the use of FieldtypeComments::findComments is documented for future projects though in case anyone finds this thread and knows.

Cheers!

Link to comment
Share on other sites

This is the code I ended up using, thanks again to interrobang, diogo and Ryan:


$blogposts = $pages->get( "/blog/" )->children;

$comments = array();

foreach( $blogposts as $blogpost ) {

   foreach($blogpost->comment as $comment) {
       if($comment->isApproved()) {

           array_push($comments, array("comment"=>$comment, "post"=>$blogpost));

       }
   }
}

if($comments) {
   $out = "<h2>Last three blog comments</h2>";
   $out .= "<dl>";

   arsort($comments);

   $num_comments = 0;

   foreach($comments as $comment) {
       $cite = htmlentities($comment["comment"]->cite);
       $text = htmlentities($comment["comment"]->text);
       $date = date("j M 'y ", $comment["comment"]->created);
       $comment_parent_url = $comment["post"]->url . "#Comment" . $comment["comment"];

       $out .= "<dt><a href='{$comment_parent_url}'>{$date}</a></dt>";
       $out .= "<dd>{$cite}</dd>";
       $out .= "<dd>{$text}</dd>";

       $num_comments++;
       if($num_comments == 3) break;
   }

   $out .= "</dl>";
   echo $out;

} else {
   echo "<p>No comments.</p>";
}

Brilliant. Thanks guys! :D

Updated 2012-06-14-1329 to use named arrays, much better, thanks to diogo for suggesting this :D

Edited by alan
  • Like 1
Link to comment
Share on other sites

  • 9 months later...

Thank you, exactly what I was looking for. Only problem I encountered is on 4th line

foreach($blogpost->comment as $comment) {

where it should be $blogpost->comments (as that is the name of field I am using). Great example.

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...