Jump to content

ryan

Administrators
  • Posts

    16,460
  • Joined

  • Last visited

  • Days Won

    1,458

Posts posted by ryan

  1. How do you manage duplicates (title) from code (in PW administration one receives an error if an existing item already exists under the same parent) ?

    The URL name ($page->name) has to be unique for all sibling pages (i.e. pages having the same parent). I don't usually bother with checking unless ProcessWire throws an error about it during the import. If it looks like there are going to be duplicates, then here's how you'd ensure uniqueness by adding a number to the end of the URL name and keep incrementing it until it's unique:

    Replace this:

    $skyscraper->name = $building;
    $skyscraper->save(); 
    

    With this (overly verbose for explanation purposes):

    <?php // just to turn on the forum syntax highlighting
    
    // Converts "Sears Tower" to "sears-tower" when setting the name
    $skyscraper->name = $building; 
    
    // Retrieve the URL name, which should be "sears-tower"
    $name = $skyscraper->name; 
    
    // a counter incremented each time a duplicate is found
    $n = 0; 
    
    // find the first non-duplicate name
    while(count($parent->children("name=$name")) > 0) {
        $n++; 
        $name = $skyscraper->name . $n; // i.e. sears-tower1, sears-tower2, etc.
    }
    
    // set the page's name to be one we know is unique, i.e. sears-tower1
    $skyscraper->name = $name;
    
    // now when ProcessWire checks uniqueness before saving, it won't throw an error. 
    $skyscraper->save(); 
    
    • Like 1
  2. ProcessWire provides a 404 page that you can modify and customize like any other (and you'll see it in your Page List).

    ProcessWire will automatically display that 404 page when someone attempts to access a non-existent URL.

    If one of your templates is configured to show a 404 page when the user doesn't have access to a page (in Templates > Template > Advanced Settings), then it'll show your 404 page in that instance as well.

    There may be instances where you want to trigger 404 pages on your own from your templates. To do this, use the following PHP snippet:

    throw new PageNotFoundException(); 

    Once you do that, processing of your template will stop and ProcessWire will send a 404 header and display the default 404 page instead (thereby passing control to your 404 template).

    Please note: you should throw the PageNotFoundException before outputting any content in your template.

  3. How did you process all the data you put in the demo ? I mean, you didn't manually create and fill a page for each city/architect/skycraper ?

    I exported a CSV file from freebase.com that contained all the skyscraper fields I wanted to use. Then I created a simple shell script to import it from the CSV. Note that I only used a shell script for convenience, you could just as easily do this from a ProcessWire template file if you preferred it or needed to do this from Windows, etc.

    Below is a simplified example of how to do this. The example is fictional and doesn't line up with the actual structure of the skyscrapers site, nor does it attempt to create page relations or import images. If you are interested in how to do that, let me know and I'll keep expanding on the example in this thread. But I wanted to keep it fairly simple to start. First, here is the contents of a CSV file with each line having a skyscraper building name, city, and height.

    /skyscrapers/skyscrapers.csv (Building, City, Height):

    Sears Tower, Chicago, 1400
    John Hancock Tower, Chicago, 1210
    Empire State Building, New York City, 1100
    IBM Building, Atlanta, 860
    Westin Peachtree, Atlanta, 790

    Next, create a new template in ProcessWire and call it "skyscraper". Create a text field for "city", and an integer field for "height" and add them to the skyscraper template.

    Create a page called "/skyscrapers/" in ProcessWire, that will serve as the parent page for the skyscrapers we'll be adding.

    Here is the command-line script to load the ProcessWire API, read the CSV data, and create the pages. As I mentioned above, this could just as easily be done from a template, where the only difference would be that you wouldn't need the shebang (#!/usr/local/bin/php -q) at the beginning, nor would you need to include ProcessWire's index.php file.

    /skyscrapers/import_skyscrapers.sh:

    #!/usr/local/bin/php -q
    <?php
    
    // include ProcessWire's index file for API access
    // (this isn't necessary if you are doing this from a template file)
    include("./index.php"); 
    
    $fp = fopen("./skyscrapers.csv", "r");
    $template = wire('templates')->get("skyscraper");
    $parent = wire('pages')->get("/skyscrapers/");
    
    while(($data = fgetcsv($fp)) !== FALSE) {
    
    // create the page and set template and parent
    $skyscraper = new Page();
    $skyscraper->template = $template; 
    $skyscraper->parent = $parent; 
    
    // set the skyscraper fields from the CSV	
    list($building, $city, $height) = $data; 
    $skyscraper->title = $building; 
    $skyscraper->city = $city; 
    $skyscraper->height = $height; 
    
    // set the URL name, i.e. Sears Tower becomes "sears-tower" automatically
    $skyscraper->name = $building; 
    
    // save the skyscraper
    $skyscraper->save();
    
    echo "Created skyscraper: {$skyscraper->url}\n";
    }

    To do the import, make the script executable and then run it from the command line:

    chmod +x .import_skyscrapers.sh
    ./import_skyscrapers.sh

    OR, if you are doing this from a template file, then load the page (that is using this template) in your web browser, and that will execute it.

    The output should be:

    Created skyscraper: /skyscrapers/sears-tower/ 
    Created skyscraper: /skyscrapers/john-hancock-tower/
    Created skyscraper: /skyscrapers/empire-state-building/
    Created skyscraper: /skyscrapers/ibm-building/
    Created skyscraper: /skyscrapers/westin-peachtree/

    If you go into the ProcessWire admin, you should see your skyscrapers.

    I used an example of CSV file for simplicity, but the same method applies regardless of where you are pulling the data from (web service feeds, etc). For the actual skyscrapers demo site, I used Freebase's web services feed to pull the data and images, etc.

    • Like 8
  4. Does ProcessWire provide functions/methods to access the DB (connecting, querying) ? Is it possible to use PW to manage (read/write) custom tables ?

    ProcessWire's Database class is extended from PHP's mysqli, so when you access the database you are dealing with a mysqli connection and all the functions and info in the PHP manual applies. From all templates, the $db instance is scoped locally, so you can do this (example):

    $result = $db->query("SELECT id, name, data FROM some_table"); 
    while($row = $result->fetch_array()) print_r($row);

    From modules or any class extended from Wire, the database is scoped via $this->db:

    $result = $this->db->query("SELECT id, name, data FROM some_table"); 
    while($row = $result->fetch_array()) print_r($row);

    From outside ProcessWire classes or in any regular function or non-ProcessWire class, the database can be accessed from the wire(...) function:

    $result = wire('db')->query("SELECT id, name, data FROM some_table"); 
    while($row = $result->fetch_array()) print_r($row);

    Intended for use outside of ProcessWire templates and classes, that wire() function also provides access to all of ProcessWire's API variables, like $page, $pages, and others... i.e. wire('pages')->find('selector');

    Also I should mention that I've never needed to use the $db from my templates. While it's there and ready for you to use, it's always preferable (not to mention easier and safer) to use ProcessWire's API for accessing any of it's data. If you need to create a connection to another database, then make a new mysqli connection (or PDO, regular mysql, etc, according to your preference). ProcessWire does not try to replace PHP's database functions.

    Also, how did you process all the data you put in the demo ? I mean, you didn't manually create and fill a page for each city/architect/skycraper ?

    Good question, I've written a reply, but going to paste in a new thread so that the subject line matches the content.

    • Like 1
  5. How do you recommend I store data in ProcessWire? To keep it simple for example, I'd like to collect results from a Contact Form and store them in PW. If I had to do it, I would create a hidden "Contact Form Results" page. Whenever someone submits the contact form, I would generate a new child page to the "Contact Form Results" Page with the information I've collected. I would then create a template with the fields I need so they are browse-able from the admin interface. Does this seem like a good way to collect the data? It seems like once it's collected, it would be simple to use PW's API to create reports and do anything else I needed to with that data.

    I think your idea is a good way to go. Setting up a page structure should be a fine place to maintain submitted forms. And it should be fairly easy to do. Just be aware that in your templates, you have full unrestricted access to the API. As a result, you shouldn't include anything like: where the page is saved (i.e. parent page or template) in the data that is user-submitted, unless it's well validated. Ideally, the data that gets saved should go exclusively in custom fields that you've created, rather than any built-in ProcessWire fields.

    For all custom fields that contain text, make sure you enable the entities text formatting filter. You'll see the text formatting filters in the field settings when you create it. I also recommend performing some basic validation/sanitization of the data before adding it to the page's fields. Granted there is built-in validation, but I always recommend sanitizing/validating data when it's first accessed, even if it will be done again later automatically. 

    Lastly, make sure the parent page where you'll be storing these contact submissions has the guest role removed (via the 'settings' tab on the page). You don't want these submissions being accessible to anyone but you.

    Here's a basic example to get started. This assumes that you are storing submissions in a child page of /form-results/ and that you have a template called "contact_submission" that contains the fields we are populating. We're populating the name, title (with the fullname field), email and comments fields into a page, then saving it.

    /site/templates/contact-form.inc

    <form action='/contact/' method='post'>
        <p>
        <label>Full Name</label>
        <input type='text' name='fullname' />
        </p>
    
        <p>
        <label>E-Mail</label>
        <input type='email' name='email' />
        </p>
    
        <p>
        <label>Comments</label>
        <textarea name='comments'></textarea>
        </p>
    
        <p>
        <input type='submit' name='submit' value='Submit' />
        </p>
    </form>
    

    /site/templates/contact.php

    <?php
    
    if($input->post->submit) {
    
        // create a new Page instance
        $p = new Page();
    
        // set the template and parent (required)
        $p->template = $templates->get("contact_submission");
        $p->parent = $pages->get("/form-results/");
    
        // populate the page's fields with sanitized data
        // the page will sanitize it's own data, but this way no assumptions are made
        $p->title = $sanitizer->text($input->post->fullname); 
        $p->email = $sanitizer->email($input->post->email); 
        $p->comments = $sanitizer->textarea($input->post->comments); 
    
        // PW2 requires a unique name field for pages with the same parent
        // make the name unique by combining the current timestamp with title
        $p->name = $sanitizer->pageName(time() . $p->title);
    
        if($p->fullname && $p->email) {
            // our required fields are populated, so save the page
            // you might want to email it here too
            $p->save(); 
            echo "<h2>Thank you, your submission has been received.</h2>";
    
        } else {
            // they missed a required field
            echo "<p class='error'>One or more required fields was missing.</p>";  
            include("./contact-form.inc");     
        }
    
    } else {
        // no form submitted, so render the form
        include("./contact-form.inc"); 
    }
    
    
  6. I really need to create pagetype, that will redirect me to first of it's children... I.E.

    - Page 1 {/page1/}

    - Child 1 {/page1/child1/}

    - Child 2 {/page1/child2/}

    and when you click on 'Page 1' in menu, you'll go straight to '/page1/child1/'.

    For pages that you want to automatically direct to the first child, I would make them use a template that has this in it's code:

    <?php if($page->numChildren) $session->redirect($page->child()->url);

    And then, when you add another child, the internal pointer will redirect there.

    If you add a new child page, and they aren't sorted by date added (descending) then the newly added page isn't likely to be the first child. If no default sort is selected, then it'll add it as the last child. So if you wanted to redirect to last page (rather than the first) then you'd want to do this:

    <?php if($page->numChildren) $session->redirect($page->child("sort=-sort")->url);

    By the way "sort" is just a name representing the order that pages have been dragged/dropped to. That's the default value if a page doesn't have another field selected as it's default sort field. The minus sign "-" in front of it represents descending sort. Without the minus sign, it would be ascending. Since you want to select the last page, that's why it's "-sort" rather than "sort".

    Or if you wanted to make it select the most recent page added by date:

    <?php if($page->numChildren) $session->redirect($page->child("sort=-created")->url);

    The above is also descending since most recent added would be the highest date.

    • Like 7
  7. As for adding a class to the current page based on the current's page URL name and the parent's URL name, you have many options. Here's how I might do it, by adding a class to the body tag that would make it possible to target any element on a page in your CSS:

    <body class='<?php echo "page_{$page->name} parent_{$page->parent->name}"; ?>'> 

    If you were on a page with URL "/news/press/", the result would look like this:

    <body class='page_press parent_news'>

    Rather than assigning body classes based on the current page and current parent, I usually find it's more convenient to assign a class based on the current section, or "root parent page" as it's called in ProcessWire. Typically these section pages are those that appear in the top navigation. Having every page identify it's section via a <body> class means we can easily highlight the current section in the navigation with our CSS. So here's how I might output the body tag:

    <body id="section_<?php echo $page->rootParent->name?>">

    If we were on the page /news/press/, the result would be:

    <body id="section_news">
    • Like 3
  8. I think I got the basic idea on how to publish content, but I don't understand how to output lists of content. With most of the projects I'm working on I have a list of recent news, a list of portfolio entries, an image gallery, a list of posts within a category or tagged with a certain tag. I tried to understand what you did in your skyscraper example in SkyscraperList.php, but I've absolutely no idea.

    The skyscraper example is probably not the best one to look at. I built that SkyscraperList.php just to maximize the efficiency and appeal to coders, but it probably made it a lot less clear to designers. It's not necessary to take that approach. The templates that come with the basic/default site are probably a better place to start.

    As far as how to output lists of content, typically you'd follow a process like this:

    1) Find the pages you want to output, typically with $pages->find(...)

    2) Loop through the results and output the fields you want.

    Example:

    <?php
    $news_items = $pages->find("parent=/news/"); 
    echo "<ul>";
    foreach($news_items as $item) 
        echo "<li><a href='{$item->url}'>{$item->title}</a></li>";
    echo "</ul>";
    

    If you wanted ProcessWire to do the above for you, you could do this:

    <?php echo $pages->find("parent=/news/")->render(); 

    (basically added the "render" to the end of the pages find)

    I prefer to generate my own markup for clarity and control, so don't recommend the shortcuts (like above), especially when you are learning. But just wanted to let you know they are there. These two pages provide more detail and examples of how to output lists:

    http://processwire.com/api/templates/

    http://processwire.com/api/selectors/

    With the documentation, I've tried to balance it between the needs of designers and developers, so if you see something you don't understand, don't feel bad about skipping it ... it will probably make sense later, or feel free to reply with questions or post in the forum.

    With regard to lists of images, I haven't yet finished this part of the documentation, but it is similar to working with pages. However, you would need to have an images field to work with in your page's template. I will assume you have one called "images" (like in the demo site). If we wanted to print the images from the current page as 100x100 pixel thumbnails linked to full size versions, we would do this:

    <?php
    foreach($page->images as $img) {
    $t = $img->size(100, 100); 
    echo "<a href='{$img->url}'><img src='{$t->url}' alt='{$t->description}' /></a>";
    }
  9. Client Login: I would want to let people log in to view their images. What do you think the best way to do this is? Obviously I could do it myself without using much ProcessWire - But I am guessing there are some handy things PW can do to help me along and make this job easier. I am thinking I would add them as a user in the admin interface and then give them access to view their private page which no one else can view. Does this make sense? How would I get them logged in through the front interface and have it work seamlessly with PW? I don't want them to see the admin interface...

    The user functions in ProcessWire are probably the least developed part so far, but I think it can still accomplish what you want pretty well. Since ProcessWire assigns permissions to roles rather than users, I think the best bet is instead to create one role for clients, and then we'll check if they have access on the actual page by comparing the page name to the user name.

    1. To start, create a new role in Access > Roles, call it "client" (or whatever), and give it just "ProcessPageView" permission.

    2. Next create a new page that will be the parent of the protected client pages, i.e. "/clients/". Once the page is created, click on the "settings" tab of that page, uncheck the "guest" role, and check the "client" role. Save.

    3. Now create a new template and associated page that will serve as the login form. I'd call the template "login" and the page "/login/". The logic for the login template should be something like the following:

    /site/templates/login.php

    <?php
    if($input->post->login_submit) {
    // process submitted login form
    $name = $sanitizer->username($input->post->login_name);
    $pass = $input->post->login_pass;
    if($session->login($name, $pass)) $session->redirect("./");
    	else echo "<h2>Login failed, please try again.</h2>";
    }
    
    if($user->isSuperuser()) {
    // display links to all the client pages
    echo $page->children()->render();
    
    } else if($user->isLoggedin()) {
    // redirect to client page, if it exists
    $private = $pages->get("/clients/{$user->name}/");
    if($private->id) $session->redirect($private->url);
    	else echo "<p>Your page is not yet setup.</p>";
    } else {
    // display the login form
    include("./login_form.inc");
    }
    

    I split the login form into a separate file, though you could mix it into the login.php file above too. Below is the markup for the login form:

    /site/templates/login_form.inc

    <form action='/login/' method='post'>
    
    <p><label>Username
    <input type='text' name='login_name' />
    </label></p>
    
    <p><label>Password
    <input type='password' name='login_pass' />
    </label></p>
    
    <p><input type='submit' name='login_submit' value='Login' /></p>
    
    </form>

    4. Now create the client template, that will serve as an individual user's private page. I would call it "client", and insert logic like the following:

    /site/templates/client.php

    <?php
    if($user->name != $page->name && !$user->isSuperuser())
    throw new PageNotFoundException("No access");
    
    // if we made it here, you are good to display their photos

    5. Now setup your client pages and client users. Create each client page under /clients/, and make it use the client.php template we setup above. The client's username and page URL name must match, so if your client's username is michelle, then her client page should be /clients/michelle/. Also, when you create each client's user account, give each one the "client" role we created in step 1.

    6. I think that will do it. Let me know if this makes sense or if you have any questions. Also, I'm doing this all off the top of my head (while also checking the API code), so let me know if you find I'm off on any parts too.

    • Like 2
  10. How do I interact with the image field in processwire? For instance, I have a Javascript gallery that takes a certain size image and it's thumbnail to make a browseable gallery. I know PW creates a thumbnail somewhere...but how do I configure the size and access it from the front end?

    To interact with the images field. Create a new field (under Setup > Fields) and call it whatever you want, like "images" for example. Set the field type as "image". Add this field to a template (under Setup > Templates). Then edit a page using that template and upload some images.

    In your template code:

    ProcessWire will create your images at any size on the fly and then keep a cache of them. For instance, lets say we want to cycle through all the images, create a large image at 500 pixel width with proportional height, and a thumbnail at 100x100, and then have the thumbnail link to the large:

    <?php
    foreach($page->images as $image) {
    $large = $image->width(500);
    $thumb = $image->size(100, 100);
    echo "<a href='{$large->url}'><img src='{$thumb->url}' alt='{$thumb->description}' /></a>";
    }
    • Like 3
  11. Sorry for the delayed reply. I've been on vacation for the holidays for a few days, and just getting caught up.

    By "auto-completion" do you mean some kind of filtering ? ie. I start typing something and all elements matching are displayed somewhere for selection ?

    That's correct. The one  in ProcessWire uses jQuery UI's autocompletion widget, combined with a new web services module on the admin that handles the ajax-driven searches.

    And about the multi-selection, a quicker way could be to add checkboxes to items and some button to validate the selection.

    What it has are not unlike checkboxes, in that clicking the item causes it to reverse background/foreground color to indicate it's selected. And clicking it again, switches it back to normal, to indicate it's unselected. This way it just  stands out a little more in a large list than the regular checkbox does, but the idea is the same. Because the selectable items list stays open, there is an optional "close" button when you are done selecting items. It still adds the selected items to the list at the top (like you saw in the video), so that the selected items are summarized and can be sorted. These items are added to that list as you select them, so there is no separate validation from the form submission at present.

    Checkboxes could have multiple usage, the button having a contextual action (could allow deleting multiple items, or changing some common properties like the template associated to a page...).

    Removing the selected item is done from the selected list (via the trash icon), or just by clicking the selected item in the selection list. But I'm confused about what you mentioned with changing page properties (like template) from this field type. At least in the case of the sites I'm using it on, I think there may be confusion if the user is potentially changing properties of pages when selecting items for a field. But I may be misunderstanding. Can you clarify?

    Thanks,

    Ryan

  12. By the way, I'm also developing a auto-completion form control for page selection. It's functional at present, but still tweaking the details. It provides the same unlimited sample size benefit, and obviously with far fewer clicks. But auto-completion is not a true multi-selection tool since you have to know something about what you'll be adding ahead of time (i.e. you need to start typing something before seeing the selectable options). Still, auto-completion is ideal in some cases, so this is on the very near-term roadmap.

  13. I watched your video demonstrating the Page Fieldtype, very cool and all, and I also like your asmSelect plugin and your explanations for its reason to be and its usage, but I think the video also demonstrates that there is a need for some easier multi-selection control ! So many clicks to select one page, then a second one, and a third, ...

    I appreciate your feedback. You are right that there are a lot of clicks. Though the selection sample size was over 3,000 items in more than dozen different possible groups in the hierarchy. I could be wrong (and probably am), but I'm not aware of any other multi-selection tool that works with an unlimited sample size. In this case, the number of clicks can be reduced, but they are there for usability in feedback. Specifically, the clicks relate to:

    • Navigating through hierarchy and pagination, and not showing more than a defined number of selectable elements at a time. This ensures usable scalability regardless of selectable sample size.
    • Providing instant feedback to show where the selected item goes. This part is optional, but can be a worthwhile tradeoff.

    One way to reduce the clicks is to not have the list collapse on each item select. I have this working already, but sitting on it for a bit. I didn't include it initially because I wanted my clients to have the instant feedback of seeing the item added to their list (i.e. click, and see where it goes). It's slower, but more clear. I also anticipated this type of selection as being one that the selectable sample size be unlimited, but the number of items actually selected being fairly small.

    So while you and I may prefer to open the list once and click many items, then close the list when we are done, I was worried that would be too ambiguous for others. Also, having the list collapse on each selection means it stays consistent with the way a regular select (and asmSelect) work.

    But now that I know there is someone else that wants the quicker-style of selection, I will push this forward.

  14. The main thing?  The dynamic resizing of an image in the layout.  I have so many people who just need to move an image, resize it, etc and make the layout look ugly.  They feel if they can do that, then everything is perfect. The undocumented feature? It works in Firefox, not chrome :(

    This is true–unfortunately webkit-based browsers, like Safari and Chrome, don't support the browser-based resize method that is used by TinyMCE to resize elements in the editor (likewise with Opera, I think). Whereas both Mozilla-based browsers and IE8 do support it… though I would never suggest you use IE8. :) Personally, I use Firefox and Chrome equally.

    The solution in webkit-based browsers is to perform your resize in the image editor instead. That uses jQuery UI to handle the drag-resize, which should work just about anywhere. It will perform the same newly resampled, proportional resize that you get in the TinyMCE editor (they both direct to the same PHP script via ajax). If you want to resize an image already in the document, just click it, then click the image icon, and then it'll pop up the editor where you can do a drag-resize. Then click the "insert image" button, and it should place the resized image in your document.

  15. Just thought I would let you know that there is an installer issue using dreamhost.  The software installs correctly, but on the system check there are errors on line 81 and 82.  I would attach a screenshot to show you, but you have the forums limited to a 128k attachment and I am too lazy to put it somewhere else :)

    Line 81 and 82 check the server software. It sounds like Dreamhost must not have that info populated, but I'm assuming they are using Apache, so it should still be fine to continue with the installation (and it sounds like you did). I have updated the install.php file to double check that the server_software variable exists before trying to read a value from it, and that should suppress the error you saw.

    Sorry about the attachment size limit. I just got this forum setup and didn't see that setting–I will try to track it down and fix.

    Thanks,

    Ryan

  16. Hi Marcin,

    The method you posted is one I hadn't thought of before, but it would certainly work just as well as any other. Another variation on it would be:

    if($page->child()->id) {
       // has children 
    } else {
       // does not have children
    }

    Here's the way that I usually do it. This is also what ProcessWire does before it executes the child() or children() methods, to decide whether a query should be executed:

    if($page->numChildren) {
       // has children
    } else {
       // doesn't have children
    }
  17. MarkupCache is a simple module that enables you to cache any individual parts in a template.

    I'm working on a site now that has 500+ cities in a select pulldown generated from ProcessWire pages. Loading 500+ pages and creating the select options on every pageview isn't terribly efficient, but I didn't want to cache the whole template because it needed to support dynamic parameters in the URL. The solution was to cache just the code that generated the select options. Here's an example:

    $cache = $modules->get("MarkupCache");
    if(!$data = $cache->get("something")) {
         // ... generate your markup in $data ...
         $cache->save($data);
    }
    echo $data;
    

    I left the markup generation code (the part that gets cached) out of the example above to keep it simple. Below is the same example as above, but filled out with code that finds the pages and generates the markup (the part that gets cached):

    $cache = $modules->get("MarkupCache");
    if(!$data = $cache->get("city_options")) {
         foreach($pages->find("template=city, sort=name") as $city) {
                 $data .= "<option value='{$city->id}'>{$city->title}</option>";
         }
         $cache->save($data);
    }
    echo $data;
    

    That was an example of a place where this module might be useful, but of course this module can used to cache any snippets of code. By default, it caches the markup for an hour. If you wanted to cache it for a longer or shorter amount of time, you would just specify the number of seconds as a second parameter in the get() call. For example, this would keep a 60-second cache of the data:

    $cache->get("city_options", 60)
    

    I hope to have it posted to GitHub soon and it will be included in the ProcessWire distribution. If anyone wants it now, just let me know and I'll post it here or email it to you.

    • Like 9
  18. This topic has been superseded by the roadmap page.

    Please see that page for the latest items on the list.

    - Pete

    These are a few of the items on the short-term to-do list:



    • Page preview before publish (i.e. page drafts)
    • Autocomplete Inputfield for use with Page Fieldtypes
    • Continue posting new documentation to processwire.com
    • JSON page-selection web services for use by admin modules
    • Customizable page "channel" view, in addition to the sitemap view currently in ProcessWire (Admin > Pages). This will enable browsing, viewing, editing of pages outside their parent/child structure. For instance, this view can match specific properties like having the same template, modified within the last day, or anything that you can match with a selector.
    • Various improvements to the FieldtypeComments module(s), including documentation!
    • Simplification of the roles/permissions system. Specifically making roles assigned to templates rather than pages as the default option, and giving permissions a more clear presentation and selected defaults.
    • Google Maps Fieldtype module
    • Conversion of some core code into plugin modules

    Some other items on the longer-term to-do list include:



    • Tagscript parser that enables you to access most Page/Pages-related API capabilities via a tagscript syntax. Some ExpressionEngine users convinced me this is worthwhile, despite my preference for a pure-PHP based API. This will be developed as a module for those that want it, and it's already in the early stages. It is being patterned off of both ProcessWire 1.x and ExpressionEngine 2.x syntax. Plugin modules will also be able to define new tags.
    • Built-in user form processing with admin tools to list/search/read/update/delete submissions, as well as the ability to import submissions directly to new or existing pages (with direct field mapping).
    • Localization support for non-English languages.
    • Strong versioning system for pages. This would also include multi-level undo and a page version comparison tool.
    • Workflow functions whereby Templates can have custom statuses assigned which affect the state of the pages using them. Access to the custom statuses would be definable by Role (or User) so that any number of workflow possibilities could be supported.

    These lists are not complete, and I'll be adding to them regularly.

    What else do you think should be here?

  19. I am especially interested in how I might get year/month get vars (or URL segments?) and what an example query /code would look to fetch those pages.

    Here's a function that would return all the children in a month. Replace the last param ($field) with the name of the date field you want it to look at, otherwise it defaults to the 'modified' field, which probably isn't what you want (but was what I used to test the function).

    <?php
    /**
    * Return all of the page's children where $field falls in $month and $year.
    *
    * @param Page $page The page that has the children we are finding.
    * @param int $month Month you want to match.
    * @param int $year Year you want to match.
    * @param string Name of the date field to check.
    * @return PageArray All the matching children.
    *
    */
    function childrenInMonth($page, $month, $year, $field = 'modified') {
        $startTime = strtotime("$month/1/$year");
        $endTime = strtotime("next month", $startTime);
        return $page->children("$field>=$startTime, $field<$endTime, sort=$field");
    }
    

    Below is an example of how you might use this function in your template. This code shows examples for both URL segments and GET vars. If you wanted to use URL segments, you would need to go in to the Admin CP, click on Setup > Templates > Your Template > Advanced > URL Segments > Set it to an asterisk "*". That tells it to allow any URL segments to pages using that template. And here is code that first checks for a URL segment, then GET vars, and defaults to current month/year if none is provided.

    <?php
    
    if($input->urlSegment1 && preg_match('/^(\d{4})-(\d{1,2})$/', $input->urlSegment1, $matches)) {
        // A URL segment matched in the format of year-month, i.e. /news/2010-12
        $month = $matches[2];
        $year = $matches[1];
    
    } else if($input->get->month && $input->get->year) {
        // GET vars were provided with the year and month
        $month = (int) $input->get->month;
        $year = (int) $input->get->year;
    
    } else {
        // No year/month provided, so display items from current month
        $month = date('m');
        $year = date('Y');
    }
    
    // display a headline with selected month/year
    echo "<h2>" . date('F Y', strtotime("$year-$month")) . "</h2>";
    
    // find the matching pages
    $children = childrenInMonth($page, $month, $year);
    
    // output a list of the matching pages
    echo "<ul>";
    foreach($children as $child) {
        echo "<li><a href='{$child->url}'>{$child->title}</a></li>";
    }
    echo "</ul>";
    
    
    • Like 3
  20. To get things started in this forum, I'm going to post some of the Q&A from emails that people have sent me.

    I wondered if you had any best practices on how to setup 'news' section(s) within PW (specifically how you setup a site with news to 'scale' over time - yearly, monthly archiving etc.)? Using the example of a wordpress blog style hierarchy where there are automatic ways of filing things rather than just a list of pages under a parent page.

    That's a good question. For most cases, I would not try to create a different page structure for years/months because that's more work and it invites the possibility that the links will change over time as you move pages to archive them.

    After using different strategies over a few years, I think it's better to have a single container page under which all news items will be placed, permanently. Then set that container page's default sort to be by date, so that newer items always appear first. From there, the news page should focus on the newest items, and provide links to past news whether by pagination, month/year links, etc. In this respect, you can treat a page in PW2 in the same manner that you would treat a channel in EE2. There is no problem with scalability… PW2 will run just as well with 10k+ subpages as it would with 10.

    When following that suggestion, these are the only scalability considerations:

    1. You may occasionally have to consider the namespace with the URL "name" (aka "tag" in PW1) field. For example, if you have two news stories with substantially similar headlines, you may have very similar URL name fields. But ProcessWire will enforce that namespace, so it's not going to let you create two pages with the same name under the same parent. What that means is it'll make you modify the page's URL name to be unique, if for some reason it's not. I'm talking strictly about URL names, not headlines or anything like that.

    2. When dealing with news stories (or any place that may have a large scale of pages), you want to pay attention to how many pages you load in your template API code.  If you are dealing with 10k news stories, and load them all, that will slow things down for sure. So the following applies:

    Avoid API calls like this:

    1. $page->children
    2. count($page->children)

    Instead, use API calls like this:

    1. $page->children("limit=10");
    2. $page->numChildren

    $page->numChildren is something that ProcessWire generates for every page automatically, so there is no overhead in calling that, like there is in count($page->children). But if working at a smaller scale, it doesn't really matter what method you use.

    The most important thing to remember is just to use "limit" in your selector when potentially dealing with a lot of pages. That applies anywhere, especially when making things like search engines. So when you want to support unlimited scalability, these are the functions where you want to place limits:

    $page->children(...)
    $page->siblings(...)
    $page->find(...) 
    $pages->find(...)

    The other reason someone might like archiving to year/month is because it makes it easier to link to since you could just link to /news/2010/04/ for instance. But it would be a fairly simple matter  in PW2 to make your template look for "month" and "year" get vars, or a URL segment, and produce results based on those… See the other topic in this forum for one way that you might do that.

    • Like 4
  21. To stay up to date with the project I recommend doing the following:

    1. Subscribe to the e-mail list by entering your email in the sidebar box at http://processwire.com

    2. Follow me on Twitter at http://twitter.com/rc_d - This is where I post general updates about ProcessWire.

    3. Follow ProcessWire on Twitter at http://twitter.com/processwire - This is where all commits to the ProcessWire source code are "tweeted" from GitHub.

  22. A couple people have mentioned that they installed ProcessWire, logged into the admin, logged out, and couldn't find where to login again. The default login URL to ProcessWire is:

    yoursite.com/processwire/ 

    You can also change the login URL by editing the admin page (Pages > Admin) click on the "settings" tab and change the URL name to something else. Just don't forget what you name it otherwise neither you nor I will be able to figure out what the admin login URL is. :)

×
×
  • Create New...