Jump to content

ryan

Administrators
  • Posts

    17,151
  • Joined

  • Days Won

    1,668

Everything posted by ryan

  1. It's getting near the end of the work day and I'm forgetting crucial details. To read this values, they will be automatically set in your AdminBar instance. So anywhere in that class, you should be able to just reference it like: $this->showModal, and so on. If the value is not set or doesn't exist, it will just be null. If that's the case, then you should use some default value, because it means the module has never been configured. Or you could set them up in a __construct method. The constructor is of course executed before PW2 sets any values to the module. Whereas the init() method is called after PW2 sets values to the module. So you might setup your defaults like this: public function __construct() { $this->showModal = true; } No need to define a separate showModal var in your class, because WireData is already handling that for you behind the scenes...
  2. Sorry, my bad. I learn something new every day. I'm admittedly ignorant on this matter (I live in the US, in backwoods Georgia, after all). Given what you've mentioned, I'm adding a new $config->dateFormat to the PW2 source. What do you suggest would be a good default? Something universal doesn't exist, but what would be the closest to something universal to serve as a default? I would like to talk more with Adam and you about more localization options for PW2 (maybe we can start a new thread soon).
  3. There isn't. But the current practice is to use either SQL date format in places where the date need to be a fixed length and/or sortable with other dates (like in a table), and to use "January 27, 2011" or "Jan 27, 2011" format anywhere else. I believe these formats are fairly universal, though correct me if I'm wrong. This is to be determined, but on the roadmap. I think that Adam is giving this some thought, as am I, and all suggestions are welcome. Thanks, Ryan
  4. Sorry about the double post. This is probably the only forum I've ever used, so I don't know what the etiquette is. Consider me new to this. Okay to make your module configurable, modify the class definition and add "ConfigurableModule" to it: <?php class AdminBar extends WireData implements Module, ConfigurableModule { To implement this interface, we need to add a module configuration function to your AdminBar class. It takes one parameter, which is an array of data (that ProcessWire provides to it). If the module has been configured before, that will contain the settings in simple key = value format. It expects you to return a value of type InputfieldWrapper(). Since that is only documented in the source right now, I wanted to get you started with an example: <?php static public function getModuleConfigInputfields(array $data) { // this is a container for fields, basically like a fieldset $fields = new InputfieldWrapper(); // since this is a static function, we can't use $this->modules, so get them from the global wire() function $modules = wire('modules'); // set some defaults if the values aren't already present if(!isset($data['showModal'])) $data['showModal'] = 1; // default to checked if(!isset($data['initCollapsed'])) $data['initCollapsed'] = 0; // default to unchecked if(!isset($data['administration'])) $data['administration'] = wire('config')->adminRootPageID; // default to admin page // showModal field $field = $modules->get("InputfieldCheckbox"); $field->name = "showModal"; $field->label = "Show modal box?"; $field->value = 1; $field->description = "Whether edit opens modal box or goes to administration."; $field->attr('checked', !empty($data['showModal'])); $fields->add($field); // initCollapsed field $field = $modules->get("InputfieldCheckbox"); $field->name = "initCollapsed"; $field->label = "Init collapsed?"; $field->value = 1; $field->attr('checked', !empty($data['initCollapsed'])); $fields->add($field); // administration field $field = $modules->get("InputfieldPageListSelect"); $field->name = "administration"; $field->label = "Where to go after clicking on 'administration'"; $field->value = $data['administration']; $fields->add($field); return $fields; } Once you've put this in there, you can go configure your module in the admin by clicking "Modules" and then clicking on your AdminBar module. You should now see the fields ready to configure.
  5. Let me know what settings you want to start with, and I'll paste in an example for your settings.
  6. Page::loaded isn't what you want. That is called after every page finishes loading it's initial data and is ready for API use. It doesn't mean that the page is loaded in the browser, just that it's loaded in memory on the server. This is what you would use if you wanted to examine or modify some value on every page that gets loaded before anything else accesses it. Maybe I should rename this hook to be "ready" rather than "loaded"? Very cool!!
  7. The reason your snippet doesn't work is because you are trying to set the page's parent to be a string. You actually need to set the parent as a Page object, so you'd need to retrieve the page and then set it to be the parent. However, even if you did that correctly, you need to be concerned about the security of this. Make sure you define what are the allowed/valid parents. You don't want someone manipulating the posted values and then adding pages in the wrong place. I would suggest mapping your valid parents to numbers, which are simpler to validate from a post. You should never put user-submitted values into a selector unless you've validated/sanitized them first. Or better yet, map them like we do here: <?php $categories = array( 1 => '/form-results/', 2 => '/categories/something/', 3 => '/categories/something-else/', ); if($input->post->category) { // get the parent page (category) and save the form $n = (int) $input->post->category; if(isset($categories[$n])) $category = $categories[$n]; else $category = $categories[1]; // default $parent = $pages->get($category); // now that you have the parent, you can save the form like in previous examples } else { // draw the form and category selection echo "<select name='category'>"; foreach($categories as $n => $category) { echo "<option value='$n'>$category</option>"; } echo "</select>"; // print the rest of the form }
  8. That's a good point about .htaccess–I will make a point to mention that when moving this over to the install and/or requirements directions.
  9. Adam, just sent you an email and attachment. I think sometimes my emails don't get through (maybe because of attachments), so just let me know if you don't get it.
  10. Vanilla forums is originally what I wanted to use... and I tried to hard to get it working. I installed locally and seemed to encounter a lot of odd bugs. It worked, but it was not stable. Then downloaded another fresh copy and tried to install to the server, and couldn't even complete the install. Rather than spend days trying to get it working, I gave up on it. Granted it's code looks a lot cleaner than SMF's, but SMF "just worked" right out of the box. I probably need to tweak the theme more, but I'm reasonably happy with SMF so far.
  11. This is really looking great. As for name, it sounds like you've got a lot of good options. I might suggest something that involves "overlay" just because that term is already familiar to many people with Drupal 7 using it. I also liked the "adminbar" term just because it's so simple and says exactly what it is (could also be something like "editbar"). Probably less technical sounding is better, because a term like "modal" means something to us, but it's far from common language (at least here). But regardless of what name you choose, this is shaping up to be a really cool module.
  12. Most often the navigation structure of a site lines up pretty closely with your page structure. For example, your top navigation might consist of your root level of pages (those having the homepage "/" as their parent). And those in the sidebar might be under some section like /tools/. So the way you'd print you top nav would be like this: <?php $topnav = $pages->find("parent=/"); // OR $pages->get("/")->children(); foreach($topnav as $item) { echo "<li><a href='{$item->url}'>{$item->title}</a></li>"; } Then your subnav: <?php $subnav = $pages->get("/tools/")->children(); // OR $pages->find("parent=/tools/"); echo $subnav->render(); // OR output them manually like in $topnav But lets say that your site structure doesn't lend itself well to this. What you might want to do is add a checkbox field to your template so that you can mark what pages should appear in the nav. For instance, you might add a field called "toggle_topnav" and another called "toggle_subnav". When you edit the page, you would check the box for one or another if you wanted it to appear in the navigation. Then you'd get your $topnav and $subnav like this: <?php $topnav = $pages->find("toggle_topnav=1"); $subav = $pages->find("toggle_subnav=1"); And you'd output them using whatever manner you prefer (examples above). Lastly, don't be afraid to hard-code navigation markup. If it's something the client doesn't need to change, it is more efficient to hard-code it rather than generate it dynamically.
  13. This is the same situation as my last post. This was taken out last minute. Though I believe the implementation for this actually still is in place (just disabled). There are a few reasons for this. Changing a pages template to one that had required fields that didn't exist in the previous template resulted in lots of ugly error messages. Easy enough to fix, but I figured this was non-crucial and something I could get back to later. The other part was that I hadn't yet implemented the required option for some of the more complex fieldtypes, and wanted to put more time into it. Lastly, required fields drive me nuts (I have a strange workflow). But I recognize the need and you can count on this one coming back.
  14. Adam is right that there is no default value yet. I agree it should be there, and it's in the Fieldtype module's interface to support it. But it's not implemented in the core. This is a side effect of this being a new project, and some non-crucial details like this are missing (though, this particular one used to be there). The way I usually handle defaults is from the template side. If something has an empty value, then (depending on the field and situation) I will output a default value. The advantage is that there aren't a lot of repeated default values in the DB. But that's too much of a compromise, so default values will be coming. This is one of those things I had in there for awhile, and then took it out to think about it and revisit it later.
  15. It's looking great!
  16. That was fast! Glad it's working. For the next step (keeping it modal), I pushed a couple updates to GitHub today to aid in doing that (made a few more things hookable). So make sure you've got the latest commit. Now we want to hook into a couple more things to modify the form URL and redirect URL, like you did by editing ProcessPageEdit, but we want to do it in a way that doesn't require changing anything in the core. So here is the full skeleton module code from before, but with the addition of two new hooks. Note that I didn't add as many comments to the new stuff, because I have to go pick up my daughter from school, so please reply with any questions: <?php class AdminBar extends WireData implements Module { /** * This is where you define some basic info about your module. * * See /wire/core/Module.php for definitions of all these. * */ public static function getModuleInfo() { return array( 'title' => 'Admin Bar', 'summary' => '[summary of your module], by apeisa', 'href' => 'http://processwire.com/talk/index.php/topic,56.0.html', 'version' => 100, 'permanent' => false, 'autoload' => true, 'singular' => true, ); } /** * Initialize the module and setup hooks * * The init method of a module is called right after ProcessWire is bootstrapped, when all * API vars are ready. Whereas the __construct() is called DURING bootstrap, so the init() * method is a better place to attach hooks to API vars. * * In this method, we'll use an 'after' hook since we want to modify the output of the * rendered page template. * * Note also that the 'Class::method' syntax means it hooks into ALL Page instances. * The syntax for hooking to a single instance would be: * $page->addHookAfter('render', $this, 'pageRender'); * * Also note that there isn't actually a Page::render method, it was instead added by * another module (wire/modules/PageRender.module). Not that it matters here, but just * wanted to mention in case you look in the Page class and don't see a render method. * */ public function init() { // modify the output of a page render, adding some markup to support the adminbar $this->addHookAfter('Page::render', $this, 'pageRender'); // hook before forms are rendered, so that we can modify the form's "action" attribute $this->addHookBefore('InputfieldForm::render', $this, 'formRender'); // hook before a redirect occurs, os we can modify the redirect URL $this->session->addHookBefore('redirect', $this, 'sessionRedirect'); } /** * Hook called when a page is rendered * * The method name used here does not matter, it just has to be consistent with the name you provided * when creating the hook. * * This method is given an $event object of type HookEvent. To see what's in that, see this file: * /wire/core/HookEvent.php (it's very short and simple) * */ public function pageRender($event) { // $event->object always has the object instance that resulted in this call $page = $event->object; // if the page isn't editable, or if it's using the admin template, abort. if(!$page->editable() || $page->template == 'admin') return; // find the location of this module for linking css and js files $url = $this->config->urls->AdminBar . "AdminBar"; // the css and js links we're going to add $out = "\n\t<link rel='stylesheet' type='text/css' href='$url.css' />" . "\n\t<script type='text/javascript' src='$url.js'></script>" . "\n</head>"; // modify the value returned by $page->render() to include our css and js files $event->return = str_ireplace('</head>', $out, $event->return); } /** * Hook to take place before forms are rendered * * We check if there is a 'modal' get var set, and if so, we add it to the form's action attribute * */ public function formRender($event) { if(!$this->input->get->modal) return; $form = $event->object; $action = $form->attr('action'); $action .= (strpos($action, '?') !== false ? '&' : '?') . "modal=1"; $form->attr('action', $action); } /** * Hook to take place right before a redirect occurs * * We intercept the redirect URL and modify it to add 'modal=1' to the query string * */ public function sessionRedirect($event) { if(!$this->page || $this->page->template != 'admin') return; if(!$this->input->get->modal) return; $url = $event->arguments(0); if(preg_match('/[?&]modal=/', $url)) return; $url .= (count($this->input->get) ? '&' : '?') . "modal=1"; $event->arguments(0, $url); } } Lastly, I should probably have the core look for a modal attribute and keep it going when it finds it (because this has use elsewhere), but I thought this was a really good example of how to implement a module, so figured we would start here.
  17. Another easy way you can upgrade from the ZIP is to unzip the archive, and copy the /site/ dir from your existing installation into it. Then delete /site-default/ and /install.php, and rename htaccess.txt to .htaccess. Upload to your web server or development environment (replacing your existing installation), and you are good to go.
  18. Great! glad that worked. Let me know how it goes...
  19. Very likely this could be developed with add on modules relatively easily. For instance, I have another ProcessWire site that is integrated into Drupal's user system, and implementation was fairly straightforward (at least on the ProcessWire side!). We use this for providing access to members-only articles, whereby a user makes a subscription purchase in UberCart/Drupal and then they gain a time-limited role in ProcessWire that gives them access to those members-only articles. Granted, this could have been done in just Drupal, but the site is broader than that and better suited for ProcessWire in all other respects. So that's one example of user integration. Can you give me an example from the PHPBB side, of what additional functions you would want to provide to the PHPBB user in ProcessWire? That will help me to better understand the goal, so that I can make suggestions on implementation.
  20. That makes sense, and is worth looking at more. On the back end, fields are actually assigned to fieldgroups, and fieldgroups to templates (rather than just fields and templates like it appears on the front end). Technically, a given fieldgroup can be attached to multiple templates, though that option is not visible on the front end (to keep things as simple as possible). But fieldgroups would represent the partials that you are talking about, which are already in the system and API accessible.
  21. Looking in the code, the error actually makes sense, and I located what the problem was right away. What I don't understand is why it's never turned up before. But I am glad you found it, because it does appear to be a bug in PW2's module installer. You'll want to update your /wire/core/Modules.php: https://github.com/ryancramerdesign/ProcessWire/commit/4cf59bb7ea49a0d6449361285c177c0dd93182bd#diff-0 Or here is the full file: https://github.com/ryancramerdesign/ProcessWire/raw/4cf59bb7ea49a0d6449361285c177c0dd93182bd/wire/core/Modules.php
  22. Strange... Can you confirm that this is the error that you when when clicking the "install" button in the Modules section? This sounds like a MySQL error. Can you tell me what version you are running? Also, I am preparing an updated /wire/core/Modules.php for you, but just wanted to confirm about when the error occurs. Thanks, Ryan
  23. Hi Peter, You need to make use of a Page reference field type instead of a Text field type. When you create a Page reference, it will use a group of pages (based on your criteria) as select options. You can choose for it to be either a regular select, select multiple, or other input type after you create the field. (I need to make a screencast to demonstrate this fieldtype). This is one way that ProcessWire is a little different from other systems, and it might seem a little odd at first, but once you try it, the benefits become obvious and hard to beat. Ryan
  24. Actually you don't need to create the fields in the DB (at least, if it's working right). It should let you store anything and it'll encode it into the existing 'data' field. But if you aren't in a hurry to get this functionality, I agree that it may be better to wait since there are some changes in order for the users system. Regardless, I don't plan to change the methods of access (api) unless I have to.
  25. Apeisa: Let me know if that module skeleton worked for you. It occurred to me last night that it might not work unless you are running a very recent version of PW2. If not, make sure you have the latest (I added upgrade instructions to the FAQ section in the forum).
×
×
  • Create New...