Jump to content
janlonden

Sorting pages by multiple values

Recommended Posts

Hi!

I´m really liking ProcessWire, even though it´s a little intimidating to a complete PHP noob like me. The basics are pretty easy understand, but one function I still lack is the option to sort pages by custom fields. I looked at Ryans Scryscraper Site Profile to try to figure out how he did it for about 5 minutes before my brain exploded. I´ve also tried to search the forums without success. So if this is something that some of you PHP gurus could help me with that would be awesome.

Here´s my question. Lets say I have a photos page with lots of photo pages in it which include custom fields such as resolution, camera, size etc.. How would i go about to list them by these fields? For example like this:

select

-option(Camera model from A-Z)

-option(Camera model from Z-A)

select

-option(Highest resolution)

-option(Lowest resolution)

select

-option(Highest size)

-option(Lowest size)

[Find]

Thank you.

/Jan Londén

Edit:

Here´s the final code. Remember this is an ugly copy/paste version from a non PHP programmer. Use at your own risk, etc.. If anyone wants to improve, make this more elegant, please do. Huge thanks to adrian who helped a lot.

<?php

/**
 * Books template
 *
 */

include("./head.inc");

$selector = '';

// For the keyword search input. Searches both title and body.

if($input->get->keywords) {
    $value = $sanitizer->selectorValue($input->get->keywords);
    $selector .= "title|body%=$value, ";
    $summary["keywords"] = $sanitizer->entities($value);
    $input->whitelist('keywords', $value);
}

// For the book publisher select tag. Sorts alphabetically from A to Z.

if($input->get->book_publisher == 'desc') {
    $value = $sanitizer->selectorValue($input->get->book_publisher);
    $selector .= "sort=book_publisher,";
    $summary["book_publisher"] = $sanitizer->entities($value);
    $input->whitelist('book_publisher', $value);
}

// From Z to A.

elseif($input->get->book_genre == 'asc') {
    $value = $sanitizer->selectorValue($input->get->book_genre);
    $selector .= "sort=-book_genre,";
    $summary["book_genre"] = $sanitizer->entities($value);
    $input->whitelist('book_genre', $value);
}

// For the book chapters select tag. Sorts numerically from highest to lowest number of pages.

if($input->get->book_chapters == 'desc') {
    $value = $sanitizer->selectorValue($input->get->book_chapters);
    $selector .= "sort=book_chapters,";
    $summary["book_chapters"] = $sanitizer->entities($value);
    $input->whitelist('book_chapters', $value);
}

// From lowest to highest.

elseif($input->get->book_chapters == 'asc') {
    $value = $sanitizer->selectorValue($input->get->book_chapters);
    $selector .= "sort=-book_chapters,";
    $summary["book_chapters"] = $sanitizer->entities($value);
    $input->whitelist('book_chapters', $value);
}

// For the book pages select tag. Sorts numerically from highest to lowest number of pages.

if($input->get->book_pages == 'desc') {
    $value = $sanitizer->selectorValue($input->get->book_pages);
    $selector .= "sort=book_pages,";
    $summary["book_pages"] = $sanitizer->entities($value);
    $input->whitelist('book_pages', $value);
}

// From lowest to highest.

elseif($input->get->book_pages == 'asc') {
    $value = $sanitizer->selectorValue($input->get->book_pages);
    $selector .= "sort=-book_pages,";
    $summary["book_pages"] = $sanitizer->entities($value);
    $input->whitelist('book_pages', $value);
}

?>

<form id="book_search" method="get" action="<?php echo $config->urls->root?>books/">
    <h3>Browse books</h3>
    <p>
        <label for="search_keywords">Search</label>
        <input type="text" name="keywords" id="search_keywords" value="<?php if($input->whitelist->keywords) echo $sanitizer->entities($input->whitelist->keywords); ?>" />
    </p>
    <p>
        <label for="book_publisher">Publisher</label>
        <select name="book_publisher" id="book_publisher">
            <option value="">Any</option>
            <option value="desc"<?php if ($input->get->book_publisher == 'desc') { echo ' selected="selected"'; } ?>>Alphabetically A-Z</option>
            <option value="asc"<?php if ($input->get->book_publisher == 'asc') { echo ' selected="selected"'; } ?>>Alphabetically Z-A</option>
        </select>
    </p>
    <p>
        <label for="book_chapters">Number of chapters</label>
        <select name="book_chapters" id="book_chapters">
            <option value="">Any</option>
            <option value="desc"<?php if ($input->get->book_chapters == 'desc') { echo ' selected="selected"'; } ?>>Highest to lowest</option>
            <option value="asc"<?php if ($input->get->book_chapters == 'asc') { echo ' selected="selected"'; } ?>>Lowest to highest</option>
        </select>
    </p>
    <p>
        <label for="book_pages">Number of pages</label>
        <select name="book_pages" id="book_pages">
            <option value="">Any</option>
            <option value="desc"<?php if ($input->get->book_pages == 'desc') { echo ' selected="selected"'; } ?>>Highest to low</option>
            <option value="asc"<?php if ($input->get->book_pages == 'asc') { echo ' selected="selected"'; } ?>>Lowest to high</option>
        </select>
    </p>
    <p>
        <input type="submit" id="book_submit" name="submit" value="Find" />
    </p>
</form>

<?php $books = $page->children($selector); ?>
<?php if (count($books)) : ?>
<ul>
<?php foreach($books as $book) : ?>
    <li>
        <p>
            <a href="<?=$book->url?>"><?=$book->title?></a><br>
            Publisher: <?=$book->book_publisher?><br>
            Number of chapters: <?=$book->book_chapters?><br>
            Number of pages: <?=$book->book_pages?>

        </p>
    </li>
<?php endforeach ?>
</ul>
<?php else : ?>
<p>No books were found.</p>
<?php endif ?>
<?php include("./foot.inc");

You might need to change desc/asc values to get them working the way you want.

Edited by janlonden

Share this post


Link to post
Share on other sites

The trick is to build up a string variable eg. $selector, based on the options chosen by the user and using that variable as part of something like:

$images = $page->children($selector); 
 

This assumes of course that all your images are child pages of the main gallery page.

You'll probably want $selector to end up being something like:

sort=-camera_model, sort=resolution, sort=-size
 

The way to build $selector can be seen in the Skyscraper's search.php file. For example, this section:

if($input->get->keywords) {
	$value = $sanitizer->selectorValue($input->get->keywords);
	$selector .= "title|body%=$value, "; 
	$summary["keywords"] = $sanitizer->entities($value); 
	$input->whitelist('keywords', $value); 
}

Each section like this appends more component parts to the $selector string using the '.=' notation. The $input->get->keywords refers to a variable passed from your form using the GET method. You could of course also use POST. GET will put the variables in the URL like ?keywords=word& etc. This is useful for allowing a user to bookmark or share a query link.

I am not exactly sure your plans for the resolution and size selects - sounds like you want to offer sorting highest to lowest and lowest to highest? If so, you can build your selector using sort options. Take a look at the sort options on this page: http://processwire.com/api/selectors/

Once you have defined your $selector and searched and sorted the children with it, you can simply foreach through the images:

foreach($images as $image){
       echo $image->url ...... //etc
}
 

Hope that helps. 

  • Like 2

Share this post


Link to post
Share on other sites

Thank you for your help. This is what I´ve managed to come up with:

<?php $images = $page->children($selector);

if($input->get->keywords) {
	$value = $sanitizer->selectorValue($input->get->keywords);
	$selector .= "title|body%=$value, "; 
	$summary["keywords"] = $sanitizer->entities($value); 
	$input->whitelist('keywords', $value); 
} ?>

<h1>Browse photos</h1>

<form id="photo_search" method="get" action="<?php echo $config->urls->root?>browse/?>">
	<p>
		<label for='search_keywords'>Keywords</label>
		<input type='text' name='keywords' id='search_keywords' value='<?php if($input->whitelist->keywords) echo $sanitizer->entities($input->whitelist->keywords); ?>' />
	</p>
	<p>
		<input type="submit" id="search_submit" name="submit" value="Find" />
	</p>
</form>

<?php foreach($images as $image) {
	echo $image->url;
} ?>

... As i said, I´m a total PHP noob. This won't even display the search results :D

I looked at the selector page and found that the code below works to display the photos by model/resolution/size.

$photos = $pages->find("template=photo, sort=camera_model");
foreach($photos as $photo) { ... }

But how to implement that into the search form i have no idea.

Maybe I´ll have to settle for a single select input which links to pages with custom querys?

Share this post


Link to post
Share on other sites

I think you have the right idea with the example you showed above, but a few things:

  1. At the end of your <form tag you are using the php close tag (?>) twice. You want something like: 
    action="<?php echo $config->urls->root; ?>browse/"
    

    When you are using PHP and things aren't working, be sure to view the source of the rendered HTML page to confirm it is generating what you think it is. Also make sure you are getting your PHP errors generated somewhere, either on the page or in a log file. Not sure how this is set up as it can depend on the settings on your host. If you don't see them, ask them and/or google turn on php error reporting.

  2. Also, turn on debug on PW config.

  3. You should define $selector once as $selector = ''; before you start appending parts to it. Not a fatal error, but good practice.

  4. You are trying to use the $selector before you have generated it

Try this:

<?php 

if($input->get->keywords) {
    $value = $sanitizer->text($input->get->keywords);
    $selector .= "title|body%=$value, "; 
    $summary["keywords"] = $sanitizer->entities($value); 
    $input->whitelist('keywords', $value); 
} 

$images = $page->children($selector);

foreach($images as $image) {
    echo '<img src="'.$image->url.'" alt="'.$image->title.'" title="'.$image->title.'" />';
}

?>

<h1>Browse photos</h1>

<form id="photo_search" method="get" action="action="./"">
    <p>
        <label for='search_keywords'>Keywords</label>
        <input type='text' name='keywords' id='search_keywords' value='<?php if($input->whitelist->keywords) echo $sanitizer->entities($input->whitelist->keywords); ?>' />
    </p>
    <p>
        <input type="submit" id="search_submit" name="submit" value="Find" />
    </p>
</form> 

Because I am still not sure of how your pages are structured, this may not work. But if as you say, 

$photos = $pages->find("template=photo, sort=camera_model");
 

worked, then maybe you could replace the selector line I have above with:

$photos = $pages->find($selector);
 

If you decide to follow the second link that kongondo mentions above, be sure to read through to the end of the thread. I made a few changes to that code to improve it, thanks to some suggestions by Soma. Honestly, I think in your case, building a custom form like we are doing here will be a better approach.

Let us know how you go.

Share this post


Link to post
Share on other sites

Thank you both kongondo and adrian for taking the time to help. I read both of those posts and tried the codes in them but couldn't get them to work. I also tested adrians new code, which just displays a unordered list of the photos and where the search doesn´t work.

I think i need to add something like this:

<?php

$selector = '';

if($input->get->keywords) {
    $value = $sanitizer->selectorValue($input->get->keywords);
    $selector .= "title|body%=$value, "; 
    $summary["keywords"] = $sanitizer->entities($value); 
    $input->whitelist('keywords', $value); 
}

// add something here, like:

if($input->get->camera_model) {
    $selector .= "template=photo sort=camera_model";
    $selector .= "template=photo sort=-camera_model";
}

?>

And then in the form add $selector or some other php to <select> camera_model and camera_resolution.

<form id="photo_search" method="get" action="<?php echo $config->urls->root?>photos/">

<h3>Browse photos</h3>

<p>
    <label for="search_keywords">Keywords</label>
    <input type="text" name="keywords" id="search_keywords" value="<?php if($input->whitelist->keywords) echo $sanitizer->entities($input->whitelist->keywords); ?>" />
</p>

<p>
    <label for="camera_model">Camera model</label>
    <select name="camera_model" id="camera_model">
        <option>Sort alphabetically(Ascending)</option>
        <option>Sort alphabetically(Desdending)</option>
    </select>
</p>

<p>
    <label for="camera_resolution">Camera resolution</label>
    <select name="camera_resolution" id="camera_resolution">
        <option>Highest to low</option>
        <option>Lowest to high</option>
    </select>
</p>

<p>
    <input type="submit" id="search_submit" name="submit" value="Search" />
</p>

</form>

Any help would be greatly appreciated. ProcessWire is such a great system otherwise which is why I´m willing to go through this trouble to get this working. I just tested the views module in drupal 7. With just a few clicks I had a nice custom query thingy. I wish ProcessWire had something similar :)

Share this post


Link to post
Share on other sites
 Because I am still not sure of how your pages are structured, this may not work. But if as you say,

My page structure is photos > photo1, 2 etc..

Share this post


Link to post
Share on other sites

Sorry, my example wasn't supposed to include the ordering - it was just an example for the keyword search. If that is working, then it shouldn't be hard to add the sort by those field options. It looks like your additions are on the right track, but you might want to take out the template=photo bit. If you are only searching the children of the photos main page, you won't need this. If you do want to keep it in, then define it first $selector = "template=photo" and then when you append other parts:

if($input->get->camera_resolution == 'asc') {
    $selector .= "sort=camera_model,";
}
elseif($input->get->camera_resolution == 'desc'){
    $selector .= "sort=-camera_model,";
}

Then in your form you need the select options to have values like:

<select name="camera_resolution" id="camera_resolution">
<option value="desc">Highest to low</option>
<option value="asc">Lowest to high</option>
</select>
 

Share this post


Link to post
Share on other sites

Thanks adrian. It´s almost working now! The search works just fine. The others work like, once after I´ve used the search, and then they stop working.

The code:

<?php

$selector = '';

if($input->get->keywords) {
    $value = $sanitizer->selectorValue($input->get->keywords);
    $selector .= "title|body%=$value, "; 
    $summary["keywords"] = $sanitizer->entities($value); 
    $input->whitelist('keywords', $value); 
}

if($input->get->camera_model == 'asc') {
    $selector .= "sort=camera_model,";
}

elseif($input->get->camera_model == 'desc') {
    $selector .= "sort=-camera_model,";
}

if($input->get->photo_resolution == 'asc') {
    $selector .= "sort=photo_resolution,";
}

elseif($input->get->photo_resolution == 'desc') {
    $selector .= "sort=-photo_resolution,";
}

if($input->get->photo_size == 'asc') {
    $selector .= "sort=photo_size,";
}

elseif($input->get->photo_size == 'desc') {
    $selector .= "sort=-photo_size,";
}

?>

<form id="photo_search" method="get" action="<?php echo $config->urls->root?>photos/">

<h3>Browse photos</h3>

<p>
    <label for="search_keywords">Keywords</label>
    <input type="text" name="keywords" id="search_keywords" value="<?php if($input->whitelist->keywords) echo $sanitizer->entities($input->whitelist->keywords); ?>" />
</p>

<p>
    <label for="camera_model">Camera model</label>
    <select name="camera_model" id="camera_model">
        <option value="desc">Alphabetically A-Z</option>
        <option value="asc">Alphabetically Z-A</option>
    </select>
</p>

<p>
    <label for="photo_resolution">Photo resolution</label>
    <select name="photo_resolution" id="photo_resolution">
        <option value="desc">Highest to low</option>
        <option value="asc">Lowest to high</option>
    </select>
</p>

<p>
    <label for="photo_size">Photo size</label>
    <select name="photo_size" id="photo_size">
        <option value="desc">Highest to low</option>
        <option value="asc">Lowest to high</option>
    </select>
</p>

<p>
    <input type="submit" id="photo_submit" name="submit" value="Find" />
</p>

</form>

<?php 

$photos = $page->children($selector);

foreach($photos as $photo) {
    echo '<ul>';
    echo '<li><a href="'.$photo->url.'">'.$photo->title.'</a></li>';
    echo '</ul>';
}

?>

I suspect there´s something wrong with the upper PHP part, the ifs and elses.

Share this post


Link to post
Share on other sites

As a self help tool, try echo'ing $selector and see how that changes between your first and subsequent searches.

eg: echo 'selector string: ' . $selector;

Share this post


Link to post
Share on other sites

Thanks, I´ll check that one out. I think the options worked but they would work even better if I´d put them on one single select tag of course. I mean I cannot sort them by more than one custom field at a time. Not in this case atleast, right? Stupid me :)

I need them to be like this:

<p>
    <label for="sort_photos">Sort by</label>
    <select name="sort_photos" id="sort_photos">
        <optgroup label="Alphabetically">
            <option value="desc">A-Z</option>
            <option value="asc">Z-A</option>
        </optgroup>
        <optgroup label="Resolution">
            <option value="desc">Highest to low</option>
            <option value="asc">Lowest to high</option>
        </optgroup>
        <optgroup label="Size">
            <option value="desc">Highest to low</option>
            <option value="asc">Lowest to high</option>
        </optgroup>
    </select>
</p>

Any ideas how to code the PHP part?

Share this post


Link to post
Share on other sites

That option seems limiting to me - now the user can only choose one of the ways to sort, rather than a grid of options. If they are in separate selects then the user can search all the combos. Do you not want that flexibility for some reason? 

But if you do want to do that, I guess you could make the option values things like: resolution-desc and resolution-asc and then in the if statements, you could split these. Something like:

$search_order = strstr($input->get->sort_photos, '-'); // gets order, eg asc

$search_type = str_replace($search_order, '', $input->get->sort_photos); // gets search type, eg resolution

Does that make sense?

Share this post


Link to post
Share on other sites

Yeah I guess you´re right. It is possible and useable to combine the options. But there´s still problems with changing the options. If I play around with the options I might succeed changing one of them. And if i then want to change that option I have to click around with the others to change the previous option. Hard to explain :)

But yeah it´s not working properly. Could it be because there´s just one value for "asc" and one for "desc"?

Share this post


Link to post
Share on other sites

That option seems limiting to me - now the user can only choose one of the ways to sort, rather than a grid of options. If they are in separate selects then the user can search all the combos. Do you not want that flexibility for some reason? 

But if you do want to do that, I guess you could make the option values things like: resolution-desc and resolution-asc and then in the if statements, you could split these. Something like:

$search_order = strstr($input->get->sort_photos, '-'); // gets order, eg asc

$search_type = str_replace($search_order, '', $input->get->sort_photos); // gets search type, eg resolution

Does that make sense?

As I said, I´m with you on using seperate selects :)

That "splitting" technique might be the answer to the problem with the select options? How would i do that splitting with the multiple select tags version?

Share this post


Link to post
Share on other sites

You don't need the splitting technique with multiple selects. That was only if you wanted to use just the one select.

I am not really sure where you are still having troubles at this point. Any chance you can show us the site? I am heading out for the day now. Hopefully someone else will pick up and help you.

One more thing you will want to do is get the select options to be selected once the form has submitted so the user can see what they selected and change from there, rather than starting from scratch. For this you'll want to echo selected="selected" for the appropriate option in your form - similar to how it is done for the keywords text input field.

Good luck! You really are close :)

Share this post


Link to post
Share on other sites

I think I got them working! Just had to change som asc/desc values. The resolution and size sortings may clash because of the similarity of their values, plus having only 3 pages to sort doesn´t help.

I also manages to code and get the selected="selected" working! All by myself! :D

With this code:

    <label for="camera_model">Camera model</label>
    <select name="camera_model" id="camera_model">
        <option value="desc"<?php if ($input->get->camera_model == 'desc') { echo ' selected="selected"'; } ?>>Alphabetically A-Z</option>
        <option value="asc"<?php if ($input->get->camera_model == 'asc') { echo ' selected="selected"'; } ?>>Alphabetically Z-A</option>
    </select>
  • Like 1

Share this post


Link to post
Share on other sites

One thing I don't understand is why it sorts the "photo_resolution" from lowest to high as: 1024, 2048 and 480. It seems that it only counts the first number. I had the same problem with Hero Framework CMS. Any ideas how to fix this?

Share this post


Link to post
Share on other sites

Congrats on getting things working - feels good doesn't it :)

I am guessing the sorting issue you are having is to do with the field type you are using to store the photo_resolution. If you are using text, try switching it to Integer and I think that will solve your problem. 

One thing to note - you should make sure you sanitize all the get variables. Read this to learn more about your options:

http://processwire.com/api/variables/sanitizer/

Share this post


Link to post
Share on other sites

It does feel really good :) Thank you again for your help!

I switched to integer and now it works. The fields are now sanitized also, using this:

if($input->get->photo_resolution == 'asc') {
    $value = $sanitizer->selectorValue($input->get->photo_resolution);
    $selector .= "sort=photo_resolution,";
    $summary["photo_resolution"] = $sanitizer->entities($value);
    $input->whitelist('photo_resolution', $value);
}

elseif($input->get->photo_resolution == 'desc') {
    $value = $sanitizer->selectorValue($input->get->photo_resolution);
    $selector .= "sort=-photo_resolution,";
    $summary["photo_resolution"] = $sanitizer->entities($value);
    $input->whitelist('photo_resolution', $value);
}

Is this correct? I get no errors at least.

Share this post


Link to post
Share on other sites

I wrote my own code which works. Haha I´m feeling like a PHP pro right now :D

$photos = $page->children($selector);

if (count($photos)) {
	foreach($photos as $photo) {
		echo '<ul>';
		echo '<li><a href="'.$photo->url.'">'.$photo->title.'</a></li>';
		echo '<li>Model: '.$photo->camera_model.'</li>';
		echo '<li>Resolution: '.$photo->photo_resolution.'</li>';
		echo '<li>Size:'.$photo->photo_size.'</li>';
		echo '</ul>';
	}
}
else {
	echo '<p>No photos found.</p>';
}

?>

I have no idea if this is good PHP coding practice or not, but it works :)

  • Like 2

Share this post


Link to post
Share on other sites

Some purists might argue against echoing so much plain html, but as long as it works...

There's a heck of a lot of my code looks just like that.  :-[

Share this post


Link to post
Share on other sites

Yeah I got that feeling myself intuitively :D

If you or anyone could help me make this better that would be great!

I´ll try to figure out how to remove those echoes.

Share this post


Link to post
Share on other sites

A much better output with this:

<?php 

$books = $page->children($selector);

if (count($books)) {

	echo "<ul>\n";

	foreach($books as $book) {
		echo "\t<li>\n" . 
			 "\t\t<p>\n" . 
			 "\t\t\t<a href='{$book->url}'>{$book->title}</a><br>\n" . 
			 "\t\t\tModel: {$book->book_publisher}<br>\n" . 
			 "\t\t\tResolution: {$book->book_chapters}<br>\n" . 
			 "\t\t\tSize: {$book->book_pages}\n" . 
			 "\t\t</p>\n" . 
			 "\t</li>\n";
	}

	echo "</ul>\n";
}

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

?>

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.

  • Similar Content

    • By David Karich
      The Page Hit Counter module for ProcessWire implements a simple page view counter in backend. Page views of visitors are automatically tracked on defined templates, with monitoring of multiple page views. This gives you a quick overview of how many visitors have read a news or a blog post, for example, without first having to open complex tools such as Google Analytics. This module quickly provides simple information, e.g. for editors. Or, for example, to sort certain news by most page views. For example for "Trending Topics".

       
      Works with ProCache and AdBlockers. With a lightweight tracking code of only ~320 bytes (gzipped). And no code changes necessary! In addition GDPR compliant, since no personal data or IP addresses are stored. Only session cookies are stored without information. 
      In addition, there are some options, for example filtering IP addresses (for CronJobs) and filtering bots, spiders and crawlers. You can also configure the lifetime of the session cookies. Repeated page views are not counted during this period. It is also possible to exclude certain roles from tracking. For example, logged in editors who work on a page are not counted as page views.

      Sort by hits and access page views (hit value)
      Each trackable template has an additional field called phits. For example, you want to output all news sorted by the number of page views.
      // It is assumed that the template, e.g. with the name "news", has been configured for tracking. $news = $pages->find("template=news, sort=-phits"); To output the page views of a tracked page, use:
      echo $page->phits; Example: Reset counter per API
      $modules->get("PageHitCounter")->resetPageViews("template=whatever", false); Example: Tracking a page hit via API and jQuery
      If you want to track a template that does not represent a full page to automatically inject a tracking script, you can define allowed API templates in the module that you can track. Below is an example of how you can track a click on news tag using jQuery. This will allow you to find out which keywords are clicked the most. For example, you can sort and display a tag cloud by the number of hits. Suppose your keywords have the template "news_tag". The template "news_tag" was also configured in the Page Hit Counter Module as a trackable API template.
      Example PHP output of keywords / tags:
      // Required: the data attribute "data-pid" with the ID of the template to be tracked. echo $pages->find("template=news_tag, sort=-phits")->each("<a href='{url}' class='news_tag' data-pid='{id}'>{title}</a>"); Example Tracking Script with jQuery:
      /** * Required: Data attribute "data-pid" with the ID of the news tag template * Required: Send the POST request to the URL "location.pathname.replace(/\/?$/, '/') + 'phcv1'" * Required: The POST parameter "pid" with the ID of the template */ $(function(){ if($('a.news_tag').length > 0) { $('a.news_tag').each(function(){ var tPID = $(this).data("pid"); if(tPID) { $(this).on("click", function(){ $.post(location.pathname.replace(/\/?$/, '/') + 'phcv1', {pid: tPID}); }); } }); } }); So simply every click on a tag is counted. Including all checks as for automatic tracking. Like Bot Filtering, Session Lifetime, etc.
      Notice: Tracking with URL segments
      If the option "Allow URL Segments" is activated on a template, the hits are only counted if the base URL of the page is called. If you want the hit to be counted even when a segment is requested, you MUST configure the segments in the template configuration. How to do this can be found here. If you use dynamic segments, configure them as RegEx. There is currently no other option. The problem is that the Page Hit Counter hooked into the PageNotFound process. If URL segments are allowed but not defined, a 404 is never triggered. This means that the Page Hit Counter cannot be called.
      New since 2.0.0: Ignore URL segments
      If a template has URL segments configured, each hit on a different segment is counted as a new hit. Enable "Ignore URL segments" so that dynamic segments are not counted individually on the base template / page.
      New since 2.0.0: Use cookieless tracking (Experimental)
      Enable this option to not use individual cookies for tracking or if you have many different pages you want to track. The limit for cookies is 50 per domain for all cookies on the page. If the option is enabled, PHP session storage is used. Downside: you can't set the lifetime higher than configured in your PHP.ini and the session will be terminated as soon as the browser is closed.
      Upgrade note for 2.0.0 from previous versions!
      Version 2.0.0 requires an update in the database schema, so that additionally the date of the last access / hit on the page can be displayed ($page->lastPageHit). To make this possible, you have to do the update via the upgrade module, upload the ZIP itself and do an update directly via the backend AND DO A MODULE REFRESH DIRECTLY AFTER UPLOAD/UPDATE. If you do not do this, you will get an error that a column is missing in the database table.
      _______________________________________________________
      Background: This module is the result of a customer requirement, where the editors are overwhelmed with analytics or no tracking tools were allowed to be used. However, a way had to be found to at least count page views in a simple form for evaluations. Furthermore, by using ProCache, a way had to be found to count views of a page without clearing the cache.
      _______________________________________________________
      Pros
      Automatic Page View Tracking Lightweight tracking code, only ~320 bytes (gzipped) No code or frontend changes necessary Works with ProCache! Even if no PHP is executed on the cached page, the tracking works Works with browser AdBlockers No cache triggers (for example, ProCache) are triggered. The cache remains persistent GDPR compliant, session-based cookie only, no personal information Filtering of IPs and bots possible Exclude certain roles from tracking Ability to reset Page Views Works with all admin themes Counter database is created as write-optimized InnoDB API to track events for templates that are not viewable No dependencies on libraries, pure VanillaJS (Automatic tracking script) Works in all modern browsers Pages are sortable by hits Cons
      Only for ProcessWire version 3.0.80 or higher (Requires wireCount()) Only for PHP version 5.6.x or higher No support for Internet Explorer <= version 9 (Because of XMLHttpRequest()) No historical data, just simple summation (Because of GDPR) Segment URLs can only be counted if the segments are defined Planned Features / ToDos
      API access to hit values Since version 1.2.1 Possibility to sort the pages by hits (Request by @Zeka) Since version 1.2.0 Don't track logged in users with certain roles (Request by @wbmnfktr) Since version 1.1.0 Possibility to reset the counter for certain pages or templates (Request by @wbmnfktr) Since version 1.1.0 Better bot filter Since version 1.1.0 Disable session lifetime, don't store cookies to track every page view (Request by @matjazp) Since version 1.2.1 Option to hide the counter in the page tree (Request by @matjazp) Since version 1.2.1 Option to hide the counter in the page tree on certain templates Since version 1.2.1 API to track events for templates that are not viewable Since version 1.2.2 Cookieless tracking Since version 2.0.0 Show last hit Since version 2.0.0 Ignore URL segments (Request by @bernhard) Since version 2.0.0 Add hookable method after pageview was tracked (Request by @bernhard) Since version 2.0.0 Changelog
       
      2.0.0
      Feature request: Add hookable method after pageview was tracked (___pageViewTracked($pageID)) (Requested by @bernhard) Feature request: Ignore URL segments option (Requested by @bernhard) New: Cookieless tracking New: Show date of last hit Update: Botlist Enhancement: Documentation improvement 1.2.7
      Feature request: make buildPageListHitCounter-Function public (Requested by @bernhard) 1.2.6
      Bug-Fix: Set the counter of a cloned page to 0 Enhancement: The function for resetting counters is now available in the module as a public function to reset counters via own scripts on the API side (Request by @VeiJari) Enhancement: Documentation improvement API reset 1.2.5
      Bug-Fix: When counting 404 hits, cookies are no longer set. The session lifetime is deactivated for the 404 page Enhancement: Documentation improvement regarding URL segments 1.2.4
      Bug-Fix: Resetting the counters on system pages (e.g. 404) does not work (Reported by wbmnfktr) Bug-Fix: Tracking endpoint is logged as 404 if module "Jumplinks" is installed (Reported by wbmnfktr) Enhancement: Corrected few typos (Merged from Sergio #6 – THX!) 1.2.3
      Bug-Fix: Tracking script triggers 404 if pages are configured without slash (#3) Reported by @maxf5 Enhancement: Reduction of the tracking script size if it's gzipped (~320 bytes) Enhancement: Documentation improvement Enhancement: Corrected few typos 1.2.2
      New feature: API to track events for templates that are not viewable Enhancement: Documentation improvement 1.2.1
      API access to hit values Use $page->phits Bug-Fix: No tracking on welcomepage (Reported by wbmnfktr; Thx to matjazp) Bug-Fix: Tracking script path on subfolders (Reported by matjazp) Bug-Fix: Tracking on pages with status "hidden" Enhancement: Change database engine to InnoDB for phits field Enhancement: Option to disable session lifetime set session lifetime to 0, no cookies Enhancement: Better installation check Enhancement: AJAX Request asyncron Enhancement: Reduction of the tracking script size by ~20% Enhancement: Option to hide the counter in the page tree You can output the counter with the field name "phits" Enhancement: Option to hide the counter in the page tree on certain templates Enhancement: Option for activate general IP validation Enhancement: Reduction of tracking overhead up to ~30ms Enhancement: Better bot list for detection 1.2.0
      New feature: Sort pages by hits – New field phits Migrate old counter data to new field 1.1.0
      New feature: Exclude tracking of certain roles New feature: Reset Page Views Better bot filter and detection 1.0.0
      Initial release Notes
      By default, the page views are stored as INT in the database. This allows a maximum counter value of 4.2 billion views (4,294,967,295) per page. If you need more, change the type to BIGINT directly in the database. But I recommend to use Google Analytics or similar tools if you have such a large number of users.
      _______________________________________________________
      Download GitHub: ProcessWire Page Hit Counter (Version 2.0.0)
      PW Module Directory: ProcessWire Page Hit Counter (Version 2.0.0)
      Install via ProcessWire (Classname): PageHitCounter
      _______________________________________________________
      Update information
      If you have used version 1.2.1 from the DEV branch, please replace it completely with the new master version.
      Old stable version
      Download GitHub: ProcessWire Page Hit Counter (Version 1.2.7)
    • By picarica
      so i made some options in t he field type, and i want to check if selected title is that output this is my sample code
      if($media->r_soc == 'facebook') { $soc = 'facebook'; } elseif($media->r_soc == 'twitter') { $soc = 'twitter'; } i just basically want to check if the user in CMS selected option facebokk and then outpit it into variable which is later outputted into fa icon, oh and also this is all in repeat field
      foreach($ikonky as $media) { so thats why its $media, but as of now it outputs blank state, not sure why,
      it doesnt outpit anything none of the check goes throught these are options i have in the field
      1=facebook 2=twitter 3=instagram 4=youtube 5=github 6=linkedin  
    • By Flashmaster82
      Is it possible to just show a list (page reference) but without any radio buttons? Or a drop down but the references is not selectable? The items needs to be references but the main thing is that its just a list. Please help!

    • By opalepatrick
      Hi, trying to order pages by modified date, date. I can do 'sort=-date_modified, sort=-date' but that will always put the modified date first regardless of actual date order. I just want to coalesce the two fields and sort. Any ideas would be appreciated.
    • By benbyf
      Hi, Looking to create form elements on a page–some input with a colection of form inputs and the appropriate labels and variables for that input. I've used ProForms in the past and rolled out my own when creating simply one off forms, but I wonder if anyone has found a good way of allowing form creation on page editing so that clients can adhocly make and edit forms?
      Thanks
×
×
  • Create New...