Jump to content

ryan

Administrators
  • Posts

    16,772
  • Joined

  • Last visited

  • Days Won

    1,530

Everything posted by ryan

  1. Since they already have to be translated for the module file, it's unnecessary duplication. Though I'm not opposed to duplication if it makes things simpler/faster for everyone. But since this one is specific to dropdowns in this admin theme (something not in all admin themes), maybe it would be better for it to grab the translated module titles rather than the page titles. Basically like this: foreach($children as $p) { if($p->process) { $info = wire('modules')->getModuleInfo($p->process); $title = $info['title']; } else { $title = $p->title; } echo "<li><a href='{$p->url}'>$title</a></li>"; } The other advantage of this approach is that it works with any modules, not just ones that have been predefined in default.php.
  2. 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.
  3. I think that it would be fine to do it with PW pages, and have been played around with doing it that way myself (and may pursue it further in the future). But Pete is right that since comments are a fixed format, and potentially more vast than your site's content, it's more efficient for them to be in their own tables, separate from PW's pages. And that's the reason why PW's comments are their own thing, rather than pages. However, I think there are plenty of benefits to having them as pages too, but it is a bit of a compromise in efficiency for flexibility. And perhaps a worthwhile one. I'd say go for it. But ideally don't have any crossover with the fields you use for comments, and the fields you use on the rest of your site. That will ensure that the quantity/scale of the fields used by comments doesn't introduce any potential bottlenecks in your site's pages.
  4. There are other ways to prevent a double post, but there are actually a few other reasons why I want to do a redirect after a successful comment submission, so figured that's the method we'd use. That's not to say we might also add another method of duplicate detection though. That's the plan, though Markdown is not anonymous-user safe, unless we can get a version like the one GitHub is using. Both BBCode and Textile provide modes that are anon-user safe, so they would be good candidates to use with a comments field.
  5. The phrases from that screenshot can be translated via these files: /wire/modules/Process/ProcessTemplate/ProcessTemplate.module /wire/modules/Process/ProcessField/ProcessField.module /wire/modules/Process/ProcessUser/ProcessUser.module /wire/modules/Process/ProcessRole/ProcessRole.module /wire/modules/Process/ProcessPermission/ProcessPermission.module Looks like I still need to make the "Languages" one translatable… ironic
  6. That makes sense, I'm fine with switching it from name to label. Though wondering if maybe I should just change it to "Updated %d fields" so that it all goes out in one message (and maybe reserve the individual change lines for debug mode or something).
  7. 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.
  8. 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.
  9. 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>
  10. What does this do? echo $templates->get($page->form_name);
  11. 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
  12. 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.
  13. 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.
  14. 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/
  15. 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);
  16. ryan

    Toolbe.lt

    Thanks for stopping by Toolbelt (and for fixing the Wikipedia link)!
  17. 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.
  18. When I hear ANSI I immediately think of the codes we used to make graphics for our BBSs back in the day.
  19. 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.
  20. 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.
  21. 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.
  22. 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).
  23. 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.
  24. 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.
  25. 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?
×
×
  • Create New...