Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 06/07/2012 in all areas

  1. Creating a sitemap is fairly easy in ProcessWire. The strategy we use is to get the page where we want the sitemap to start (like the homepage), print out it's children, and perform the same action on any children that themselves have children. We do this with a recursive function. Below is the contents of the sitemap.php template which demonstrates this. This example is also included in the default ProcessWire installation, but we'll go into more detail here. /site/templates/sitemap.php <?php function sitemapListPage($page) { // create a list item & link to the given page, but don't close the <li> yet echo "<li><a href='{$page->url}'>{$page->title}</a> "; // check if the page has children, if so start a nested list if($page->numChildren) { // start a nested list echo "<ul>"; // loop through the children, recursively calling this function for each foreach($page->children as $child) sitemapListPage($child); // close the nested list echo "</ul>"; } // close the list item echo "</li>"; } // include site header markup include("./head.inc"); // start the sitemap unordered list echo "<ul class='sitemap'>"; // get the homepage and start the sitemap sitemapListPage($pages->get("/")); // close the unordered list echo "</ul>"; // include site footer markup include("./foot.inc"); The resulting markup will look something like this (for the small default ProcessWire site): <ul class='sitemap'> <li><a href='/'>Home</a> <ul> <li><a href='/about/'>About</a> <ul> <li><a href='/about/child1/'>Child page example 1</a> </li> <li><a href='/about/child2/'>Child page example 2</a> </li> </ul> </li> <li><a href='/templates/'>Templates</a> </li> <li><a href='/site-map/'>Site Map</a> </li> </ul> </li> </ul> Note: to make this site map appear indented with each level, you may need to update your stylesheet with something like this: ul.sitemap li { margin-left: 2em; } The above sitemap template works well for a simple site. But what if you have some pages that have a "hidden" status? They won't appear in the sitemap, nor will any of their children. If you want them to appear, then you would want to manually add them to the what is displayed. To do this, retrieve the hidden page and send it to the sitemapListPage() function just like you did with the homepage: <?php // get the homepage and start the sitemap // (this line is included here just for placement context) sitemapListPage($pages->get("/")); // get our hidden page and include it in the site map sitemapListPage($pages->get("/some-hidden-page/")); What if your sitemap has thousands of pages? If you have a very large site, this strategy above may produce a sitemap with thousands of items and take a second or two to generate. A page with thousands of links may not be the most helpful sitemap strategy to your users, so you may want to consider alternatives. However, if you've decided you want to proceed, here is how to manage dealing with this many pages in ProcessWire. 1. First off you probably don't want to regenerate this sitemap for every pageview. As a result, you should enable caching if your template in: Admin > Setup > Templates > Sitemap > Advanced > Cache Time. I recommend setting it to one day (86400 seconds). Once you save this setting, the template will be rendered from a cache when the user is not logged in. Note that when you view it while still logged in, it's not going to use the cache… and that's okay. 2. Secondly, consider adding limits to the number of child pages you retrieve in the sitemapListPage function. It may be that you only need to list the first hundred child pages, in which case you could add a "limit=100" selector to your $page->children call: <?php // this example takes place inside the sitemapListPage function. // loop through the children, recursively calling this function for each: foreach($page->children("limit=100") as $child) sitemapListPage($child); 3. Loading thousands of pages (especially with lots of autojoined fields) may cause you to approach the memory limit of what Apache will allow for the request. If you are hitting a memory limit, you'll know it because ProcessWire will generate an error. If that happens, you need to manage your memory by freeing groups of pages once you no longer need them. Here's one strategy to use at the end of the sitemapListPage function that helps to ensure the memory allocated to the child pages is freed, making room for another thousand pages. <?php function sitemapListPage($page) { // ... everything above omitted for brevity in this example ... // close the list item echo "</li>"; // release loaded pages by telling the $pages variable to uncache them. // this will only uncache pages that are out of scope, so it's safe to use. wire('pages')->uncacheAll(); }
    1 point
  2. Isn't the default sort oldest first? Then you should get newest first just reversing the order (of course assuming you haven't changed the order): $images = $page->images->reverse(); Other WireArray methods: http://processwire.com/api/arrays/
    1 point
  3. Ryan, any news regarding this? I am thinking about my discussion module and one upcoming project where I probably will use that (of course, more polish and tweaks will come). But there are about 50 000 posts already on old forum, that probably will be converted, so that folder limit would be real issue here. Although in Discussion module it would be fine to adjust the module to remove the folder right after saving, but of course nicer and more native solution to this problem would be welcome. There is another simple way to do "folder folding": http://superuser.com/a/66341
    1 point
  4. Okay, so I'm different. Usually, people want to exclude stuff from an automagically generated navigation – I would like to add stuff. Let's see if I can explain this: I have a primary navigation which this module is just perfect for. But the site also has a secondary navigation in the footer, so there should be an item in the primary nav which skips to said secondary nav in the footer. So basically, I would have to append an item to the nav generated by the module, technically another list item containing a link to an anchor on the same page. Conveniently, this "skip to service nav" item would be the last item of the primary navigation, so I came up with this: 'outer_tpl' => '<ul class="clearfix">||<li><a id="skip-to-service" href="#service">Service</a></li></ul>' which works fine unless I'm on a page which has children (<li class="current has_children">). In that case, outer_tpl is "reset" to '<ul class="clearfix">||</ul>' or something, at least the "appended" list item is not rendered. Not being a PHP coder myself, I can't figure out if this is intended behaviour of the module or maybe a bug. (Although I'm aware I might be misusing 'outer_tpl' here.) I also thought about different approaches to realize that kind of nav item, maybe by using a "dummy page" or something, but I can't figure out how to do that. (Suggestions welcome, of course.)
    1 point
  5. copied from the wire/modules/Fieldtype/FieldtypeComments/Comment.php /** * Status for Comment identified as spam * */ const statusSpam = -2; /** * Status for Comment pending review * */ const statusPending = 0; /** * Status for Comment that's been approved * */ const statusApproved = 1;
    1 point
  6. Made a little update to this module. I strongly encourage to update with the latest version. - unfortunately it stoped working in the latest PW since script/css version (..script.js?v=100) in the admin were introduced (1,5 months?). Since I have to manually str_replace the script tag into the header right after jquery core js, it failed because the string is now different :/. Changed it to use replace on another location/part of the code which will hopefully stay there. - added the admin root path to the script url, so it now also works on PW installed in a subdir. - added script versioning appended to file name ..?v=101.
    1 point
  7. I've just added it to ProcessPageSearch and committed the update to the P21 source. Now you can do something like this: var url = config.urls.root + 'page/search/for?template=basic-page&body*=something'; $.getJSON(url, function(data) { console.log(data); }); The example above shows "search/for?" as the URL. When you add the "for" to it, it assumes that you are going to specify a selector in the URL. This works with either Ajax or regular mode. In ajax mode, it returns JSON. In regular (non ajax) mode it's going to output the results in interactive/html mode as usual. This "selector mode" isn't used in the search engine by default, so it's only used when you include the "for?" in your URL and specify a selector after it. I believe this selector mode is much more convenient than the regular mode for AJAX use, as well as regular non-ajax links to the search engine. The selector can be identical in format to a regular selector with the only difference being that you separate each part of the selector with a "&" rather than an ",". Here is an example: /processwire/page/search/for?template=villa&body*=luxury&bedrooms>5&bathrooms<=3 The above is a valid URL, but it's also a valid selector. If we replace the "&" with ", ", then we get this: template=villa, body*=luxury, bedrooms>5, bathrooms<=3 PW abstracts away the parsing of GET vars that lack an equals sign, like "bedrooms>5", and translates all of PW's 2-character operators just fine too (like *=, ~=, %=, <=, >=). Of course, you can also do this (specify a parent path): /processwire/page/search/for?parent=/path/to/parent&featured=1 If you want to specify what fields should appear in the JSON output (or the interactive table), then just add a "get=" var to your URL, like this: /processwire/page/search/for?template=basic-page&get=title,path,categories Separate out the fields you want to "get" with commas, like above. When you specify what fields should be included, it will include them in the output, in addition to the native fields that are included in all (like id, name, template, parent, etc.). Because JSON can represents objects nicely, PW will also include partial objects (like page references) as JSON objects. For something like a Page reference, it'll include most of the native fields for each page, as well as the title and path. By default it will paginate by 50, though you can increase that up to 250 by specifying your own "limit=123" var in the URL (where 123 is the limit you want to specify). To retrieve the next pagination, specify the same limit but precede your URL with the page number, i.e. /processwire/page/search/for/page2?template=basic-page&limit=100 If you prefer, you can specify a "start=123" var in your selector (just like with other PW selectors), to indicate the result number you want to start from. But I'm guessing most will prefer the simplicity of using the page number pagination. If you call jQuery's getJSON() on the search URL, you will get your results in JSON format. Here's an example of a call we might use: $.getJSON("/processwire/page/search/for?template=basic-page", function(data) { console.log(data); }); jQuery's getJSON automatically converts it to an object in jQuery, but the JSON string is probably the simplest way to envision it, so here is the actual JSON string as it's returned from that query. This query was performed on a stock install of PW 2.1 using the included profile. <?php // ignore the PHP tag, I just wanted syntax highlighting { "selector":"template=basic-page, limit=50", // just a repeat of the selector you used "total":"4", // total number of results found. if there were 1230 matches, this would be 1230 "limit":50, // the max number of results that will be in this request (default=50) "start":0, "matches":[ // array of matches { "id":1001, "parent_id":1, "template":"basic-page", "path":"/about/", "name":"about", "title":"About" // plus any fields you specify with get=... }, { "id":1002, "parent_id":1001, "template":"basic-page", "path":"/about/what/", "name":"what", "title":"Child page example 1" }, // and so on for each match ] } I'm sure there are tweaks and improvements still to be made, so please let me know if you find any issues or areas for improvement.
    1 point
  8. That is still a good approach, but here is another you can take that's a little simpler (if it suits your needs). You would want to be running the latest commit of 2.1 for this. 1. Create a new role in Access > Roles. Name it "distributor" (or whatever you want). Add only the "page-view" permission to it. 2. Create a new template that will run on the password protected page(s). On that template's "access" tab, uncheck the "guest" role, and check the "distributor" role in the "view pages" column. Also on the "access" tab, in the field labeled "What to do when user attempts to view a page and has no access?" – select "Show the login page". (Also, just a note in case you change it: on the "URLs" tab, URLs must be set to end with a slash [which is the default setting]. This is required for templates that use a login.) 3. Create your password protected page(s). Select the template you created above as the template for this page. The page is now password protected. 4. Create your user(s) that will have access to this page. Give them the "distributor" role. 5. Your done. When someone hits the URL to it, they'll get a login form. Upon completing a login, they'll see the password protected page.
    1 point
×
×
  • Create New...