Jump to content

ryan

Administrators
  • Posts

    16,459
  • Joined

  • Last visited

  • Days Won

    1,456

Everything posted by ryan

  1. Edit /site/config.php and set $debug = true (located near the bottom of the file). Then try that again and you should get an error message. I'm going to try here too. What version are you using btw? 2.0 (stable) or 2.1 (dev) ?
  2. I missed it the snippet you pasted before, but PHP is right, $contactForm is not a variable. It should be $form instead, i.e. $form->render(); It looks like my example at the top of the module file is incorrect (sorry about that). But if you replace that $contactForm with $form, that should solve it. For your hidden field (contactPage), add it to your form template as a text field. But hide it from your stylesheet so that it doesn't appear in your form (even though it's still technically there).Then I think you'll want to populate the value into $input->post manually before rendering the form, i.e. <?php $input->post->contactPage = $page->title; $form = $modules->get('FormTemplateProcessor'); ... As a side note, since your contactPage field is hidden by your stylesheet, you could do this: <?php if($input->post->contactPage) { // if this field is populated right now, it's very likely spam since a live user never would have seen it // but automated spam bots don't usually look at stylesheets to see if a field is visible $session->redirect("/"); // redirect spammer to homepage } $input->post->contactPage = $page->title; $form = $modules->get('FormTemplateProcessor'); ... I haven't tried these examples, but think they should work. I should also mention that this module was really designed just as a proof-of-concept, rather than a full solution. It's somewhat bare and intended as a starting point for you to modify for your needs or build-upon. In most cases, I just build and process forms the old fashioned way in my own sites... can't beat the flexibility. But we'll be improving the form tools in ProcessWire more and more.
  3. Good call. The admin theme stuff is bundled in with the modules forum, and really deserves it's own. But I'm thinking "Admin Themes and Customization" (or something more along those lines) is the terminology we should use for this. To me the term "hacks" implies modifying core code or modifications outside of what the system is built for, and that's not something I want to encourage people to do just because it gets overwritten on upgrades.
  4. I think you are right about having both buttons. There are actually several different actions you might want to take after saving a page. These are the ones I could have used at some time or another: - Save and continue editing (like now) - Save and close (return to list) - Save and view - Save draft and preview - Save and add another sibling (useful when you need to add a bunch of select options) I'm thinking we'll keep the default with as few buttons as possible (perhaps only save, to keep things simple), but work towards making the system configurable so that you can control what buttons you have (whether by modules like Adam's, built-in config options, or a collapsed field below the buttons where you can adjust and save your own setting).
  5. I like your idea of the FieldtypeValueKey! But if you needed to do something really quickly, here are two other options to consider: 1. Use polldaddy and be done with it. 2. OR: Use pages: Templates: - poll_question (fields: title) [set required child template to be poll_answer] - poll_answer (fields: title, total:integer) Pages: - poll_question: title=Choose what describes you best: - poll_answer: title=Awesome - poll_answer: title=Smart - poll_answer: title=Polite Here's one way the poll_question template might work (written in the browser, so please excuse errors). But this might have similarities to how you'd implement it with a Fieldtype too. <?php // display the question echo "<h1>{$page->title}</h1>"; $displayResults = false; if($session->get("poll" . $page->id)) { // if they already answered the poll this session, just display results $displayResults = true; } else if($input->post->submit_answer) { // if answer submitted, save it $answer_id = (int) $input->post->answer; $answer = $page->child("id=$answer_id"); if($answer->id) { $answer->total = $answer->total + 1; $answer->save(); } echo "<p>Your answer was saved.</p>"; // save the poll ID in session to remember they already did it $session->set("poll" . $page->id, true); $displayResults = true; } else { // they haven't answered the poll yet, show the form: echo "<form action='./' method='post'>"; foreach($page->children as $answer) { echo "<label><input type='radio' name='answer' value='{$answer->id}' /> {$answer->title}</label>"; } echo "<input type='submit' name='submit_answer' value='submit' />"; echo "</form>"; } if($displayResults) { // display the poll results $allTotal = 0; foreach($page->children as $answer) $allTotal += $answer->total; echo "<h2>$allTotal people responded to the poll:</h2>"; foreach($page->children as $answer) { $percent = round(($answer->total / $allTotal) * 100) . "%"; echo "<p>{$answer->title}: $percent</p>"; } } Then, in the template where you want to display the poll: <?php $poll = $pages->get("/path/to/poll/you/want/"); echo $poll->render(); I know you know how to do all this, so this example is just for fun (and procrastination on another project, hehe) and and I'm sure you have something better in mind. But I'm particularly interested in learning more about the FieldtypeValueKey you mentioned. Thanks, Ryan
  6. $page->render() isn't listed in the Page API right now because I've not used it much beyond rendering the requested page (one page per request). But it should also be fine to call from your own code, and should be able to render as many pages as you want it to in one request. I will be adding this to the API in the future once tested in more contexts, so it's not going anywhere. It's not been tested much in the context you are asking about, so please let me know if you run into any issues with it, and we should be able to resolve them quickly. If you view the PHP source (/wire/core/Page.php), you won't find the render() method in the Page class because it's added by a module (/wire/modules/PageRender.module). There aren't any arguments to this function, so nothing to it other than calling $page->render(). This render method is available on all Page instances (like the pages returned from a find() for example). If you are rendering pages in this manner, and the templates used by those pages are defining functions or classes (whether in your template or by including them from another file), PHP may throw a fatal error about duplicate definitions. As a result, your template files should include files that have function/class definitions in them with include_once() or require_once() rather than include() or require(). If functions are defined directly in the template file (as opposed to include files), you'll want to use PHP's function_exists() function to check if your function already exists before defining it again. For regular header/footer includes, you would want to continuing using include() or require() since you want them rendered on every page you call the render() method for. It's only the ones where you are defining functions/class that you have to consider. Many people don't make their own functions and classes, so it may not be a consideration at all, but I just wanted to mention it.
  7. Your code looks right to me, as do the steps you mentioned. When you say it's not working, can you describe more? Do you ever see the form that it outputs? Or is it just that you never get an email? I'm not clear about where it stops working. I also suggest editing /site/config.php and temporarily setting $config->debug = true (near the bottom of the file). That will ensure that you see error messages during development. Also, if you have a URL where I can see it in the context of the rest of the page, that may help (and feel feel to PM it to me if you prefer not to post here).
  8. It sounds like there must be a bug somewhere if the table was incorrect in the first place. That helps to know that the rebuild fixed it. The only place this table gets populated is in the Pages::saveParents() private function, and that function is only called by the Pages::save() in certain conditions. Meaning, if there's a bug, it's probably confined to the logic in a few lines of code, which should make it relatively easy to fix. The only thing that makes it difficult is that this has not turned up before, so it may be something that only occurs under rare conditions. I'm going to take a closer look at this and see what I can find. If you encounter the Page::find() producing incorrect results again, please let me know, and I'm going to try and duplicate here too. Thanks, Ryan
  9. Those two should return the same thing, except that the first example wouldn't include the homepage (if that was part of your results). I'm testing the same thing locally, but getting the expected result -- same pages are returned from both. Hard to tell what might be the problem. What are the results from the second call? Getting different results from the get("/")->find(...) could mean something is amiss in the pages_parents table and point to a bug somewhere. PW manages this pages_parents table as a way to execute finds within a specific part of the tree. To test if there might be a problem with the table, you can force PW to rebuild it by doing this trick: $home = $pages->get("/"); $home->trackChange('template'); $home->forceSaveParents = true; $home->save(); Then try the two find operations again. Is there any change?
  10. If the above doesn't fix it, this might: Get rid of the beforePageRender hook that sets the template filename, and move it into your init() function: $template = $this->templates->get("adminbar"); if($template) $template->filename = $this->config->paths->AdminBar . "templates/sitemap.php"; I think this would work in either version of PW, though have not tested. The reason I think this might fix it is because this would set the template's filename much earlier than it currently does (well before PW would have any opportunities to check whether the sitemap page is viewable). So theoretically, this should prevent it from deciding that the page isn't viewable due to lack of a template file.
  11. I'm thinking the problem might be in wire/core/Template.php. It caches the state of whether the template filename exists. But it wasn't resetting it when the value of filename was changed. PW will only display a 404 for a page that exists to the superuser when there is no template to render the page. AdminBar appears to be setting the filename, but PW still thinks it doesn't exist because the previous "non existing" value was cached. I'm thinking this is it anyway. If you grab the latest /wire/core/Template.php from the PW 2.1 source, does this make a difference? I will also test locally later today, but wanted to get this posted before a call, hoping this was it. Thanks, Ryan
  12. You could do this in the same way as described in the other message, and give each partner their own role. But if you are dealing with just one user account per page, and the editing needs are simple, I'm not sure I would even bother with giving them admin access or any built-in page editing permission. Instead, do your own access control in your site's template. Give them their own role "partner", but with nothing but page-view access. Then some code like this in your "partner" template would be enough to determine if they can edit the content that's on their own page: <?php // if user is a partner and user and page have the same name, we'll let them edit it if($user->name == $page->name && $user->hasRole('partner')) { if($input->post->submit) { $page->setOutputFormatting(false); $page->content = $input->post->content; $page->save('content'); $page->setOutputFormatting(true); } // edit content echo "<form action='./' method='post'>"; echo "<textarea name='content'>{$page->content}</textarea>"; echo "<input type='submit' name='submit' value='Save' />"; echo "</form>"; } // display content for everyone echo "<div id='content'>{$page->content}</div>"; The example above assumes the field "content" is a textarea field that has at least the "HTML entities" formatter applied to it in the field settings. I think this is simpler then giving them admin access for such a specific need. But if you were dealing with lots of fields and of lots of types, then using the ProcessPageEdit does become a more compelling solution.
  13. This is one area where there are significant differences between PW 2.0 and 2.1, though both versions use a role-based access control system (RBAC). Here's how you do it in either version: 1. Create client role and assign permissions The first thing you'll want to do is create a role for your client, called "client".These are the permissions you'd assign to your "client" role in 2.0: ProcessPageView ProcessPageEdit ProcessPage... (any other Page permissions that you want them to have) ProcessHome* ProcessList* ProcessLogin* ProcessLogout* The permissions listed above with an asterisk (*) are assumed in 2.1, so you don't have to specify them in 2.1. These are the permissions you would assign to the "client" role in 2.1: page-view page-edit page-* (any other "page-" permissions that you want them to have) 2. Create users and give them the client role Now you have a role called "client" and it has most page editing permissions. Next you have to assign that role to some users. So you should create new users for your clients (or use existing users) and add the "client" role to them. 3. Assign the client role to the pages they can edit You've got the "client" role and users added to that role. But those users still can't edit any pages. In order to give them edit access, you have to assign the "client" role to the pages the client can edit. On a large site this isn't practical on a page-by-page basis, so you will likely want to assign roles in a manner that affects multiple pages. This is the area where PW 2.0 and 2.1 differ the most. 3a. Assigning roles to pages in ProcessWire 2.0 In PW 2.0 you assign a role to a page, and any children inherit that role setting. That role inherits down through the tree to children, grandchildren, great-grandchildren, and so on. You can also remove that added role from any of those children (grandchildren, etc.) and that will likewise be inherited in the same way. This resembles how permissions inherit on a file system through a directory structure. In the case of your /news/ page, you would want to go ahead and edit that page and add the "client" role to it (on the page's settings tab). The client can now edit the /news/ page and any children. Note that you may not necessarily want them to be able to edit the actual /news/ page (as opposed to it's children)... unfortunately that's not an option in 2.0 unless you want to add roles to the news-items on a page-by-page basis. 3b. Assigning roles to pages in ProcessWire 2.1 In PW 2.1, you no longer assign roles to individual pages. Instead you assign them to templates. So you will want to assign the "client" role to your "news-item" template. If you also want them to be able to edit the actual "news" page, you can add the "client" role to your "news" template. But I'm guessing you only want them to be able to edit the news items, and not the actual news page. Assuming you added the "client" role to just your "news-item" template, the client can now edit any news item pages. In either of the above cases, the client can't edit anything other than what you assigned to them. That client can edit "news-items" (and possibly the /news/ page), but they can't edit anything else in the site. 4. Hiding pages from the client role If you want a page to be completely hidden from your client, they have to lack view access to it. In your case, I'm assuming we're talking about a branch to hold special types of data (banners, etc.) that isn't typically rendered as pages. Lets say these pages are located under /tools/, and you want that section to be invisible to anyone except the superuser. In PW 2.0, you'd remove ALL roles from the "/tools/" page. In PW 2.1, you'd remove ALL roles from any of the templates used by pages in the "/tools/" tree of pages. If you still had some roles that you wanted these pages to be visible (like an "editor" role, or the like), then you would keep that role assigned, but remove all the others. Now only the superuser can see those pages, and the client won't see them in the admin. You can still pull data from these pages via the API as much as you'd like. 4a. Letting roles inherit in 2.1 PW 2.1 also gives you the option of having roles inherit through pages (like they do in 2.0), which you might want to do if pages in your /tools/ section are using various different templates. In that case, you'd set those various templates to "not manage access" (under each template's "access" tab). And you'd remove all roles from whatever template is being used by your main /tools/ page (we'll assume it's called your "tools" template). Now all access to your /tools/ pages is managed in one spot. 4b. Tell PW 2.1 to automatically exclude pages from search results If you are using PW 2.1, you might also want to check the box for the setting on the "tools" template that tells it to exclude pages from search results when the user doesn't have access to them. That way you won't have to worry about any of those pages showing up in any search engines you build for your site. (You couldn't do this in 2.0, instead you had to filter these yourself). Automatically excluded pages and the API Pages that a user doesn't have access to, and that are excluded from search results (as outlined above) are automatically excluded from $pages->find, $page->children and any API call that returns multiple pages. From the perspective of your API call, this is identical to the behavior of pages that have a "hidden" status. This is desirable for most of your site, but maybe not when you are trying to pull multiple banners from /tools/banners/ with a $pages->find. You can cancel that behavior for your API call by adding a "check_access=0" selector to your API call, i.e. $banners = $pages->find("parent=/tools/banners/, limit=3, sort=random, check_access=0"); That "check_access=0" essentially tells it to ignore whatever access the current user has. You don't need to do this with API calls that return single pages (like $pages->get) because such filtering is more of an annoyance than a help on such specific calls. It also maintains consistency with the behavior of pages with a "hidden" status -- they are automatically excluded API functions that return multiple pages, but not those that return single pages.
  14. Almonk posted a great article on his approach to building multi-lingual sites with ProcessWire: http://codeordie.posterous.com/multi-lingual-sites-with-the-processwire-cms
  15. I'm not at a place where I can look in the code right now, so I'm going to go back and do that later. But initially I'm thinking that Apache took over this request: /ot/processwire/&modal=1 ... because there is no "?" in the URL So it's not a valid URL, at least not one that PW will get. Do you know if PW or AdminBar generated that URL? I'm guessing PW since AdminBar works in 2.0, but just wanted to check if you knew. The error message you posted was from Apache rather than PW, because PW excludes itself from getting URLs it doesn't understand via it's htaccess file. Also in 2.1, $pages->find() and $pages->children(), etc. exclude pages that you don't have access as an option in each template's settings. You can reverse that behavior in a selector by adding: "check_access=0" to the selector. I don't think that's the case here, but just wanted to mention this option.
  16. It's probably a good way to show people how selectors are used. And someone could just copy/paste the resulting selector and use it in their own code if they wanted to. It used to be that it only showed the selector when in debug or advanced mode (like in 2.0), but since selectors are such a common thing in PW, it probably makes sense to show them all the time. I agree with you. The quick links are great though. We have to think of where they should go. Perhaps they should stay where they are (but configurable with the module), or perhaps they should be built into an admin theme? Seeing the most recently edited/added pages like you had is particularly useful. I agree, this will be a good addition. I will plan to convert them to asmSelects (or some other multi selection widget) where applicable. Thanks, Ryan
  17. Almonk--thanks for the update!
  18. Nice job. Just tested this and looked at the code. This is very well put together! I also like how you made it configurable. Also, I tested and it works equally well in 2.0 and 2.1. Your module is so nicely coded that I have one suggested optimization to make it even better. That would be to add more conditions before adding hooks. This is so that your hooks don't get added when they aren't applicable, like on the public side of the site, or when a user isn't logged in. Your module already accounts for that, but only after the hooks have already been put in place. Page::loaded can be an expensive hook (it gets called for every single page loaded in memory in the request, which could feasibly be hundreds of calls). So it's desirable to be selective about when you add a hook to it, as you can save some CPU cycles by not adding that hook when you don't need it. The init() function can't tell anything about the current $page simply because modules are init'd before PW even tries to handle the page request. So a good strategy is to have your init() just determine if your hooks will possibly be useful to the current user. If it's a guest user, there's no point in even adding hooks. But if it's not a guest user, then your hooks may be useful, depending on what the current $page->process is. Since we can't tell anything about the $page yet from init(), just delay the decision till Page::render, like this: <?php public function init() { // if there is no logged-in user, don't bother continuing if($this->user->isGuest()) return; // if the user is logged in, add a hook before Page::render // which will determine whether to add more hooks $this->addHookBefore('Page::render', $this, 'pageRender'); } public function pageRender(HookEvent $event) { // modules are init()'d before the page is loaded // so we couldn't check the value of page->process from init() // that's why we're doing it here instead. // this checks to make sure that we are in the admin and on a Process we wish to hook if(in_array((string) $this->page->process, array('ProcessPageEdit', 'ProcessTemplateEdit', 'ProcessField'))) { // hook before a redirect occurs, so we can modify the redirect URL: $this->session->addHookBefore('redirect', $this, 'sessionRedirect'); if($this->page->process == 'ProcessPageEdit') { // hook after the page has been loaded and modify the breadcrumbs array $this->session->addHookAfter('Page::loaded', $this, 'breadcrumbsEdit'); } } }
  19. Thanks, I have updated my source trees to have the same update as yours, and will push to GitHub tomorrow. And thanks for the feedback on ProcessWire, glad you are finding it useful--at least, now that we can get it to create pages. Ryan
  20. Btw, if we find that swapping the order of translit//ignore doesn't do it, then I'm going to modify the source to ignore the return value if it's blank, and instead use the value pre-iconv instead. That way it should ignore the iconv() on systems where it fails, but continue to use it where it doesn't. This is the first instance I've seen where it fails, but what turns up once it bound to turn up again. So while this sounds like a rare problem, I doubt it's unique to your server.
  21. Thanks for testing that. It looks like the iconv() is the culprit then. The strange thing is that I just compared my phpinfo() to yours, and our iconv() versions and settings are identical. Looking on php.net, it sounds like some people are reporting strangeness with iconv when combined with "//TRANSLIT//IGNORE" in some rare instances. But they were able to solve it by swapping the order to "//IGNORE//TRANSLIT". Do you want to try that? Replace: $value = iconv("UTF-8", "ASCII//TRANSLIT//IGNORE", $value); With this: $value = iconv("UTF-8", "ASCII//IGNORE//TRANSLIT", $value); If that doesn't do it, then then you can remove that line entirely. It's only there to provide better translation of accented characters and such, and it's not required. If you take it out, it'll just replace unknown characters with dashes rather than trying to translate from UTF-8 to ASCII.
  22. That's interesting. So it sounds like it's failing in the Page::set() method. In this part near the top: case 'name': if($this->isLoaded) { $beautify = empty($this->settings[$key]); $value = $this->fuel('sanitizer')->pageName($value, $beautify); if($this->settings[$key] !== $value) $this->trackChange($key); } $this->settings[$key] = $value; break; Following the path of calls, Sanitizer::pageName() is the next place to look. It's in the file /wire/core/Sanitizer.php. I've got my eye on these lines: if($beautify) { $value = iconv("UTF-8", "ASCII//TRANSLIT//IGNORE", $value); } $value = strtolower($this->nameFilter($value, array('-', '_', '.'), '-')); Do you want to try removing or commenting out those lines and seeing if it makes any difference? I'm especially wondering about the iconv(), and if it might be returning something different on your server.
  23. Was the die($this->page->name) placed after this line? $this->page->name = $name; For example, I'm wondering what this would do: $this->page = new Page($template); // existing lines $this->page->parent = $this->parent; $this->page->name = $name; var_dump($this->page->name); die(); // add this line right after the above Trying to determine if $this->page->name is "0" after specifically setting it.
  24. I got a look at your phpinfo and nothing jumps out as a known problem (versions look good, etc.). It's a mystery so far. I've seen this problem when the PHP version was less than 5.2.4, and that's one of the reasons why that's the minimum version required by PW. But you are running 5.2.17, so no problem there. If you want to set me up with a temporary PW superuser login and FTP, I will be glad to go in and find where exactly the problem is. My email is ryan at the domain name of this site. Or if you prefer, I can tell you how to debug it yourself. We should be able to find out where it's happening relatively easily since it's apparently either in ProcessPageAdd::processInput() or Pages::save(). So it's just a matter of inserting: "die($page->name);" until we find the location where it's changing from the actual name to "0", and there aren't many lines of code to test here. I'm confident we'll be able to find a fix.
  25. The field names look fine. In the past there have been a couple of reserved words that I'd forgotten to reserve in the system, so just wanted to make sure we weren't running into something like that. I will keep an eye out for your phpinfo and then reply here as soon as I get a look at it.
×
×
  • Create New...