Leaderboard
Popular Content
Showing content with the highest reputation on 09/01/2012 in all areas
-
This was the first full site I built with Processwire. We launched it several months ago, but I immediately got swept up in another project, and forgot to post it. In case the name didn't clue you in, it's a site for my bother's company. http://www.renobuilding.com3 points
-
I also thought about this Pete but it doesn't sort by multiple. It sorts first all by id and then all by title. Well since I'm also in need of such exact feature for my project, I took this approach and created a little helper module. After install you have a new method on $pages var. $pages->findRelated(...); $pages->findRelated( Page $page, PageArray $tags, string $field [, string $tmpl, int $limit] ); I tried also to do it with the PW API only but it isn't possible to sort by score AND modified so I commented that part out and wrote a plain sql query to do it instead. To use it you do something like this: $found = $pages->findRelated($page, $page->tags, 'tags', 'product|product2', 50); if($found) { foreach( $found as $rel ) { echo "<p><a href='$rel->url'>$rel->title</a> ($rel->score)</p>"; } } else { echo "<p>No related Products found</p>"; } The module can be found here: https://gist.github.com/35589742 points
-
I'm good with a toggle. I don't want to change the existing default behavior, just because it's been there awhile, and some people may be relying on it (including me). So dont want to produce any surprises. But I've added a toggle called 'arrayToCSV' that you can put in the $options. If you set that to false, then it'll put it in the format that you prefer. I've attached a copy of this file. Can you test to confirm that this works the way you were thinking and let me know? If all looks good, I'll commit it to the source. MarkupPagerNav.module1 point
-
I just wrote one answer but erased everything before posting it as I found almost everything in it dead wrong. Another try. And then I started to write another explanation, but after checking if I'm reading the latest code decided to give this even one more try. Maybe I shouldn't have tried to answer this now . And here's the answer, finally: you're right in the sense that there actually is a bug in the code you're running. But this issue has been fixed by Ryan a month ago, so updating to the latest version from GitHub should fix your problem. I was reading the old version myself at first too... Edit: I did have something right in the first version of my answer. Here goes, again. Only one sort selector is supported at the moment, not even "sort=-rank,-created" works. There's a comment in the code saying "Currently only sorts by one field at a time". And find() for arrays does not support "start" at all, but this can be achieved by leaving "limit" (and "start") from the selector and calling $array->slice($start, $limit) instead for the sorted array.1 point
-
The /our-experience/ page shows the first project from each child page. foreach($pages->get("/our-experience/")->children as $project) { $image = $project->child->images->first()->size(286,190);; echo "<a href='{$project->url}'><div class='thumb'>"; if ($image) { echo "<img src='{$image->url}' width='286' height='190' alt='{$image->get('description|name')}'/>"; } echo "<h5>{$project->title}</h5>"; echo "</div></a>"; } Here's how I grabbed the prev/next images and titles in Processwire: if ($page->prev->id) { $prev = $page->prev()->child()->images->first()->size(250,175); echo "<a href='{$page->prev->url}' class='sub-nav-left'><div class='arrow'>←</div><img src='{$prev->url}' /><br />{$page->prev->title}</a>"; } if ($page->next->id) { $next = $page->next()->child()->images->first()->size(250,175); echo "<a href='{$page->next->url}' class='sub-nav-right'><div class='arrow'>→</div><img src='{$next->url}' /><br />{$page->next->title}</a>"; } A little bit of jQuery handles the animation: $('.sub-nav-right').hover(function() { $(this).stop().animate({ right: '0' }, 300) }, function() { $(this).stop().animate({ right: '-280' }, 400) }); $('.sub-nav-left').hover(function() { $(this).stop().animate({ left: '0' }, 300) }, function() { $(this).stop().animate({ left: '-280' }, 400) }); Edit: GAH! The code editor is a nightmare. Hopefully you get the idea.1 point
-
Hi Ryan, Yes! *slaps forehead* that's perfect! Thank you! Using the page field would let me create a handful of unique mini-site layouts could easily be reused, instead of having to make a new one for each site. Something like: /templates/mini-layout-a.php /templates/mini-layout-b.php /templates/mini-layout-c.php /templates/mini-layout-d.php I need to use more descriptive names of course, but all of those templates could have unique layouts. Thanks again.1 point
-
Love it. Love the cleverness of the headline too - I was immediately wondering why the full stops were there, but it works well as a sentence and separate statements too. Good stuff!1 point
-
Apologies in advance if this is old news, but for anyone who hasn't realised how trivially easy PW makes this, just give it a try. Google Analytics (GA) has a newish feature - 'Content Experiments' (multivariate testing if you want to be posh), and this is so easy to do with PW, it's almost unbelievable. What it boils down to is testing different variations of a page to see which performs (gets more sales, signups, leads, whatever) better, either between 2 versions (A/B testing) or more (multivariate testing). Say you have a page with a download link (or 'sign up for newsletter' or whatever), and you want to test size, colour, position or whatever of the download link - Install Ryan's Page Clone module Clone your page as many times as necessary, so you end up with /download-page/ (the original) /download-page-1/ /download-page-2/ etc [*]Edit page titles so they are the same as the original [*]Set the copies to hidden, so they don't appear in navigation, search, etc., but are still accessible by their URL [*]Change whatever in each copy (link colour, button size/colour) [*]Create a Goal in GA (I'm not a GA expert by any means, so you're on your own with that bit, but it is quite easy) [*]Create a new experiment under Content > Experiments and point it at your original and variations [*]GA gives you a bit of JS to add after the <head> tag of the original page, which allows them to redirect to the variations as necessary, so you need this in that page's template. [*]Sit back and bask in how easy it was and await GA doing the hard work Eventually, GA will detect which variation performs better, and you can end the experiment and dump the other page variants, replacing the original with the winner.1 point
-
The disadvantage with uniqid() is that its output is predictable since the value returned is based on the current timestamp. So on the surface, it seems there's possibility for that to be exploited, although it might be challenging. The password generation I put in the example above is based all around random characters, which aren't predictable other than the set which they come from (a-z2-9) and the length (between 9 and 12). I think this is pretty strong. However, the security of it could be increased by adding more to the set of possible characters (punctuation, upper/lower, etc.) and increasing the possible length range, like up to 30 characters or something. I opted to limit the character set and exclude the letters that are easily confused with each other, like "o O 0" and "i I l 1", just in case people are hand-typing (rather than copy/pasting)… less support burden. Another thing I might add to the code would be to make it only work with users of a certain role. But that would be pretty site-specific, so left it out here.1 point
-
I recently had to setup front-end system to handle logins, password resets and changing passwords, so here's about how it was done. This should be functional code, but consider it pseudocode as you may need to make minor adjustments here and there. Please let me know if anything that doesn't compile and I'll correct it here. The template approach used here is the one I most often use, which is that the templates may generate output, but not echo it. Instead, they stuff any generated output into a variable ($page->body in this case). Then the main.php template is included at the end, and it handles sending the output. This 'main' template approach is preferable to separate head/foot includes when dealing with login stuff, because we can start sessions and do redirects before any output is actually sent. For a simple example of a main template, see the end of this post. 1. In Admin > Setup > Fields, create a new text field called 'tmp_pass' and add it to the 'user' template. This will enable us to keep track of a temporary, randomly generated password for the user, when they request a password reset. 2a. Create a new template file called reset-pass.php that has the following: /site/templates/reset-pass.php $showForm = true; $email = $sanitizer->email($input->post->email); if($email) { $u = $users->get("email=$email"); if($u->id) { // generate a random, temporary password $pass = ''; $chars = 'abcdefghjkmnopqrstuvwxyz23456789'; // add more as you see fit $length = mt_rand(9,12); // password between 9 and 12 characters for($n = 0; $n < $length; $n++) $pass .= $chars[mt_rand(0, strlen($chars)-1)]; $u->of(false); $u->tmp_pass = $pass; // populate a temporary pass to their profile $u->save(); $u->of(true); $message = "Your temporary password on our web site is: $pass\n"; $message .= "Please change it after you login."; mail($u->email, "Password reset", $message, "From: noreply@{$config->httpHost}"); $page->body = "<p>An email has been dispatched to you with further instructions.</p>"; $showForm = false; } else { $page->body = "<p>Sorry, account doesn't exist or doesn't have an email.</p>"; } } if($showForm) $page->body .= " <h2>Reset your password</h2> <form action='./' method='post'> <label>E-Mail <input type='email' name='email'></label> <input type='submit'> </form> "; // include the main HTML/markup template that outputs at least $page->body in an HTML document include('./main.php'); 2b. Create a page called /reset-pass/ that uses the above template. 3a. Create a login.php template. This is identical to other examples you may have seen, but with one major difference: it supports our password reset capability, where the user may login with a temporary password, when present. When successfully logging in with tmp_pass, the real password is changed to tmp_pass. Upon any successful authentication tmp_pass is cleared out for security. /site/templates/login.php if($user->isLoggedin()) $session->redirect('/profile/'); if($input->post->username && $input->post->pass) { $username = $sanitizer->username($input->post->username); $pass = $input->post->pass; $u = $users->get($username); if($u->id && $u->tmp_pass && $u->tmp_pass === $pass) { // user logging in with tmp_pass, so change it to be their real pass $u->of(false); $u->pass = $u->tmp_pass; $u->save(); $u->of(true); } $u = $session->login($username, $pass); if($u) { // user is logged in, get rid of tmp_pass $u->of(false); $u->tmp_pass = ''; $u->save(); // now redirect to the profile edit page $session->redirect('/profile/'); } } // present the login form $headline = $input->post->username ? "Login failed" : "Please login"; $page->body = " <h2>$headline</h2> <form action='./' method='post'> <p> <label>Username <input type='text' name='username'></label> <label>Password <input type='password' name='pass'></label> </p> <input type='submit'> </form> <p><a href='/reset-pass/'>Forgot your password?</a></p> "; include("./main.php"); // main markup template 3b. Create a /login/ page that uses the above template. 4a. Build a profile editing template that at least lets them change their password (but take it further if you want): /site/templates/profile.php // if user isn't logged in, then we pretend this page doesn't exist if(!$user->isLoggedin()) throw new Wire404Exception(); // check if they submitted a password change $pass = $input->post->pass; if($pass) { if(strlen($pass) < 6) { $page->body .= "<p>New password must be 6+ characters</p>"; } else if($pass !== $input->post->pass_confirm) { $page->body .= "<p>Passwords do not match</p>"; } else { $user->of(false); $user->pass = $pass; $user->save(); $user->of(true); $page->body .= "<p>Your password has been changed.</p>"; } } // display a password change form $page->body .= " <h2>Change password</h2> <form action='./' method='post'> <p> <label>New Password <input type='password' name='pass'></label><br> <label>New Password (confirm) <input type='password' name='pass_confirm'></label> </p> <input type='submit'> </form> <p><a href='/logout/'>Logout</a></p> "; include("./main.php"); 4b. Create a page called /profile/ that uses the template above. 5. Just to be complete, make a logout.php template and create a page called /logout/ that uses it. /site/templates/logout.php if($user->isLoggedin()) $session->logout(); $session->redirect('/'); 6. The above templates include main.php at the end. This should just be an HTML document that outputs your site's markup, like a separate head.inc or foot.inc would do, except that it's all in one file and called after the output is generated, and we leave the job of sending the output to main.php. An example of the simplest possible main.php would be: /site/templates/main.php <html> <head> <title><?=$page->title?></title> </head> <body> <?=$page->body?> </body> </html>1 point
-
Ryan, this doesn't return the anything for me. ? echo $page->pdf->pathname; // returns nothing However, I got a little class that works pretty well for download files. Without getting headache. https://gist.github.com/27758821 point