-
Posts
17,231 -
Joined
-
Days Won
1,699
Everything posted by ryan
-
Where does the error message appear? it should be in the /site/assets/logs/errors.txt file for the site where the error occurred (unless the sites are sharing a common /site/assets/logs/ dir?). Let me know, I can add a hostname to the error log.
-
How to get image scaled down proportionally (given a constraint)
ryan replied to landitus's topic in General Support
You can specify 0 for the width or height to have it be proportional to the other dimension. Or you can just use the width(x) or height(y) functions rather than size(x, y) function. So in your case, I think what you are asking for is this: $image = $page->image->width(400); -
This isn't something that's on the roadmap. URLs of file-based assets are usually something that's behind the scenes and not something that the user or the administrator typically interacts with directly. We use this to our advantage and ensure that files are stored in a manner that is organized, can scale, limits potential name conflicts, and relate to their source. This ensures the CMS can effectively manage them with a page, avoid file system limitations, and recover from errors. I would see a common directory like /pdfs/ as being more the forte of something like a media manager that exists independently of pages. And that may be something that we'll see as a 3rd party module at some point.
-
This isn't possible using the default file and image fieldtypes, though anything is possible when making your own fieldtypes. A workaround that may be possible is to create a page called 'files' and set it's template ('files-gateway') to have URL segments ON. The page/template could then execute a search for the file (in field 'files') and redirect to it, or perform a passthrough. So it'd work something like this: Page: /pdfs/ run by template 'files-gateway' with this code in the template file: <?php if(!$input->urlSegment1) throw new WireException("No file specified"); $filename = $sanitizer->pageName($input->urlSegment1); $p = $pages->get("files=$filename"); if(!$p->id || !$p->viewable()) throw new Wire404Exception("File not found"); $session->redirect($p->files->get($filename)->url); // redirect to it So an access to /pdfs/my-file.pdf would redirect to the right file. You could also perform a passthrough, where you literally feed the file to them right here, but that's a little less efficient.
-
Since you are wanting to do next/prev with single products, I don't think you'll want to use PW's pagination at all. I think this also makes sense given that you want the URL to reflect the product name rather than a page number. So if I'm understand your example correctly, I think you'll want to do something like this: <?php $cat = the current category page; $product = the current product page; $products = $pages->find("parent=/ad-products/, categories=$cat"); $prev = $product->prev($products); $next = $product->next($products); if($prev->id) echo "<a href='./{$prev->name}'>Previous: {$prev->title}</a> "; if($next->id) echo "<a href='./{$next->name}'>Next: {$next->title}</a>";
-
Okay, hopefully someone else will reply that understands. This happens to me regularly where I don't understand something, but someone else comes in and understands perfectly. I will also come back and read this again when my mind is not tied up on so many work projects.
-
I added core support (in the dev branch) for directing to different /site/ directories based on domain or subdomain. I don't like telling people to make changes to the /index.php file since that's something that should be overwritten on updates. So figured I needed to provide an alternate approach here. If you have the /dev/ branch, take a look at the file /wire/index.config.php. Copy or move that file to your web root (or dir where PW is installed). Edit it and there are instructions on how to configure it. Each alternate /site-domain/ directory should be configured to use a different database. So the best bet is to do one of the following: 1. Copy the entire /site/ directory to a new /site-domain/ directory. Edit /site/config.php and supply new database information (seen at the bottom). Export your main PW site database, and import it to the new DB used by your alternate domain. 2. OR: install more copies of PW on your server (like in directories). After running through the installer, move their site/ directory to the /site-domain/ directory in the main PW install, and then delete any other installed copies as you don't need them anymore.
-
Thanks Marc, I will plan to put in this update soon.
-
I've always held Textpattern in high regard, so it makes my day just to hear that the developer thinks the idea has merit. I wouldn't expect them to pursue the idea, especially given the time they've already invested. There are probably larger considerations than it appears on the surface, especially for someone that authors a CMS. I also don't think it solves everything they are trying to do. For instance, PW already has a strong hook system in place, whereas their need is to support an existing one and maintain compatibility with it. Their list also indicated one of the goals as database independence, and PW is dependent on MySQL and certain aspects like indexes (fulltext indexes for example, which are far from universal). On the other hand, I do think PW as a framework would solve MOST of the things they are wanting to do, just not all of them. But that's only a surface evaluation and there may be much more to it when considered in the context of the TXP system, history, requirements, code as a whole. That's not something that I think any of us can evaluate. And especially not me, since I don't have much experience with TXP. But I think the best thing I can do is just express support and enthusiasm for the idea should it ever become a consideration. Lots of respect to Textpattern as a long running quality platform and group of folks that knows how to build a great CMS.
-
Assigning pages to a Subnavigation, featuring those pages on homepage
ryan replied to Alex's topic in Getting Started
I'm guessing that you are getting that error because $item->image has no file attached. Also, we're assuming your field is named 'image'. But since it's possible items may not have images, you'd want to put this as the first thing in your foreach($items as $item): if(!$item->image) continue; // skip because there is no image In that case, replace $page->rootParent->children()->render() with $pages->get("/portfolio/")->children()->render(); -
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.