-
Posts
16,772 -
Joined
-
Last visited
-
Days Won
1,531
Everything posted by ryan
-
I think for what you are trying to do: provide a simple solution to this particular need, it seems like a good solution. I like it. From a storage perspective, you could make it a little more efficient by using the month numbers (integers) in your encoded JSON rather than the month names, and then unset any blank values from the array before encoding it. This would ensure it's reduced to the smallest encoded format possible. Also, December is spelled wrong in your $months array at the top.
-
Nice job Nico! Just a couple suggestions: Get rid of this line in the code below, you don't need it. It's also not very safe because it will load any page named trash in the site, so if someone has another page named trash anywhere in the site, your API call might load it instead of the one you want. That could be solved by prepending a '/' to the beginning, but you won't even need this line so just delete it: $trash = $this->pages->get('name=trash'); // delete this You are currently doing this: $page->parent = $trash; Instead, it's preferable to use the API function (which is why you won't need $trash anymore): $this->pages->trash($page); For security, in your execute() function, you should add this immediately after retrieving the $page: if(!$page->deleteable()) throw new WirePermissionException("You don't have access to delete that page"); You are already performing this check in your function that adds the action to PageList, which is good. But it's not providing any security unless you also perform the permission check in your execute function().
-
Multi-section site using subdomains and single PW setup
ryan replied to Robert Zelník's topic in General Support
Just thinking about this a little more, another possible approach you could take would be to make your root level of pages consistent with the hostname that it should be accessed at. So your root level of pages might be named like this: /domain.com/ /sub.domain.com/ /other-domain.com/ Then your homepage template file could be the gateway, using URL segments. You'd need to turn on URL segments in the homepage template settings first. Then you'd do this, or something like it (haven't tested, just writing in browser): <?php if(count($input->urlSegments) && $config->httpHost != 'www.default-domain.com') { // convert urlSegments to a URL like: /sub.domain.com/path/to/page/ $url = '/' . $config->httpHost . '/' . implode('/', $input->urlSegments); // get the page. throw 404 if not found. $p = $pages->get($url); if(!$p->id) throw new Wire404Exception(); // render the page and get it's output $out = $p->render(); // URLs will have the httpHost in them, so replace these in the output // so user doesn't see hostname in the URLs $out = str_replace("/{$config->httpHost}/", "/", $out); echo $out; } else { // continue about rendering homepage for default domain } -
Welcome Viking! I agree, that's one of the coolest names ever. I'm originally from Minnesota (USA) and our Football team is named The Vikings.
-
Qwertyeee, your English is fine except that there's no spaces between your words. However, I'm not sure that I understand. I think I need more explanation on this to understand:
-
I kind of like this approach because if you've got the trash open, then accidents are unlikely because it's basically saying that you are here to delete stuff. Also, non-superusers don't have access to trash, so no worries about clients absentmindedly deleting stuff they shouldn't.
-
Adam, that's a pretty slow page render time you had there. I don't think that can be attributed to taking an MVC approach, so am guessing there is some other factor at play that caused the bottleneck. If you want your current template file to be a controller pulling in other views, then use the TemplateFile class and place your view files in a directory like /site/templates/views/ $t = new TemplateFile('./views/list-news.php'); $t->set('items', $pages->find('template=news, featured=1, sort=-date, limit=3')); $out = $t->render(); Your /views/list-news.php file would look like this: <ul> <?php foreach($items as $item): ?> <li><a href="<?=$item->url?>"><?=$item->title?></a> <?=$item->date?></li> <?php endforeach; ?> </ul> If you are using this approach, it is far more efficient and straightforward to keep the foreach() in the view rather than calling up a new view for each item. It also gives the view the opportunity to handle an empty condition (if you want it to), and it prevents separation of the container from the items (i.e. you aren't splitting a <ul> and an <li> in separate files). Another approach (and the one I like to use) is to use a module as a view. I'll create an autoload module that adds a 'renderNews' (or another name as applicable) to the PageArray class. Then I get the output of that view like this: $out = $pages->find('...')->renderNews(); It's almost as easy with a normal, non-autoload module: $m = $modules->get("MarkupRenderNews"); $out = $m->render($pages->find("...")); Of course, the same approach can be done just by including a set of functions as views and calling upon them as needed, though I prefer the structure of modules for this stuff. But the end result is just as simple: $out = render_news($pages->find('...'));
-
You'll probably need to change these lines to be consistent with the approach you are taking with your templates: $page->body .= <<< _OUT That line assumes that you want to append the form to the 'body' field, and that it hasn't already been output. If you are using head/foot includes (like in the default profile), then you'll probably just want to echo the output, i.e. echo <<< _OUT Likewise, you'd want to change any other instances that append to $page->body, and instead echo that output (or assign it to another variable). The bottom of the example says this: include("./main.php"); It has that because it's assuming main.php handles all the output (rather than a head/foot include). So you may want to remove that line.
-
But this isn't a file system, at least not by default. Deleting stuff on a web site should always be done with care. When you delete something, you are potentially affecting other resources linking to it (whether on-site or off-site). When you delete something, you are potentially sacrificing pagerank. Just because something is out of date doesn't mean it should be deleted. If there are still links to it anywhere offsite, your entire site is the beneficiary. Deleting has consequences online and is a much more complex issue than it looks on the surface. So while I don't disagree that a quick delete link would be handy in some situations, I think it's also one of those things that goes against best practices in most website situations. I tell my clients, never delete anything unless absolutely necessary. Don't delete, just stop linking to it. But I know there are still times (like development, etc). So when you need to do quick deletes: click to open the trash. Then click 'move' for the page you want to delete, and drag it into the trash. If we ever have a 'delete' page action built into the core, it'll likely only appear if the trash is open.
-
The way I see it, ProcessWire is designed for this sort of thing as it's a CMS framework. One can pretty easily build a CMS on top of it and that CMS can have a ready-to-go starting point for just about everything you could want at the lower level. Page, field, data management, API, hooks, access control, etc. One never even has to use database queries (though there's a database API var too called $db, if you want it). All of this is driven around an accessible API, and all the complex stuff happens behind the scenes. The front-end Admin that you use in ProcessWire is basically just a web site/application that's built using that API. ProcessWire is a more flexible framework than most in that it doesn't try to force you into anything. If you don't want to use some part of it, you don't have to. You can put your files where you want to. If you want to use MVC, great. If not, no problem. ProcessWire is not your mom. It's meant to be your friend like jQuery. If another project picks up ProcessWire as a back-end CMF, I think that only benefits both projects. It's also a good opportunity to actively maintain a separate pure-framework version of ProcessWire, which is something that I've wanted to do, but didn't think folks would be interested. ProcessWire was a framework long before it was a CMS. The framework is already there (by using the include/bootstrap), so the framework version would basically be a blank version with nothing but a root, 404 and trash page (no admin pages). The only issue I see from the framework perspective is namespace. ProcessWire was originally designed with PHP 5.3 namespaces in mind, so it has some pretty generic class names like "Database". Such class names could very well conflict with another application. So we'd likely rename our classes to be more PW specific, or we'd make PHP 5.3 a requirement and bring namespaces back into the fold.
-
That's a good point, taxes are another thing I don't like to think about more than once a year.
-
You'll want to make a module that looks into ProcessPageListRender::getPageActions. The best existing example of this is the ProcessPageClone module, included with the core modules in 2.2. I suggest taking a look at this module. Here's a description of how it works with regard to adding an action to PageList. I've pulled out and pasted in the functions here that are applicable: <?php /** * Called when the API and $page loaded are ready * * We use this to determine whether we should add a hook or not. * If we're in ProcessPageList, we add the hook. * */ public function ready() { $process = wire('page')->process; if($process == 'ProcessPageList') { $this->addHookAfter("ProcessPageListRender::getPageActions", $this, 'hookPageListActions'); } } /** * Hook into ProcessPageListRender::getPageActions to return a 'copy' action when appropriate * */ public function hookPageListActions(HookEvent $event) { $page = $event->arguments[0]; $actions = $event->return; $actions[] = array( 'cn' => 'Copy', 'name' => 'Copy', 'url' => $this->config->urls->admin . "page/clone/?id={$page->id}" ); $event->return = $actions; } What the above is doing is hooking into the function that figures out what actions to show for each page in the PageList, and then appending an action to it. The array should contain the following: cn - the class name that will be added to the html for this action. It will be appended to ProcessPageListAction, like 'ProcessPageListActionCopy'. name - the text label/name you want it to have in the navigation url - the URL it should link to when clicked on
-
Looking good cbuck! Thanks for reporting back on how it worked. Glad you are enjoying ProcessWire.
-
Assigning pages to a Subnavigation, featuring those pages on homepage
ryan replied to Alex's topic in Getting Started
Most commonly you would use your top-level of pages (those that have 'home' as the parent, in the tree) for your top navigation. Typically you wouldn't use those pages for stuff that would be intended for subnavigation. Assuming subnavigation consists of the children of a top-level page, you can retrieve that top-level page no matter where you are in the structure by referring to the rootParent property of $page. Assuming you have a URL like /a/b/c/ then the pages represented by a, b and c will all refer to 'a' as the rootParent. Very often, I use this for subnavigation: <div id='topnav'><?php echo $pages->get('/')->children()->render(); ?></div> <?php if($page->url != '/'): ?> <div id='subnav'><?php echo $page->rootParent->children()->render(); ?></div> <?php endif; ?> You'll want to do something like this from your homepage template: <?php echo "<ul id='portfolio_list'>"; $items = $pages->get('/portfolio/')->children("limit=6"); foreach($items as $item) { $thumb = $item->image->size(150, 200); echo "<li><a href='{$item->url}'><img src='{$thumb->url}' alt='{$thumb->description}'>"; echo "{$item->title}<br />{$thumb->description}</a></li>"; } echo "</ul>"; -
To literally extend the images field to have more inputs, you would have to make your own Fieldtype/Inputfield to support. See the file attached above (in one of my previous posts) for an example of that--it does take some PHP. Most likely we'll add built-in support for extending the image/file fields in the future (i.e. something you could configure with the field settings). Another approach that some use is to create an 'image' template with one image field, and all the other fields you want to be grouped with an image. Then each page serves as an image with whatever metadata you want. At small scale use, this may be less convenient to manage than having an image field with it all built in. But it is more powerful and scalable to use this approach.
-
E-mail notification? I'm still not getting them, except for direct messages. Did you do anything to get it?
-
WillMorris, Very likely ProcessWire will be a good fit for your need. That bird site would be an excellent example of where ProcessWire does well. When it comes time to build your "taxonomy" post the full scenario here and we'll guide you through the best approach. ProcessWire tends to be very flexible in this regard, and that means that some ways to approach something are better than another. For instance, it would be possible to build this taxonomy in a way that's not very efficient, and likewise possible to build it in a way that's highly efficient. When it comes to building for the large scale, you have to be more careful with approach in order to ensure you aren't accidentally loading 6k pages in 1 API call (as Adam mentioned). Taxonomy is such an unfortunate term. It has a strong resemblance to the term "Taxidermy", which in English means the "art" of creating life-like stuffed animals out of dead animals. Not a mental picture I like. This is why you don't see me use the term taxonomy very often.
-
For that type of multi-site setup, the way that I do it, and I think others are, is to just use symbolic links. So all the sites share the same /wire/ directory, but each have their own /site/ directory. But lets say you've got just one hosting account and want to run multiple sites at the same web root. In that case you need to adjust the config according to the hostname. This is easy to do. Edit your /index.php file and locate this line: $siteDir = "site"; ...and add this after it: if(strpos($_SERVER['HTTP_HOST'], 'other-site.com') !== false) $siteDir = 'other-site'; Admittedly I haven't had a need to try it just yet, but that's the way it's meant to work. So in the above scenario, if someone access your site at 'other-site.com', then it uses the 'other-site' directory rather than the 'site' directory.
-
When you have more than 50 children, ProcessWire starts paginating them in the admin. Anything that has large numbers of children should generally have a default sort assigned to it (like date). I work with several sites that have thousands of pages and ProcessWire is specifically built for this sort of scalability in the admin and the API.
-
All the redirects from the old (SMF) forums to the new (IP.Board) forums are now in place. This includes all the boards and topics. You can take any URL from the old forums (http://processwire.com/talk_old/) and replace the 'talk_old' in the URL with 'talk' and it should redirect to the right place on the new forums. This includes boards, topics, and even pagination within topics. Just in case anyone is interested (Pete?) I'm going to post how to do it, as I'm guessing someone, somewhere will eventually have this need again. And even if nobody is interested, I'm feeling proud of myself and want to type about it. Redirecting all SMF boards and topics to IP.Board (IPB) First, I added the following after the 'RewriteBase' line of IP.Board's .htaccess file: RewriteCond %{REQUEST_URI} ^/talk/index\.php/(board|topic), RewriteRule ^(.*)$ /redirect.php?it=$1 [L,QSA] That basically says: Match any URLs that look like /talk/index.php/board, or /talk/index.php/topic (i.e. SMF style URLs), and send them to my PHP file called /redirect.php (rather than sending them to IP.Board). It sends the URL that was requested in a GET var called 'it' (this is the same method ProcessWire uses). So now that we've got the URLs pointing to our /redirect.php file, we have to make the redirect.php file. Here it is (below). I'm matching the board URLs statically (with a translation array) since there are so few of them. For the topics, I'm going into both the SMF and IPB database and matching them up based on post time and subject. <?php // if redirect.php accessed directly without 'it' get var, then abort if(empty($_GET['it'])) exit(); // static redirects for SMF boards => IPB boards $redirects = array( 'index.php/board,6.0.html' => '/talk/forum/7-news-amp-announcements/', 'index.php/board,7.0.html' => '/talk/forum/8-getting-started/', 'index.php/board,1.0.html' => '/talk/forum/2-general-support/', 'index.php/board,5.0.html' => '/talk/forum/6-faqs/', 'index.php/board,12.0.html' => '/talk/forum/13-tutorials/', 'index.php/board,2.0.html' => '/talk/forum/3-api-amp-templates/', 'index.php/board,3.0.html' => '/talk/forum/4-modulesplugins/', 'index.php/board,11.0.html' => '/talk/forum/12-themes-and-profiles/', 'index.php/board,4.0.html' => '/talk/forum/5-wishlist-amp-roadmap/', 'index.php/board,8.0.html' => '/talk/forum/9-showcase/', 'index.php/board,10.0.html' => '/talk/forum/11-pub/', ); // 'it' contains the URL that was attempted $it = $_GET['it']; // initialize $location, where we will store our found redirect URL $location = ''; if(isset($redirects[$it])) { // see if we have a board that matches our array, so use it $location = $redirects[$it]; } else if(preg_match('/topic,(\d+)\.(\d+)?/', $it, $matches)) { // URL matches the format like: /talk/topic,1234.html (and similar) // so we'll connect a SMF topic ID to IPB $topic_id = (int) $matches[1]; // get the optional starting post number (for pagination) $start = isset($matches[2]) ? (int) $matches[2] : 0; // get the SMF database $db = new mysqli('localhost', 'user', 'pass', 'smf_database'); // find the subject and posterTime from the SMF topic ID $result = $db->query("SELECT subject, posterTime FROM smf_messages WHERE smf_messages.ID_TOPIC=$topic_id ORDER BY posterTime LIMIT 1"); if($result->num_rows) { // found the SMF topic list($subject, $posterTime) = $result->fetch_array(); // sanitize for query $posterTime = (int) $posterTime; $subject = $db->escape_string(trim($subject)); // connect to the IPB database $db = new mysqli('localhost', 'user', 'pass', 'ipb_database'); // retrieve the ID and title_seo from IPB that matches the posterTime and subject $result = $db->query("SELECT tid, title_seo FROM ipb_topics WHERE start_date=$posterTime AND title='$subject' LIMIT 1"); if($result->num_rows) { // found it, build the redirect URL list($id, $title_seo) = $result->fetch_array(); $location = "/talk/topic/$id-$title_seo/"; // add the starting post number if we're redirecting to a page number if($start) $location .= "page__st__$start"; } } } // if no location was found, just redirect to the forums index if(!$location) $location = '/talk/'; // perform the 301 redirect header('HTTP/1.1 301 Moved Permanently'); header('Location: ' . $location);
-
You are on the right track Here's an example that does everything. It lists all the categories, and then lists all the entries within each category. This may not be something you actually want to do, but I'm putting it here as an example that can be translated to different contexts. It assumes your blog entries have a page reference field names "categories" and a date field named "date". $cats = $pages->get("/blog-categories/")->children(); echo "<ul>"; foreach($cats as $cat) { echo "<li><a href='{$cat->url}'>{$cat->title}</a>"; $entries = $pages->find("parent=/blog/, categories=$cat, sort=-date"); if(count($entries)) { echo "<ul>"; foreach($entries as $entry) { echo "<li><a href='{$entry->url}'>{$entry->title}</a> {$entry->date}</li>"; } echo "</ul>"; } echo "</li>" } echo "</ul>";
-
I'm working on 301 redirects and hope to have a solution in place today.
-
Nice job Marc! You've captured the place well and it makes me want to visit. Northern CA is my favorite part of the US. Nice colors, textures, and very readable throughout. Also like the food overlays in the nav rollovers. Are you doing a mobile version for this one too?
-
Thanks to Pete for all his great work in getting this converted and setup! As you can see, most avatars didn't convert over. Since IP.Board makes pretty heavy use of them, please update your profiles when you get a chance (I see you guys above already did). If you need to grab your old avatar pic from SMF, it's still up at running for a few days at http://processwire.com/talk_old/ We'll work out any more details over the coming days (stylesheet tweaks, etc). Let me know if you come across any errors. We had one issue with a corrupted file that we had to replace, so it's possible there are more. But hopefully not. I'm excited to learn all the features of this new forum! Hope that you all like it too. Thanks again to Pete for making this possible!
-
Just wanted to give you guys a heads up on what's going on this week (in order of occurrence): New Forums The forums software is moving from SMF to IP.Board. SMF has been very good to us, but with ProcessWire growing quickly we figured it would be a good time to take the forums to the next level. IP.Board will give us a lot more capabilities than we currently have, while maintaining the same ease of use. I looked at a test version setup by Pete, and I think you guys are going to love it. All of your existing login info will stay the same and all the posts will carry over, etc. It's possible you may lose your profile pic, in which case you'll need to replace it. This change might take place as soon as today, but we haven't decided for sure yet. Let me know if you run into any bugs or issues with the new system once we're up and running. Going live with ProcessWire 2.2 I'm going to be merging the ProcessWire 2.2 source into the stable branch (P21 master) this week. The optional LanguageSupport modules that come with it will still be considered beta. If you are tracking the source with Git, then the PW 2.2 update will come in automatically. If you are downloading the ZIP, then you'll just need to replace your existing /wire/ directory and /index.php file in order to apply the update. PW 2.2 now includes a "page-create" permission on the Templates > Edit Template > Access tab. If you are making use of any non-superuser roles that are able to edit pages, you will need to check the box on any relevant templates to add page-create permission for them. To word it differently, ProcessWire now wants you to tell it which templates a given role is allowed to use when creating a new page. If you don't do anything, than any non-superuser roles that can currently create pages won't be able to until you give them that page-create permission on at least one template. Please let me know if I can provide any more detail here, and I'm happy to assist anyone individually with this too. We won't put out a press release or officially announce ProcessWire 2.2 until the LanguageSupport modules are out of beta and we have some other promotional materials ready. But I don't see any reason to delay making PW 2.2 the stable branch in the source code.