Jump to content

ryan

Administrators
  • Posts

    17,095
  • Joined

  • Days Won

    1,641

Everything posted by ryan

  1. I think that may be the problem here, as title is a required field. How do you have templates without a title? PW requires a title from all templates, except in specific cases. The ProcessPageAdd module assumes your template has a title field. When it finds there is none, that's where the exception is getting thrown (I think). I'm thinking you can fix this just by adding a title field to any of your templates that lack it, but still wondering how the templates were created without one. (Perhaps something about PW 2.0 that I don't remember).
  2. I suggest not extending the User class, and instead plugin to it with a module class UserExtended extends WireData implements Module { public static function getModuleInfo() { /* return your array here */ } public function init() { $this->addHook('User::sendThankYou', $this, 'sendThankYou'); public function sendThankYou($event) { /* do something */ } } The above would add a sendThankYou method to all User instances. Your sendThankYou method can gain access to the $user the method was called on like this: $user = $event->object; Your sendThankYou method can also have one or more arguments if you want it to: $arg = $event->arguments[0]; If you want your sendThankYou method to return a value, do it like this: $event->return = 'value you want to return'; Looks like Antti beat me to it.
  3. This is a fairly complex pagination scenario. I can see why you want to get it all in 1 find() operation here, and if the option I mentioned works, I would probably use it. But if not, you'll need to adjust your setup to perform pagination and sorting at the $pages->find() level, rather than after. Your $posts->find() is not setting pagination details to the PageArray it returns to you because all those pages are already in memory, and pagination is assumed to be for stuff that is not in memory. Writing in the browser here, but try changing your example to this: $template = $templates->find("name^=post_"); $parent = $pages->get("/beitraege/"); $posts = $parent->children("template=$template, post_confirmed=1, sort=-created, limit=10"); if(!$user->isGuest()) { $posts->import($parent->find("template=$template, user=$user, sort=-created, limit=10")); $posts->sort("-created"); // sorts with the previous results } A caveat is that the items-per-page is going to be somewhere between 10 and 20 rather than always 20, at least if the result set is not large. The other caveat is that it's not going to show more than 10 of the given type in each pagination. These may or may not be issues in your case, but just wanted to mention it. There are ways around it, but it'll take more code. Note the way I'm using the $template var requires the latest PW (or at least one from the last month). You no longer have to do something like implode('|, ...) in recent versions.
  4. Kind of a hack, but give this one a try: $pages->find("offer_global|offer_from=1|22|33|44|55"); It should work with pagination. At least, I can see I've got code to account for pagination in PageArray::import(). However, I am not certain I've ever actually had to use it. Let me know what kind of result you are getting?
  5. Nice job Diogo! I suggest adding this line to the top of your format() function, just so that it doesn't have to perform the preg_match (a heavy function) when it doesn't need to: // check if we even need to perform a preg_match and exit if not if(strpos($str, '{') === false) return; One idea for a future version is that if you just type the field name without the index, i.e. {images} it could output them all. Another idea is to add a class name to the <img> tag like "ImageTags" so that one could style them independently of other images.
  6. When you try to add that new page, do you have the choice of selecting which template? If not, try adjusting your 'family' setting on the parent page's template and temporarily adjust it to not have a defined child template here. Just in case some data is amiss, also edit the template (Setup > Templates > your new page template) and save it. Do the same for the template used by the parent of the page you are trying to add. Lastly, do the same for the 'title' field (Setup > Fields > title). The purpose of this is to refresh the config data for the relevant templates/fields there, just in case there is some leftover PW 2.0 setting, re-saving those templates/fields should clear it out.
  7. Regarding workflow: the default profile is pretty much always my starting point. It's rare that I don't end up repurposing the fields and templates that are already there to start building things out. Likewise, I usually end up just renaming (as necessary) and repopulating the pages that are already in the default profile. Then I will start adding new fields, followed by templates, specific to the needs of the site. While I try to determine most of the templates/fields that I'll need ahead of time, I will continue adding fields and templates throughout the entire development process as necessary to make the site do what I want it to. Most larger PW sites are pretty relational and make good use of Page references. But this is also the part that I think is most important to outline when it comes to workflow. This part is quite a bit different from other systems, but has major advantages. I try to make my selectable Page references part of the site's structure, if at all possible. For example, on tripsite.com, every bike tour has a "country" page reference field, and those countries are useful in the site's overall structure (Netherlands in this case): http://www.tripsite.com/countries/netherlands/ In other cases, page references might not fit as part of the site's general structure, so I'll have a /tools/ section in the site where they live. Though it's easy enough to make them function as pages, so I figure why not. Here are a few examples (they are all using the same template): Multi-page reference field "months" (April in this case): http://www.tripsite.com/tools/months/april/ Multi-page reference field "tour_types" (Guided in this case): http://www.tripsite.com/tools/tour-types/guided/ Page reference field "difficulty" (Difficult in this case): http://www.tripsite.com/tools/difficulty/difficult/ The template used on those pages is not much more than this: $tours = $pages->find("template=tour, {$page->parent->name}=$page, limit=10"); foreach($tours as $tour) { // output the tour } Admittedly, most of my projects are rebuilding existing sites, so I usually have some (or a lot) of data to migrate to the new site. This becomes a major component of the development workflow, so I figured I should mention it here. After I've setup the necessary fields and templates (and usually before front-end development), I'll work on bringing in the new data. If it's a relatively simple conversion job, I might use the ImportPagesCSV module. But most jobs require some markup replacement, character set conversion or other things, so I'll build my own import script. This is where I like to bootstrap PW from a command line PHP script. Here's a simple example: /import-airports.php #!/usr/bin/php <?php require("./index.php"); // bootstrap PW $fp = fopen("./airports.csv", "r"); while(false !== ($data = fgetcsv($fp))) { $page = new Page(); $page->template = 'airport'; $page->parent = '/building-types/airports/'; $page->title = $data[0]; $page->location = $data[1]; $page->year = $data[2]; $architectName = wire('sanitizer')->pageName($data[3], true); $architect = wire('pages')->get("/architects/$architectName/"); if(!$architect->id) { $architect = new Page(); $architect->template = 'architect'; $architect->parent = '/architects/'; $architect->title = $data[3]; $architect->name = $architectName; $architect->save(); } $page->architect = $architect; $page->save(); echo "\nCreated page: {$page->url}"; } Once I've got a lot of data to work with in the system, I'll start doing front-end development: creating the template files, markup, css and anything else necessary to handle the output for the site. The files from the basic profile either get used as a starting point, or replaced completely at this point. These are my main workflow components I can think of, but let me know if there are any specific areas you'd like more detail on or can think of anything I've missed.
  8. A lot of shared hosts will have Apache/PHP running as you, which is good. When you installed ProcessWire on your server, if it never asked you to make any directories writable, then Apache/PHP is likely running as you. You can also tell by running a PHP script that just contains this: <?php echo exec('whoami'); If you run that script and it says the name of your account, then there's likely not any reason for anyone to have access to the site's files except you. This may or may not be necessary, depending on what jailing measures your shared host is already handling. But better to be safe than sorry. Don't do any of this if Apache/PHP is not running as you. To start, you can recursively remove write access to your /site/assets dir: chmod -R og-w site/assets Likewise, remove read access from your /site/config.php: chmod og-rw site/config.php You'll also want to tell PW what permissions to use when creating new files or directories. So edit your /site/config.php and locate the lines containing the chmodFile and chmodDir settings. Update them to this: // 0755 = owner r/w/x, group+other can r/x $config->chmodDir = "0755"; // 0644 = owner can r/w, group+other can only read $config->chmodFile = "0644";
  9. Does anyone have experience setting up/running a wiki like this? Drop me a note. I can setup an account here to host it.
  10. Uh oh, I'm using readability and was really enjoying it up until I read this. :- Okay I'm still enjoying it. But maybe I'll click 'read later' on readability's homepage or something, just in case.
  11. There's a lot in PW (like the Template > Family tab) that is really useful when you get things going, but not really necessary when getting started. It's one of those things that you tend to find once the need comes up. I'd used ProcessWire for years without a lot of this stuff. So it's always a bit of a battle balancing simplicity vs. power. I think it will be good for these tutorials to outline what's essential [to get things started] and what's not. One of the problems I had with EE years ago is that I would get lost in it's endless configuration screens, and not really know what I needed and what I didn't. I'm writing this here so I won't forget when it comes time to expand upon the tutorials.
  12. Looks like a good book Alan. Let us know how you like it. I've been hunting for new books, but have lately found more of the kind of content I'm looking for online than in books. Most recently I've been enjoying this site: http://phpmaster.com/ ... grabbing articles with Readability and reading them offline on the iPad and Kindle.
  13. Whether 777 is a bad idea or not depends on several factors like whether it's a shared host, and if so, how well the accounts are jailed from one another. I think that many shared hosts are pretty well jailed against problems here now, though that didn't used to be the case. So you have to be careful and critical about your web host in this area. If you are on your own server (VPS or dedicated) and your site(s) are the only ones running there, then it's a non issue. The problem with both 777 and 755 is that even if the accounts are jailed at the shell/FTP level, if Apache is running as the same user (like "nobody", as it does on my server) then a PHP script on one account can write a file to another account anywhere that the other account has an Apache-writable directory. 755 doesn't really help you here (I don't think) because so long as Apache can write to it, the problem is the same. I don't have enough experience with other shared hosts to say how good protection is for that problem. Even if the problem exists, chances are you won't ever have to deal with the consequences as exploiting it can be rather obscure, but it's always a real risk. Consider another risk with shared hosts-- readable files aren't any safer. Another account could create a PHP script that reads a file containing your DB connection info, then connect to the DB and have full read/write access to your database. I think it's best to use a VPS, dedicated or something like it so that you have a completely separate OS instance from any other accounts, and that ensures you can have an Apache readable/writable directory without worrying about other accounts taking advantage of it. Another route is using a server that runs Apache as a CGI or phpsuexec so that all scripts execute as you rather than Apache. In such a case, you would remove read and write access from everyone except yourself, providing a little more security in a shared hosting environment. But shared hosting is not worth the hassle and cost savings in my opinion.
  14. Netcarver I think that makes sense, though the 403 strikes me as more semantic (if that's the right word?) here. Since these are from Apache, not PW, I'm not sure they necessarily hide it any better since Apache's 404 is unlikely to be the same as PW's. PW is subtle and quiet (unlike WordPress or Drupal) but completely hiding PW's existence is not something we are necessarily trying achieve. If we were, we'd have to go a lot farther than disguising blocked directories. Even then, no matter how well a software disguises itself, if you've got access to the code, there are nearly always ways to figure it out. Though maybe more transparency is something we should aim for down the road, as PW is already very quiet about itself and it's not a stretch to take it further. I'm just afraid of getting too far into this as I'm not sure 100% disguise/transparency is possible with any reasonably complex software.
  15. ProcessWire is meant to support your existing way of developing things, but I think it's always good to provide a starting path and then let people take it from there. More needs to be added, like you mentioned. We added the tutorials board here a few months ago and hoping to continue adding to it with more stuff like this. I also want to start adding new site profiles. I plan to expand on this tutorial with the items mentioned at the bottom of it (page 1), as soon as time allows. Anyone that wants to make tutorials or site profiles, that's great too and just let me know what I can do to assist.
  16. You can also locate where your php.ini file is by viewing the output of phpinfo(); Place this in a test.php file on your server and view it in your browser: <?php phpinfo(); Search for "php.ini" and it should tell you exactly where it is. Since you are going to be dealing with large images, you may want to set your memory limit to 256M and hopefully that would cover the uncompressed size of those images enough that they can be manipulated from PHP.
  17. It would be trivial for a module to hook into the PageList and avoid listing pages that the user can't edit. But it's not something that I recommend in a tree-based hierarchy because access can change at any branch. The PageList is meant to show everything the user can view. The context of the hierarchy is generally important everywhere in ProcessWire, whether the user can edit a given branch or not. There are permissions in the user's role that control their access to all the relevant items from the settings tab. Another route you can take is to lock down the allowed parents and templates from any given template's "family" tab. But that is structure control rather than access control, as it applies to everyone. However, it's the one I find most handy to ensure clients (and myself!) aren't adding or moving pages around where they shouldn't.
  18. When it comes to objects (like pages), I think that using === is more efficient than == because: // compares that the two objects are the exact same instance, holding the same spot in memory // this is just 1 quick comparison $page1 === $page2; // compares that the two objects have all the same properties // this spawns potentially lots of comparisons (?) $page1 == $page2; Rather than comparing page objects, I usually just avoid thinking about the above, and just check that they have the same ID: $page1->id == $page2->id; If you find it simpler to look at, putting them in the context of a string does the same thing as comparing the ID: "$page1" == "$page2"
  19. First, make sure that you can access your site at mydomain.com and that it stays there as you browse it. You want to make sure there isn't anything redirecting back to me.friendsdomain.com. Once you've got that down, you are likely safe to setup a redirect at me.friendsdomain.com. You'll want to use a 301 Permanent redirect to ensure that it is SEO friendly. Though note that even SEO friendly redirects can make Google shy for a bit, especially if you've been at the previous URL for a very long time. The following can be added to your .htaccess file on me.friendsdomain.com, directly after your "RewriteEngine On" line: RewriteCond %{HTTP_HOST} me\.friendsdomain\.com RewriteRule ^(.*)$ http://mydomain.com/$1 [R=permanent,L] This has worked well for me, but you will want to check that all works correctly on your server too by using a browser plugin to make sure you are getting the proper 301 redirect header.
  20. Thanks for the update Slkwrm! No problem with double posting. If it's something that you want to show up in new content, then double posting is the way to go because otherwise people might miss it (I don't know of a better solution).
  21. Alan, you don't necessarily need to use PW's MarkupPagerNav module if all you need are next/prev links. Here's how you might do it instead with your own code: $limit = 5; $items = $page->children("limit=$limit"); $prev = $input->pageNum > 1? $input->pageNum-1 : 0; $next = $items->getStart() + $limit < $items->getTotal() ? $input->pageNum+1 : 0; if($prev) echo "<a href='{$page->url}page{$prev}'>Prev</a> "; if($next) echo "<a href='{$page->url}page{$next}'>Next</a> "; If you prefer to use the MarkupPagerNav module instead, then you could always just hide the numbered links with CSS: ul.MarkupPagerNav li { /* hide all the links */ display: none; } ul.MarkupPagerNav li.MarkupPagerNavNext, ul.MarkupPagerNav li.MarkupPagerNavPrevious { /* display just the next/prev items */ display: inline; }
  22. Just to give more explanation behind it, the "a" class is meant to count from the beginning, so "a1" means first item, "a2" means second item, etc., while the "z" class is meant to count from the end so "z1" means last item, "z2" means second to last, etc. It could just as easily be called "from-the-beginning-1" or "from-the-end-1", but just wanted to make sure my extra short class names weren't causing confusion. The purpose of going this route was to keep comparisons to numbers rather than objects. We know that the first item is always going to have a key of 0, and the last item is going to have the key of $page->numChildren-1. So we don't really need to call first() or last(), though there's no harm in it either. The only other real difference here from earlier examples is just that I'm not using the getItemKey() method. It's not necessary to do that because anytime you call foreach() in PHP you have the option of including the $key in the foreach. As a result, this: foreach($page->children as $key => $item) { is the same as this: foreach($page->children as $item) { $key = $item->getItemKey();
  23. Looking good Diogo! The way to identify if something is an image is like this: $image = $page->get("image_field_name"); if($image instanceof Pageimages) { // WireArray of multiple images } else if($image instanceof Pageimage) { // a single Image }
  24. Of course, I'll make it work for Textile before Markdown.
  25. Nice job with the responsiveness too... quite a fun one to drag the window size.
×
×
  • Create New...