Jump to content

ryan

Administrators
  • Posts

    16,772
  • Joined

  • Last visited

  • Days Won

    1,531

Everything posted by ryan

  1. The installer does check file permissions. But those directories don't need to be writable. Only the /site/assets/ needs to be writable (and PW's installer will tell you if it isn't). I'm wondering if maybe one of those dirs may have not been readable by Apache for some reason ... that's a permission we do not check for. I wouldn't have thought we would need to, but perhaps we should. Most likely the white screen was a result of the server having PHP's display_errors off (which is a good idea for production servers). Whatever error occurred likely ended up in your PHP error_log file. If it's easy to find, please post what it said. If it's not easy to find, don't worry about it, and I'll keep an eye out for similar issues in the future.
  2. There's been very little written about ProcessWire formally on other sites, so always glad to see someone write something about it and I'll try to post links here when they appear. Marc Carson (@circular on twitter) posted an article on his site titled "Thoughts on CMS packages, July 2011". In it he briefly covered Textpattern, ProcessWire and a couple others. I thought it was very complimentary to ProcessWire and Textpattern (one I've not tried before). Here's the link: friendlyskies.net/site/webdev/thoughts-on-cms-packages-july-2011 http://www.friendlyskies.net/notebook/thoughts-on-cms-packages-july-2011 I think we'll get a lot more written about it once get get 2.1 finalized and we start promoting it intentionally, like on opensourcecms, etc.
  3. The parentPrevious is only available until the page is saved, and it's a runtime thing, so it's not saved in the DB. Though a revisions module is underway that will be saving all previous states of pages, but we're a couple months away from that being ready. Of course, you can always save the previous parent info yourself if you need it. For runtime, you can set whatever you want to a page and it will act as a data container. It only saves data in the fields assigned to it, so there's no harm in setting some other random values to a page if you want to. So you could for instance set $page->parentPreviousPete = $page->parentPrevious and use it where you needed it. If you wanted it to save to the DB, then you would need to actually add a field to the page called parentPreviousPete.
  4. I see what you mean. If you are okay with setting it in your /site/config.php file, I can make it happen. This doesn't involve adding any real overhead or complexity to the system, because these types of config options are optional.
  5. While the PW core isn't built around the idea of rendering markup, I don't think there is any problem with other modules filling this need for those that want it. While we've got that now with modules (like Markup modules), we don't have a specific standard as it relates to markup rendering 'widgets'. I think all we need is a class that requires a render() method, so will plan on this to start. Most likely I'll round up the existing Markup modules behind a base Markup class that implements the Module interface, and we'll take it from there... If we need something more specific to widgets, then we'll probably make a MarkupWidget class to serve as a base for those modules.
  6. Here's how you can make a site profile to be installed somewhere else: 1. Export your database with mysqldump using this command, replacing [user], [pass], [database] and [host] with the ones you are using. You can probably duplicate this with PhpMyAdmin too, but note you'll want complete inserts and you don't want extended inserts. mysqldump --complete-insert=TRUE --add-locks=FALSE --disable-keys=FALSE --extended-insert=FALSE --default-character-set=utf8 --comments=FALSE --compact --no-set-names --skip-disable-keys --skip-add-locks -h[host] -u[user] -p[pass] [database] >install.sql 2. Move the resulting install.sql file to /site/install/install.sql. Of course, if the /site/install/ directory doesn't exist already, then create it. mkdir /site/install/ mv install.sql /site/install/ 3. Move /site/assets/files/ to /site/install/files/ mv /site/assets/files /site/install/files 4. Delete these dirs and files: rm -rf ./site/assets/sessions/ rm -rf ./site/assets/logs/ rm -rf ./site/assets/cache/ rm ./site/assets/installed.php 5. Edit your /site/config.php and remove these lines at the bottom: $config->dbHost = 'localhost'; $config->dbName = '...'; $config->dbUser = '...'; $config->dbPass = '...'; $config->dbPort = '3306'; $config->userAuthSalt = '...'; 6. Zip up your /site/ dir. zip -r -v ./site-default.zip ./site/* Now you've got a site-default.zip file that is ready to be installed somewhere else. All you need to do is download a fresh copy of PW, remove it's /site-default/ directory and replace it with the one you zipped up. Then run the installer. I may be missing something, but I think that's all there is to it. If anyone tries this and runs into any problems please let me know. The plan is to automate all this into a site-exporter module at some point. Edit: I forgot step 5, and just added it above. Edit 8/15/11: Updated mysqldump command above to new/better version
  7. Are you sure that your hook isn't being triggered when moved in PageList? I can't think of any reason why it shouldn't. But if you can confirm that's the case let me know because it would be a bug. Both the trash() and restore() functions are triggered by $pages->save() when it detects that the parent has changed to or from the trash. There isn't currently a move() hook, though I'd be willing to add one to $pages if you all think it would be worthwhile. Currently, you can detect a move by hooking into $pages->save() and checking if the page's parent has changed: <?php if($page->parentPrevious) { // page has moved // $page->parentPrevious is the previous parent (Page object) // $page->parent is the new parent (Page object) } There also isn't currently a trash empty() hook either, though I'll also be happy to add one of these if you want it. However, when you empty the trash, $pages->delete() is called for every page in the trash, so an 'empty trash' hook might be irrelevant?
  8. This can be set on a per-template basis in your template settings. I don't think you can hack the core for this just because the PW admin requires trailing slashes, so hacking the core to make non-trailing the default setting may cause problems elsewhere in the system. But if you want to match the slash behavior WP URLs, I would set this for the page templates where applicable.
  9. Widgets like they are in WordPress are an entirely different animal than they would be in something like PW. In WordPress, you aren't dealing with anything-goes templates and instead you are dealing with themes. The theme follows an expected format an typically has an area built to contain widgets, among other things. Drupal is the same with blocks. These CMSs are markup generation engines because it's assumed that the various elements (widgets, blocks, modules, plugins) are generating their own markup. In these CMSs you are typically designing the theme for the CMS, rather than having the CMS accommodate your design. You are styling the output of someone else's markup. There are plusses and minuses to this approach. A plus is that you can make assumptions about things like widgets. Another plus is that you can make a lot happen without development (like dragging widgets in WordPress). A minus is that you are locked in by the needs of the theme and you have far less flexibility and control over your output. PW is a very different tool from WP and Drupal. PW's approach is to provide you with the tools to get to your data easily, and let you decide what you want to do with it in terms of output. With a few exceptions, it isn't going to generate the markup for you, and that's the point. I personally dislike working with tools that generate the markup for me because it always feels like I'm cleaning up someone else's mess rather than creating my own. Most Designer/Developers prefer to create their own markup because it lets you use your skills to accomplish whatever you want to. ExpressionEngine is another tool that operates on this same principle. Given the above, I prefer to keep PW out of markup generation at it's core. Meaning, I wouldn't ever want widgets/blocks to be a required element of the software, or part of it's base architecture (like WP or Drupal). But I also think that this is a great use of plugin modules, as well as your own development processes. The methods described by Antti and Adam are great ways to make widgets part of your site. And as was described earlier, you can turn any Page into a widget simply by rendering it (and you'd want to make sure your page's template is producing the appropriate output): echo $pages->get("/widgets/latest-news-list/")->render(); Still, something like the above really isn't much different than this (with less overhead too): include("./widgets/latest-news-list.php"); That's how you might make your own widgets. But I like the approach of using modules for widgets too, as they are easier to share for people that want them. I wouldn't ever want to start including built-in widgets in the core since that would be directing how you should build your site. But I'm not opposed to at least supporting it in the core for modules. So if you guys think it makes sense to add a base Widget module class in the core (like the Pyro example) that's good with me. In fact, we already do to an extent so I'm not sure it would be much more than this: abstract class Widget extends ModuleJS { abstract public function render(); } Still, good to have a known starting point even if not much to it. The way you would call it would be the same way you already do for other modules: echo $modules->get("MyWidget")->render(); or maybe something simpler: echo $widgets->MyWidget->render(); Almonk is this along the lines of what you were thinking, or something different?
  10. You could do $page->save('fieldname'), replacing fieldname with the name of the field you want to save. But unless we're talking about something different than above, you don't need to do any save() calls. Also, saving a single field isn't going to trigger your hook.
  11. Adam and Antti are right. When you are calling save() you are triggering an recursive/infinite loop. Why? Because every time you call $pages->save() your hook it getting executed once again. So in this case you'll want to do what Antti suggested which is to make your hook run before (rather than after). That way you can jump in before PW executes the save and set what you need, and let the original $pages->save() do it for you. Also, I'm assuming that "exit;" is there just for debugging... In terms of scalability, this is exactly what PW is built for. I've used it on sites up to ~10k pages. Most sites I develop in it are 2k-8k pages and up to 10x that number of URLs. This is either a lot of pages, or not a lot, depending on your point of view. I think for most open source CMSs, this is considered large scale. But if you are working at Google or Facebook, then you would say this is small scale. PW hasn't been tested in the hundreds of thousands of pages scale yet. I imagine it would work just fine at that scale, but don't have the sites to prove it yet. As you start to use PW at a larger scale, you do have to pay more attention to how you use it. For instance, calling $page->children() on a page that has 2,000 children is a bad idea because it'll be slow. Whereas calling $page->children('limit=25') is fast. Here's some more details on this: http://processwire.com/talk/index.php/topic,5.0.html Another factor to consider as you go larger scale is caching. PW 2.1 comes with some strong caching features that you can define on a per-template basis (edit a template, set a cache time, and more options open up). This is for caching entire page renders. For caching smaller pieces, it's really good to use the MarkupCache module. For instance, on that VillaRental site, the top left "villa search" box is expensive to create since it has to to iterate through all the regions, destinations and vacation types. As a result, it is cached using the MarkupCache module, which re-creates it once per day, while the rest of the page may be uncached. More info on how to use the MarkupCache module is here: http://processwire.com/talk/index.php/topic,8.0.html
  12. To filter out the current rights holder, I think you'd just want to not link to it, or add some logic to the template to avoid listing those. To not link to it, you'd just do something like this: <?php if($page->atype->name == 'current_rights_holder') { echo $page->atype->title; } else { echo "<a href='{$page->atype->url}'>{$page->atype->title}</a>"; } Or if you want to link to, but not list all the current rights holders, your atype template could have the logic instead: <?php if($page->name == 'current_rights_holder') { echo "nothing to list"; } else { echo $pages->find("atype=$page, limit=25")->render(); }
  13. I misunderstood before that you actually want to re-create this in PW. I think that makes sense to do it, and it should be straightforward to setup your event template and add fields to it. I would keep all your events under the same parent and just set the default sort to be reverse chronological on your date field, and select from them based on that same date field. For example, to retrieve all events in July, 2011 you'd so something like the following. We'll assume you have a field called 'date' that hold's the events date: <?php $start = strtotime("2011-07-01 00:00:00"); $end = strtotime("2011-08-01 00:00:00"); $events = $pages->find("template=event, date>=$start, date<$end, sort=date"); You'll also want to draw a calendar using an HTML table. To do this, you'll need to know the number of days in the month. There's a lot of examples out there on how you might do this with PHP. So I won't attempt to redo it here, but will say that as you are drawing those rows and columns for the days, you'll want to check if any of them matches the date you found in your $events for the month (like above), so that you can highlight the individual cell as having an event in it.
  14. Definitely check out the example sinnut linked to, that's even better.
  15. See the code example on this page, which demonstrates running a hook after a page is saved: http://processwire.com/api/modules/ You could also do the same thing when a page is deleted by hooking into the $pages->delete. method. There are a lot of these kind of hooks in PW. You can identify them by doing a grep for "___" (3 underscores) in PW's core or modules, as they all start with 3 underscores. Likewise, you can make any functions in your own modules hookable by preceding the function name with 3 underscores.
  16. If I had to create a calendar like this, I would just create an 'event' template and give it title, detail and date fields. It would certainly be simpler to develop this in PW than without it. But if I'm understanding you correctly, you don't have that option and you need to work with this existing code and database. Given that, I think you should be able to just copy all this code and paste it into a PW template file (after fixing the security issues). Not sure if this is necessary, but since PW already has a DB connection going on, you probably want to keep a copy of your own DB connection and use it in your calls: <?php $mydb = mysql_connect(...); /// And then use that in your DB calls, i.e. mysql_select_db("database_event", $mydb); mysql_query("SELECT ...", $mydb); With regard to the security issues, there are both XSS and SQL injection problems here. XSS in a giant can of worms and you want to keep it closed. You need to make sure that any input from the user is routed through htmlentities() or htmlspecialchars() before it is output, unless you have specifically typecast it as something (like an integer). This includes $_SERVER['PHP_SELF'] which can be considered tainted, and needs to be sanitized in the same way. Though you probably don't need to use PHP_SELF at all, so I would just avoid using it. To protect against SQL query injection, you need to sanitize and validate your data. If you are expecting something to be an integer, then typecast it to an integer as soon as you get it from GPC (get, post or cookie), i.e. <?php if(isset($_GET['month'])){ $month = (int) $_GET['month']; if($month < 1 || $month > 12) die("Invalid month"); } else $month = 1; If you are getting a string from GPC (get, post, cookie) input, then there's more to consider. If there is a group of expected values, then make sure the string is literally one of those expected values before using it. i.e. <?php $valid = array('Jan', 'Feb', 'Mar', ...); $key = array_search($_POST['month'], $valid, true); if($key === false) die("Invalid month"); $month = $valid[$key]; If you are dealing with unknown text, then you'll want to sanitize it as much as possible: <?php $title = substr(strip_tags($_POST['txttitle']), 0, 128); // strip HTML and limit to 128 characters $title = htmlentities($title, ENT_QUOTES, "UTF-8"); // may or may not want this here, see below $title = mysql_real_escape_string($title); // sanitize for database query After the above, SQL injection is not going to be a problem with your $title. You may or may not want the htmlentities() there. If you don't have it there, then you'll need to know that you may be inserting XSS tainted data into your database, and any time you output that data, it will need to be entity encoded. I think in your situation it may be a good idea to run the htmlentities() before insertion, but I generally prefer not to keep entity encoded data in the database just because it takes up more space, prevents legitimate HTML, and interferes with fulltext indexing. ProcessWire does not store entity encoded data. But it does take a little more discipline to always treat data in your DB as possibly XSS tainted. To recap, look at all the $_GET, $_POST and $_SERVER vars in your code and consider them tainted. Do what's necessary to make them safe for database insertion and/or output, depending on the context. And once it's secure, try using this in a PW template.
  17. Once you start really using them, you may not want to do it any other way. While the page reference type is infinitely scalable, I also think it's a good solution for small needs too. Lets say that you needed to associate some other data with your Publisher, Developer and Current Rights Holder. For instance, maybe a brief summary of what they are, an graphic/image/icon, or anything else. You just add that field to your template used by those entries. I'll reuse a previous example: <?php // for syntax highlighting foreach($page->atype as $a) { echo "<p><a href='{$a->url}'>{$a->title}</a><br />{$a->summary}</p>"; } Note how I liked to the atype page. This presents some cool new possibilities for usability (not to mention things for Google to index). We could make the atype page show all pages that have a given type selected. Depending on the context, this might be really useful to the users of your site (if not, yourself). Here's what we might do in the atype template: <?php echo "<h1>{$page->title}</h1>"; echo "<h2>{$page->summary}</h2>"; echo "<h3>Pages with {$page->title} selected:</h3>"; $entries = $pages->find("atype=$page, limit=25"); echo $entries->render(); When you start building sites in this manner, the page references start to become valuable parts of the site's structure. You start to build connections that weren't possible before, many of which are genuinely useful. But for everything else, or for pages that may not have a place in your site structure, put them in a /tools/ or /config/ section of your site, which you may or may not make accessible to guests. Here are a couple examples: http://www.tripsite.com/tools/difficulty/easy/ http://www.tripsite.com/tools/tour-types/self-guided/ From a technical standpoint, while you are right that there may be a max of 3 entries per page in the database instead of 1, each entry is an integer (a pointer to a page) rather than a string of text, like you see in many other CMS's select types. So perhaps there are 3 entries, but they are consuming far less storage resources than in the other CMS (or in fieldtype you linked to). Lets say you decide the word "Current" in "Current Rights Holder" is not necessary and you want to change the label to "Rights Holder". In PW you just go and change it. In other CMSs, you might not be able to, or if you did, it might corrupt the data leaving all existing "Current Rights Holder" entries there while new ones are labeled "Rights Holder". If you are certain you won't ever want/need to do anything more than just show a Developer, Publisher and Current Rights Holder checkbox, then there's still no harm in keeping it a Page reference. But if you don't want to take that route or one reason or another, you can make them single checkbox fields: $page->developer $page->publisher $page->rights_holder Wrap a fieldset around them to keep them together. I only use these checkboxes for single on/off toggles, but just wanted to mention this alternative if you don't want to use the Page fieldtype for one reason or another. But as a best practice, I nearly always recommend using Page references for this kind of stuff as I think it leads to good design structure, scalability and long term benefits. But I can say that only for my own sites, and I know everybody's needs are different.
  18. Thanks for the link. Nice photos in that story too (love the cockpit photo). Amazing there's only 400 of them. But I guess given what it is, the cost is pretty prohibitive. But for someone with money that wants a supercar for the attention, perhaps this is a much better value (and grabs more attention) than any Ferrari or Lamborghini.
  19. Great explanation Antti! Here's a couple more simple examples. I think that 'type' might be a reserved word (not positive), but I'll change it to 'atype' in the examples just in case. Iterate through the selected values on your $page: foreach($page->atype as $a) { echo "<p>" . $a->title . "</p>"; } The output might look like this: <p>Publisher</p><p>Developer</p> Or, if you made your page reference a single page reference, then it's just: echo "<p>" . $page->atype->title . "</p>"; Antti's second example can also be simplified a bit to this: if($page->atype->has("name=publisher")) { echo "Publisher"; }
  20. You can define config settings for your own use. What I do on a lot of sites is define some of the common image dimensions in my /site/config.php file and just call upon these when I need them: $config->myThumbWidth = 150; $config->myThumbHeight = 100; Then when you need to create a thumbnail, just refer to those: $thumb = $page->image->size($config->myThumbWidth, $config->myThumbHeight); This may be a preferable way to do it if you have multiple templates that need to use the same dimensions. That way you aren't specifying the same dimensions in multiple places... though I'm not always that disciplined.
  21. ryan

    Page IDs

    I think I'm going to manually change it to start at exactly 5k–that way it won't look like an accident.
  22. Sounds good, I will plan to implement. Admittedly, this isn't a huge priority for the sites that I work on (though certainly a very useful feature), but perhaps it is more important for others. I'm leaving the country to travel in 2 weeks and want to come back and get 2.1 released asap and then start focusing on multi-language features. I'm thinking it would be good to focus on multi-language features first, as that is the priority. But perhaps the image fieldtype/inputfield improvements would be a good to accompany 2.2 as well.
  23. Actually I think if you set $config->advanced = true in your /site/config.php file, then you'll get a 'required' option with most fieldtypes. The only problem is that this has to be implemented by the fieldtype module, and it's not implemented by all of them. But as we get closer to wrapping up 2.1, it seems like this is one thing that should probably be finalized in this version (and taken out of advanced mode).
  24. I can't reproduce either. Can you provide additional details on your environment (esp. browser) and the exact steps to reproduce? Thanks, RYan
  25. ryan

    Page IDs

    Did your own pages start with lower numbers and then jump into the 5k's, or did they just start in the 5k's? Hopefully they started in the 5k's, but want to double check. I'd hoped to keep a few thousand IDs reserved in the system for future needs. But you are right in your assumption in that I was testing with a lot of data at one point. I'd planned to reset it back, but ultimately didn't because I figured I'd like to keep a block of IDs as reserved for future system use. I didn't originally plan it that way, but did intentionally not reset it back when I realized there would be some benefit to keeping a block of lower IDs for system use.
×
×
  • Create New...