Jump to content

ryan

Administrators
  • Posts

    17,240
  • Joined

  • Days Won

    1,702

Everything posted by ryan

  1. There was a missing CSS line in one of the files for a few hours last week, and you must have gotten a copy of the source in that timeframe. If you pull in the latest it should fix it.
  2. I don't even use template labels myself, but added them so that multi-language template selection would be more friendly for those that wanted it. Honestly, I start getting confused when I see a template identified as anything other than its name (or filename, if it has one). So while it's not my cup of tea, I'm definitely fine with having a description field with templates and can see why some may want it. I also want to mention that it's a good idea (where possible) to make use of the 'Family' settings for all/most/many of your templates, so that users rarely have to consider anything about templates.
  3. 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>
  4. What does this do? echo $templates->get($page->form_name);
  5. Comments manager is the main one, but some other things I've been planning to add that aren't necessarily tied to a version: addition of an optional website field built-in honeypot spam protection option to auto-redirect after a comment post, to prevent possible double post simpler template integration (1 function call rather than 2) support for textformatter plugins on comment text on comments gravatar support
  6. Are you thinking of something like a "find translatable files" tool that's built in? It could be done, but thinking it would be slow as it'd have to load up potentially thousands of files and scan them for translation functions… it can only scale so far. Whereas a quick grep at the command line can do it a lot quicker. Still, maybe it's worthwhile, as it would be nice to click on the file you want to translate rather than copy/paste the filename into the add file box. Plus also nice to see at a glance which files are new and don't yet have anything translated. Well we don't have to worry about out of date translations because the translation gets abandoned if the original changes. But it's true that incomplete translations are always possible and expected. But this is the nature of the beast, anywhere that translation is done, isn't it? When ProcessWire grows, new translatable copy comes into existence. I can't think of any solution to that problem other than stopping development? Also want to mention that this is one reason why all of ProcessWire's translation tools are dynamic and built-in to the admin control panel itself. If you see something that's not translated, you can get to it with a few clicks and type in the phrase you want it to translate to. Compare that to most any other open source CMS (WordPress, Drupal, etc.) where the translations are handled with GNU gettext and pretty much out-of-reach of the client's reach or understanding. Those translations are dependent upon a 3rd party translator and developer. Whereas in ProcessWire, when a client sees some text that's not translated, and that they want translated, all the tools to do it are right there, ready for them to use.
  7. Not really worried about that. We advertise jQuery "inspiration" not "duplication". But like I say the goal has never been to clone their API… nor would it be logical to, given the very different contexts. Instead, I think the goal should be to make ProcessWire's API as simple, easy and logical as possible for the place that ProcessWire works in. I actually thought that jQuery had quite a sweet spot in their API right around 1.2.6 (or thereabouts). Since that time, I think the balance has shifted a bit towards complexity in complexity vs. power balance. But then again, I'm not a full time jQuery user, so there's a lot in their API that I rarely use.
  8. PawelGIX, I will work on an actions select built-in to the Image Fieldtype perhaps for PW 2.3. But for now, it seems like your module is quite stable and works well. At your convenience, do you think you could post it to the ProcessWire modules directory? http://modules.processwire.com/add/
  9. Glad to hear that shaved off a few seconds! I think the only way to possibly go faster would be with direct SQL queries. Though it sounds like you are dealing with a large quantity of data and the scale is probably going to be a bottleneck no matter how it's done. I'm not sure I know exactly why it's doing that, though I've also never used array[] style in GET vars. But think the simplest solutions would be to either 1) str_replace it to where you need it, or 2) use commas to separate values in the URL rather than repeating the same var[]. For instance: // setting $url = $page->url . '?print=' . implode(',' $print); // getting $print = explode(',', $input->get->print);
  10. ryan

    Toolbe.lt

    Thanks for stopping by Toolbelt (and for fixing the Wikipedia link)!
  11. Everything in admin is specifically excluded from the search results (including users) and has been for a couple months I think. Mainly, I just got sick of all my repeater values taking over my search results. I was mistakenly not thinking about users... I'll change this so that if you specify a template it won't exclude anything from superuser.
  12. When I hear ANSI I immediately think of the codes we used to make graphics for our BBSs back in the day.
  13. You might try creating a new field using the FieldtypeCache type. This isn't installed by default, but it is included with PW, so you'll just need to click "install" from the modules menu. This field essentially keeps the values from several fields in one field, so that they can all be loaded at once as a group. Like all caches, it's creating duplication and trading disk space for speed. These cache fields are also handy if you are building a text searching engine that needs to scan lots of fields at once... your selector can query just the cache field rather than "field1|field2|field3|etc". Once installed, create the new "cache" field, click to its "details" tab and follow the instructions there. Don't make it autojoin. Instead, have your output generation code reference the cache field field (like $page->my_cache) before any of the others that are triggering queries. This should enable you to reduce it to just one query for all those fields. I'll be honest and say I created this fieldtype with many good intentions, but have rarely found it necessary to use. So be certain the situation you describe really is the bottleneck, and that you aren't omitting pagination or accidentally referencing something like $page->children() or $page/s->find() without a "limit=". The reason that I mention it is that MySQL selects are extremely fast, to the point where the difference between autojoin and non-autojoin may require some scale before you can measure the difference. If you are query counting, avoid doing that, as it often doesn't correlate with performance, especially in ProcessWire. (I used to be a big query counter until I read the book High Performance MySQL, which is reflected in PW's DB query approach). One other idea you might look at is temporarily convincing the fields in question at runtime that they are autojoin, before loading your pages: foreach($selectedFields as $fieldName) { $field = wire('fields')->get($fieldName); $field->flags = $field->flags | Field::flagAutojoin; } That's assuming all the fields in question support autojoin. Some fields, like files/images, can't be autojoined and telling it to may cause unpredictable results.
  14. I'm not sure that I understand the specific situation here... read it over a couple times and still can't seem to visualize it. But that could just be because I'm still waiting for the coffee to kick in here. But I wanted to mention that repeaters are nothing but groups of pages. Very often, you are better off to just use your own group of pages to create the same structure, rather than creating a repeater. So you technically could get the structure you are wanting if you go back and use traditional pages to create the structure. Repeaters aren't the place to create particularly complex data structures, but pages are.
  15. ryan

    Minify

    Would probably need to see the specific code block in question--feel free to send along to me and I'll take a look.
  16. Well if you are working in a text editor from the 1960s, then it's a little more tricky. But I found out how to get VIM in UTF-8 mode... just wish it knew how to auto detect it. I don't want to change the encoding on all the core files, but should be okay in specific instances like this install.php. Also sounds like I should change the default profile template files to UTF-8 encoding. Didn't realize they were showing up as ANSI for others--can't say as though I've ever seen that encoding in PW's files. For me they show up as either ASCII or Mac OS Roman with unix linefeeds, though I've always kept the character usage to pure ASCII except in specific instances (like InputfieldPageName.module).
  17. I'm thinking we'd add the same thing to both parents() and parent(), except that parents() would return all matching, while parent() would return the first (closest) one. That way you always know you'll get a PageArray() from parents() and a Page from parent(). I'm not too concerned about maintaining consistency with jQuery, as their context is still very different from ours… different enough that strict adhesion to their API syntax would ultimately be confusing if taken too far in our context. ProcessWire takes inspiration from jQuery where it makes sense, but cloning their API is not the goal. Rather, we want to provide the clearest API for ProcessWire within our context, regardless of what jQuery is doing. The environments they operate in are very different. In terms of how you work with it, ProcessWire probably has more in common with YUI3 than jQuery, given the more specific single vs. multiple types in YUI3. But I still prefer jQuery as our syntax starting point, rather than ending point.
  18. I could maintain a default translation pack on GitHub, which already has all the files in it (empty, ready for edits). That way, someone could just upload that to start a new language translation, or easily see what's been added (or more rarely, moved or deleted) via the commit history. This would only be necessary for the files themselves, as the LanguageSupport modules are already telling you of changes to the translations. But I'll be happy to maintain this if you guys would find it useful. This is a rare occurrence in the core. In this particular instance, we needed to add a CSS file to InputfieldRadios. That module wasn't in it's own directory before, so it had to be moved into one. The translation file would probably have to be renamed to reflect the updated location. While abandoned translation files should be rare in the core, a detection for it may still be worthwhile, especially for 3rd party modules since you wouldn't need to keep around translation files for a module that was no longer installed. There have only been two translatable files in the core moved in the last year that I can think of: InputfieldPage.module and InputfieldRadios.module. Again, this should be a rare occurrence. But another good reason for me to keep a master translation on GitHub, so there is a place where a translator could more easily keep track of it. This one may be easy for us to accomplish if we just say that a translation with nothing but a period "." in it might be considered intentionally empty, or something like that. Then I can add a bit of code to detect it and have the parser fall back to the default text when it sees that. The core on the master branch is always kept in a stable state, though individual modules may be kept in an alpha/beta stage. When the core is not in a stable state, I keep it in a separate dev branch (still on GitHub). Someday we may tie all updates to big versions, but for now, when something is ready to use or something is fixed, I like to make it available for people as soon as possible. There shouldn't be any side effects. If any text in a translation changes, then it's considered abandoned, regardless of what version. If the text stays the same, then it's considered still good, regardless of version. The translations are tied to a hash of the default version as it appears in the PHP source files, so there's no potential of the wrong information to ever be sent via the translation. Version mismatches between the original and translation are technically impossible. Upgrades shouldn't touch your translations. This is one of the reasons why translations are kept as part of your /site/ structure rather than your /wire/ structure.
  19. ryan

    Toolbe.lt

    Thanks for adding that Diogo. The wikipedia link at the bottom is broken: Processwire vs. ProcessWire -- I guess case matters for Wikipedia. I tried to fix it, but it's the one thing that apparently isn't editable, at least I couldn't find a way to fix it?
  20. I've just made that function public, so should appear in the source shortly. But I'm thinking Soma's jQuery solution seems like a pretty great one.
  21. This is definitely still on the to-do list. Schedule's been tough here lately (been out of town on the weekends), but should be able to give this a closer look hopefully this week.
  22. You could keep a separate install directory like /src/, with a blank/uninstalled copy of ProcessWire. And then have your live /wire/ a symlink to /src/wire/. The /index.php and /.htaccess change very rarely, so those I would just replace manually when called for. You don't want an uninstalled copy of PW to be web accessible to anyone but you. To keep people out of the /src/ directory, you might rename it to be /.src/ (PW blocks access to any dirs beginning with a period) or place it somewhere else, non web accessible.
  23. In the blog profile, I tried adding a new post under /posts/, and the family there is configured to limit it to that template (posts template only allows children of post, and post only allows parent of posts). But can't seem to duplicate this. I'm wondering if the scenario you had was a little different or maybe involved user access or something else? Either way, I'm thinking I can setup the Inputfields to not generate an error for any required fields that have a disabled attribute set, but just wanted to make sure I had a repeatable test case so that I could confirm when it is fixed.
  24. There isn't yet a dedicated multi-language image field, like there are multi-language text fields. So you'd probably want to use a repeater for multi-language captions with images, like you mentioned.
  25. I have to admit, I kind of liked the buttons appearing when I rolled over each image field. Assuming there is repetition (i.e. lots of images), I think it's better than having them visible for all images at once (whether the buttons or small icons, etc). That would be a lot more furniture on the page, when it's something you'd only use for 1 image at a time. So this may be more subjective than bad UI vs. good UI. When reasonable, I often prefer things to show themselves when they are in context or focus and stay out of the way when they are not. But it's good to read the different preferences here, because it seems like we would all agree on the value of an actions menu. Are you guys thinking just a right-aligned select box in each image, like this? There was also this setup in ProcessWire 1.x: Last, there was also this setup in Dictator (PW from 10 years ago) where you would select one or more images and then choose an action from the menu:
×
×
  • Create New...