Jump to content
nfil

Store and output visited pages with $session or $_SESSION

Recommended Posts

Hello, I'am trying to store the 4 latest visited pages, using sessions and output the first image and title from those pages to the user. 

Any help is appreciated! 

Tried $session and PW api variables but  couldn't get this to work.

This is working but only to get the urls to the page:

        session_start();
        // URL array
        if (empty($_SESSION['pageurls'])) {
        $_SESSION['pageurls'] = array_fill(0,4,'');
        }

        function trackPage($url) {
        array_unshift($_SESSION['pageurls'],$url);
        array_pop($_SESSION['pageurls']);
        }
        trackPage($_SERVER['REQUEST_URI']);

        foreach ($_SESSION['pageurls'] as $page) {
        echo "<a href='{$page}'>" . $page . "</a>" . "<br/>";
        };

Share this post


Link to post
Share on other sites

Still somewhat ugly, but I'd probably go with something like this:

$session->history = is_array($session->history) ? array_slice(array_merge(array($page->id), $session->history), 0, 4) : array($page->id);

After that you can output stored data like this:

foreach ($session->history as $page_id) {
    $p = $pages->get($page_id);
    echo "<a href='{$p->url}'>{$p->title}</a><br />";
}
  • Like 2

Share this post


Link to post
Share on other sites

Thanks for the help teppo! Tried to output pages from a specific PW template but it outputs all the pages, maybe there is something wrong with this:

<?php 
    $session->history = is_array($session->history) ? array_slice(array_merge(array($page->id), $session->history), 0, 4) : array($page->id);
    foreach ($session->history as $page_id) {
    $p = $pages->get($page_id)->find("template=basic-page");
    echo "<a href='{$p->url}'>{$p->title}</a><br />";
}
?>

Share this post


Link to post
Share on other sites

@nfil: $pages->get($page_id) returns one page and you can't "find" from one page :)

Try adding new row after $p = $pages->get($pages_id) with something like this: if ($p->template != "basic-page") continue;

  • Like 1

Share this post


Link to post
Share on other sites

@nfil: $pages->get($page_id) returns one page and you can't "find" from one page :)

Try adding new row after $p = $pages->get($pages_id) with something like this: if ($p->template != "basic-page") continue;

oops, You are right!  

I added the first image from those pages too.

    $resized_imageWidth = 120;
    $resized_imageHeight = 0;
    $session->history = is_array($session->history) ? array_slice(array_merge(array($page->id), $session->history), 0, 4) : array($page->id);
    foreach ($session->history as $page_id) {
    $p = $pages->get($page_id);
    if ($p->template != "basic-page") continue;
    echo "<img src='{$p->images->first->url}' width='{$resized_imageWidth}' heigth='{$resized_imageHeight}'>" . "<a href='{$p->url}'>{$p->title}</a><br />";
}

Thanks again teppo for all the help!

  • Like 2

Share this post


Link to post
Share on other sites

I'm glad I could help.. and this actually looks quite interesting, might have use for similar snippet somewhere :)

Share this post


Link to post
Share on other sites

@nfil: $pages->get($page_id) returns one page and you can't "find" from one page :)

Try adding new row after $p = $pages->get($pages_id) with something like this: if ($p->template != "basic-page") continue;

Hey teppo,

Possibly I am missing something so wanted to clarify with you:

I often chain get and find for finding all the children/grandchildren of a particular single parent. Compare this to "->get->children(selector)" which of course only returns first level children.

I know that it doesn't work for what @nfil is after, but wanted to clarify how they can actually work together for those that are new to PW.

Also, curious what you think of:

$p = $pages->get($page_id);
if ($p->template != "basic-page") continue;
echo ....

vs

$ps = $pages->find("id=$page_id, template=basic-page");

foreach($ps as $p){
    echo ......;
}

The first option (your suggestion) is likely more efficient, but just wanted to point out the second option to others and make the note that, in this case, you need a find rather than a get, because with a get, the id= selector overrides anything else after it.

  • Like 1

Share this post


Link to post
Share on other sites

Possibly I am missing something so wanted to clarify with you:

I often chain get and find for finding all the children/grandchildren of a particular single parent. Compare this to "->get->children(selector)" which of course only returns first level children.

I know that it doesn't work for what @nfil is after, but wanted to clarify how they can actually work together for those that are new to PW.

Very good clarification. My explanation earlier was way too vague :)

What I meant was that you can't find from a single page, i.e. use find like a filter for one page. You can find from children of given page, though: $pages->get(123)->find("template=basic-page") would return children of page 123 with template "basic-page" recursively, while $pages->get(123)->children("template=basic-page") would only return matching direct children.

Also, curious what you think of:

$p = $pages->get($page_id);
if ($p->template != "basic-page") continue;
echo ....

vs

$ps = $pages->find("id=$page_id, template=basic-page");

foreach($ps as $p){
    echo ......;
}

The first option (your suggestion) is likely more efficient, but just wanted to point out the second option to others and make the note that, in this case, you need a find rather than a get, because with a get, the id= selector overrides anything else after it.

That's another way to do it. With find() you could also do something like this to, perhaps, simplify it a bit:

$p = $pages->find("id=$page_id, template=basic-page")->first();
if (!$p) continue;
echo ....

Quick look at the SQL generated by get() vs. find():

SELECT id, templates_id FROM pages WHERE id=1001

SELECT pages.id,pages.parent_id,pages.templates_id FROM `pages` WHERE (pages.id=1001) AND (pages.templates_id=29) AND (pages.status<1024) GROUP BY pages.id /* Selector id=1001, template=basic-page, status<1024 */

I would assume first one (get) to be slightly faster, but this is micro-optimisation at it's best and doesn't usually matter at all in real world use. I prefer get() for getting single pages as it's the straightforward way :)

  • Like 2

Share this post


Link to post
Share on other sites

Another clarification. (I seem to need these a lot these days.)

As is (probably) made quite obvious by the SQL statements above, get() with a Page ID doesn't care about the status of the page at all. It returns hidden and unpublished pages too, making it somewhat equal to find() with "include=all".

This is important to keep in mind in case that those pages you're "getting" could've been unpublished in the meantime; if that's possible, you really should add another check for $p->viewable() before displaying content. With this addition, nfil's final code could look like this:

$resized_imageWidth = 120;
$resized_imageHeight = 0;
$session->history = is_array($session->history) ? array_slice(array_merge(array($page->id), $session->history), 0, 4) : array($page->id);
foreach ($session->history as $page_id) {
    $p = $pages->get($page_id);
    if (!$p->viewable() || $p->template != "basic-page") continue;
    echo "<img src='{$p->images->first->url}' width='{$resized_imageWidth}' height='{$resized_imageHeight}'>" . "<a href='{$p->url}'>{$p->title}</a><br />";
}
  • Like 2

Share this post


Link to post
Share on other sites

Since we're in a clarifying mood :), the catch with $p->viewable is that there must be a template php file for the page, so this isn't a complete fix for using ->get and making sure it is not hidden/unpublished.

Maybe this instead of viewable?

!$p->status>=1024 

I know it won't matter for this script because we are looping through pages that were at some point viewable (even if the status was changed in the meantime), so they must have had a template file at some point and likely still do.

Sorry, I know I am getting too pedantic and off-topic now - time to sleep :)

  • Like 2

Share this post


Link to post
Share on other sites

Since we're in a clarifying mood :), the catch with $p->viewable is that there must be a template php file for the page, so this isn't a complete fix for using ->get and making sure it is not hidden/unpublished.

in this case you only have to change the order in this line:

    if (!$p->viewable() || $p->template != "basic-page" ) continue;  // old
    if ($p->template != "basic-page" || !$p->viewable()) continue;  // new

PHP will return after the first conditional if it does not match and in these cases the code of the second condition (or any following) never get executed. Changing this, Teppos code is a complete fix. :)

  • Like 1

Share this post


Link to post
Share on other sites

Good clarifications from both of you :)

This is getting a bit out of hand, but one more addition: in current code image isn't actually resized -- it's just forced to specific dimensions with HTML attributes. This could be intentional, but I'm wondering if this might make even more sense here: 

...
echo "<img src='{$p->images->first->size($resized_imageWidth, $resized_imageHeight)->url}' width='{$resized_imageWidth}' height='{$resized_imageHeight}'>" . "<a href='{$p->url}'>{$p->title}</a><br />";
...

This way end-user doesn't have to download excessively large images, if what you really want here is a thumb. It should also be noted that simply defining width and height with HTML attributes forces image to those exact dimensions without considering actual aspect ratio, which can easily result in distorted images.

(More about various options that size() accepts here.)

  • Like 2

Share this post


Link to post
Share on other sites

I often chain get and find for finding all the children/grandchildren of a particular single parent. Compare this to "->get->children(selector)" which of course only returns first level children.

Another way to return all children including grand-children is to use has_parent:

$all_children = $pages->find("has_parent=$parent, ...");
  • Like 1

Share this post


Link to post
Share on other sites

in this case you only have to change the order in this line:

    if (!$p->viewable() || $p->template != "basic-page" ) continue;  // old
    if ($p->template != "basic-page" || !$p->viewable()) continue;  // new

PHP will return after the first conditional if it does not match and in these cases the code of the second condition (or any following) never get executed. Changing this, Teppos code is a complete fix. :)

Actually I don't think that makes any difference in this hypothetical case. The $p->template check doesn't look to see if the template file exists, just the name of the template assigned to the page.

So assume it hits a page with that template - it will then move to the "viewable" check. Assuming there is no template file, this will force the "continue". So this means that you still can't check just the assigned template and page status (not hidden or unpublished).

I think that makes sense.

But, yes, now we are really getting silly - sorry for starting it :)

Share this post


Link to post
Share on other sites

Good clarifications from both of you :)

This is getting a bit out of hand, but one more addition: in current code image isn't actually resized -- it's just forced to specific dimensions with HTML attributes. This could be intentional, but I'm wondering if this might make even more sense here: 

...
echo "<img src='{$p->images->first->size($resized_imageWidth, $resized_imageHeight)->url}' width='{$resized_imageWidth}' height='{$resized_imageHeight}'>" . "<a href='{$p->url}'>{$p->title}</a><br />";
...

This way end-user doesn't have to download excessively large images, if what you really want here is a thumb. It should also be noted that simply defining width and height with HTML attributes forces image to those exact dimensions without considering actual aspect ratio, which can easily result in distorted images.

(More about various options that size() accepts here.)

Thanks Teppo for the reminder! The uploaded image will always have the dimensions attributes. Also great contributions from all the forum's members! 

Share this post


Link to post
Share on other sites
On 3/9/2014 at 7:36 PM, teppo said:

Still somewhat ugly, but I'd probably go with something like this:


$session->history = is_array($session->history) ? array_slice(array_merge(array($page->id), $session->history), 0, 4) : array($page->id);

After that you can output stored data like this:


foreach ($session->history as $page_id) {
    $p = $pages->get($page_id);
    echo "<a href='{$p->url}'>{$p->title}</a><br />";
}

Sorry to resurrect this topic several years later. This works well but I am trying to a) prevent the displayed list of pages from showing the current page as well and b) also to only show each visited page once in the list. My attempts with array_unique have failed so far. Any tips?

Share this post


Link to post
Share on other sites
24 minutes ago, francis said:

Sorry to resurrect this topic several years later. This works well but I am trying to a) prevent the displayed list of pages from showing the current page as well and b) also to only show each visited page once in the list. My attempts with array_unique have failed so far. Any tips?

Perhaps something like this?

$session->history = is_array($session->history) ? array_slice(array_unique(array_merge([$page->id], $session->history)), 0, 4) : [$page->id];

And when you're displaying the history, just skip over current page:

foreach ($session->history as $page_id) {
    if ($page_id == $page->id) continue;
    $p = $pages->get($page_id);
    echo "<a href='{$p->url}'>{$p->title}</a><br />";
}

 

  • Like 1

Share this post


Link to post
Share on other sites

Fantastic, thank you, much obliged. That works perfectly!

I was putting the array_unique in the wrong place and just couldn't work out how to leave out the current page.

  • Like 1

Share this post


Link to post
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

  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...