Leaderboard
Popular Content
Showing content with the highest reputation on 08/09/2013 in all areas
-
I pushed an update to the dev branch yesterday that should solve the issue of broken links in textarea/HTML fields when migrating a site between a subdirectory and root, and any other scenario that involves a change to the site's root path. This was previously solved by the the PageLinkAbstractor module, but I've always been on the hunt for a solid core solution. The solution I put in is really basic and simple, and I'm not 100% positive it's the right one, but here's what it does. When editing the settings for any Textarea field, you now have a "Content Type" setting: If you select "Markup/HTML" then it signals FieldtypeTextarea to look for certain attributes to convert when you save the page. Specifically, it's going to convert any local pointing <img src='...'> or <a href='...'> attributes to assume that the site's root is always "/" (at least from a DB storage perspective). Then whenever the field is loaded, it converts them back to the site's actual root. Using this method, any links or images placed in your TinyMCE/CKEditor textarea fields should continue working normally no matter where you move your site. Like PageLinkAbstractor, it doesn't retroactively apply to existing links. It only applies to links/images saved on pages after enabling the option. Unlike PageLinkAbstractor, it keeps the original code in a state that's still portable regardless of whether you later turn off the option or pull the text directly out of ProcessWire's DB. It's not yet had a lot of testing yet, so don't choose "Markup/HTML" unless you want to test it. As of 10 minutes ago, it's now compatible with TextareaLanguage as well.6 points
-
I think this type of thing would be a very different animal from a repeater. While there are similarities, I think the functionality would be a lot simpler to build as its own thing rather than extending repeaters. Not to mention, I'm not sure I'd want to add that complexity to repeaters either. I can't envision a use for this type of field in the sites that I build for my clients, so I'm not likely to build it. But I can see how others would find it useful, I do agree that the idea is fun and interesting. Here's how I think it could be built without getting too complex: The Fieldtype itself would basically just be a FieldtypePage and may not need to be anything more. The Inputfield would be where all the action would happen, and I think a lot of it would be JS fun more than PHP code. When you click "add", the Javascript would append an <iframe> with a "src" attribute pointing to /processwire/page/add/?parent_id=123&modal=1 where "123" represents the predefined parent_id where these pages would go. That "modal=1" in there tells PW's admin to just display the editor and no header/footer, etc., making it perfect for this particular Inputfield. The "add" screen would prompt them for the template, as it already does, and let them add the page there. You could of course restrict the allowed the templates the usual way in the template family settings. Some JS would also have to be used to communicate between the <iframes>s and the parent window. Specifically, when the Save button is pressed in the parent window, you'd have JS trigger the save buttons in the other iframes (which you might choose to hide with JS/CSS). Likewise, JS would need to be used from the parent frame to examine the ID of the iframe/repeater items so that it could be saved to the FieldtypePage. There wouldn't be any need to add new API level stuff, because I think that what's provided by FieldtypePage already provides what this field would need. There would be some other issues to resolve as well, but ultimately the whole thing would be simpler to build than the repeaters if the author is willing to take advantage of iframes.5 points
-
This is my first attempt with Processwire. I must say that I am impressed with this CMS. I know Drupal, Wordpress, Liferay, Concrete5, and so far, PW would be certainly on top of the list now (perhaps at the same level as Concrete5). My mother had made her own website with FrontPage. So all photos are from her, and I did only structure it with Processwire. The site use basically four templates. 1) Front 2) Front-mosaic 3) Mosaic, and 4) Basic (used in the timeline). The site is not finished. It was done in 20 hours (5 hours for the design process, 5 hours structuring the site, 10 hours creating pages and dumping the photos (there are a lot!). http://irenegiguere.com5 points
-
4 points
-
I'm really enjoying your posts too. You've got a gift with words – I find your writing really easy to follow and digest. All the right things explained in an accessible and succinct manner.3 points
-
Make sure that you are more specific with your includes than this. If there was an "inc" directory off of the directory where your module is installed, then you'd want to do this: include($this->config->paths->MyAwesomeModule . 'inc/file.inc'); or this include(dirname(__FILE__) . '/inc/file.inc');3 points
-
I proposed this idea several times already in various threads... right in the repeater thread once it was published. I played with the idea and even tried to work out adapting repeater module, but to no success yet as it gets a lot more complicated than first thought. Since there were no real response or interest I haven't spent more time with it. One try was also to build a block module, but haven't got the time to further develop this and it's in a proof of concept alpha stage, only front-end editing and not backend interface. Searching those seems one of the harder things to solve as it gets complicated, but if using a spider or something it wouldn't be a real problem. Scalability would be another consideration, as I can image people using this then to build vast websites with every block being a page, with repeaters inside resulting in even more pages. You get the idea.3 points
-
Hi Marty, What trouble do you have? Let's say Seminar1 and Seminar2 both have the same template. If a user visits those sites, you should be able to do a check like this: // Check if the current user can access this seminar page if ($page->allowedUsers->has($user)) { // Good! List the Seminar children } else { throw new Wire404Exception(); } ... where allowedUsers is your Page field (checkboxes) for the users. Of course you'd need also to check on the seminar subpages, so that a user can't access them directly: if ($page->parent->allowedUsers->has($user)) { // Good! } else { throw new Wire404Exception(); }3 points
-
Every time I use this module I laugh when it's complete. I just imported 200+ pages flawlessly — Beer:30.2 points
-
SImply replacing a file with the same filename isn't usually a good idea because browser caches may not recognize it as a new file. Not to mention, the filename may have significance for the document, containing version numbers or the like. Basically, a replace by filename has a lot of drawbacks. You need a reference separate from the filename. In ProcessWire, that reference can be a page (for single file fields), or tags (for multiple document fields). For document centric sites, I usually have a dedicated space where file links go, rather than trying to manually link them in rich text editor fields. For instance, a sidebar with links to the files. If I need the links in body copy then I'm going to use a Hanna code there... but prefer to isolate file links to a dedicated and consistent space. If I want to list all the files on the current page with the tag "application" then I'll do this: <h3>Application Files</h3> <ul class='files'><?php foreach($page->files->findTag('application') as $file) { echo "<li><a href='$file->url'>$file->description</a></li>"; } ?></ul> If I want to pull all files with the tag "2013" (current year) from a page /shared/files/ then I'll do this: $year = date('Y'); $files = $pages->get('/shared/files/')->files->findTag($year); if(count($files)) { echo "<h3>$year Files</h3><ul class='files'>"; foreach($files as $file) echo "<li><a href='$file->url'>$file->description</a></li>"; echo "</ul>"; } If I have a page that I always want to print a link to the latest application form, rather than using tags, I might keep an individual page dedicated to that file (with a single file field) below my /shared/ page. $app = $pages->get('/shared/latest-application/'); if($app->file) { echo "<p><a href='$app->file->url'>Download latest application</a></p>"; } Any of this code could work just as well in a Hanna code as it could in a template file. The point here is to abstract files away from filenames, to pages or tags (at least on large document centric sites). This scales well, prevents possibility of broken links, and is simple and foolproof for the client.2 points
-
If $page->viewable() is returning false, then it means one of the following: 1. the page it was given is unpublished 2. the page is in the trash 3. the page has no template file 4. the user has no access to it as a result of access control settings in the page's template, or one of it's parent templates. 5. A third party module is overriding the Page::viewable() function and changing the result. If you are logged in as superuser, then the page will always be viewable unless in the trash or has no template file. In your case, it sounds to me like it's most likely item 3 or 4 above. First, check that you actually have a /site/templates/vendor.php file. If you do, then look at the parent pages used by your pages using the "vendor" template. Do any of them define access?2 points
-
You can add any tinymce config to the field tinymce settings, look at the tinymce documentation what you need. Then enter them in the custom advanced config textarea. http://www.tinymce.com/wiki.php/Configuration3x:cleanup2 points
-
Some of the below could be of value to this conversation http://processwire.com/talk/topic/3998-your-deployment-process/ http://processwire.com/talk/topic/3245-current-local-development-setup/ http://processwire.com/talk/topic/2461-keeping-in-sync/ http://processwire.com/talk/topic/2975-team-development/2 points
-
1) Migrations I had the same problem during my work with Processwire. If you have a team working on a Processwire project where everyone has his own dev server then you need to be able to version the "structure" you put into Processwire and keep it in sync with the template files. I found it to be important to strictly distinguish between structure and data. In 90% of the cases this means templates and field can be seen as structure and pages would be the data. In my current project I tried to use the concept of migrations with Processwire utilizing the phpmig library. If you strictly create all of your "structure" with migrations and never with the Backend UI then it works perfectly, your structure is always in sync with the template files and you can put both in your favorite VCS. To give you an example of how this works: https://gist.github.com/webholics/6191779 2) Structure vs. Data I'd like to add more thoughts to the problem of mixing structure and data in CMSes. This is not a problem only Processwire has, but most CMSes do this (in my opinion) wrong. If your main target user group are developers, it should be possible to keep those things separate in order to enable professional workflows like continuous integration and TDD. This is only possible if you define the structure in code or in config files and not in the database and via a backend UI. It is always the case that template files and structure are strongly depended on each other. One CMS - I'd like to mention here for inspiration - which implements this concept perfectly is Bolt (http://bolt.cm/) . They use YAML files to configure the database models. Bolt then tries to keep them in sync with the database. Maybe it helps to have a look at how they did it.2 points
-
Single page designs are hard in ProcessWire. You either go with RTE-solution (like TinyMCE templates etc) or then with pages/repeaters solution. Neither of those solutions is close to ideal. I think currently best solution can be found in newsletter-systems like MailChimp and MadMimi. Drag and drop different kind of components (like header, images, images & text etc) to build your content. There is of course obvious drawbacks in that kind of content building: you are mixing content and styling together. Sometimes that doesn't matter though (mostly small marketing sites or campaign pages etc).2 points
-
First of all, in my opinion you're giving a bit too much information about your live site here - domain and username, plus no proper sanitation apparently. Luckily the error is before actual login call and no password can be seen . So, as the error message says, your selector value wasn't properly escaped. Looks like you're running a find() with only the raw username given somewhere ("First Lastname" in this case, without the quotation marks). This could be something else, but do remember that all user input should be sanitized before using it in your code. At least run the input through $sanitizer->selectorValue() or do some more specific kind of sanitation depending on the situation. If all the usernames are formed like "first-lastname" then do check that's what you've got in before using the value and handle the error properly.2 points
-
Being able to compose a page of individual blocks on the fly has been requested a couple of times now. I remember asking for something similar some time ago (click). I think the obvious and most comfortable solution would be that repeaters have no fields attached to them but rather templates, or only one template to have the same functionality as we have now. One step further would be that one is able to attach more than one template to the repeater, and then while creating content when you click add item a drop down appears with the template names you added. You choose a template and the next repeater item contains the fields of that chosen template. Next item could be another template and so on. This would be awesome. I would create this kind of behaviour with a module/fieldtype but my knowledge of pw module development and the related api work is not sufficient yet. Sure this kind of structure can now be created with subpages but this is not convenient for clients, since they don't have all the content on one page. One argument I've seen a lot is that there is too less of constraints for content creators/editors so they would mess up things or go nuts with laying out content. But the developer can exactly define which templates are assigned to that repeater. And those individual blocks/templates are very much under control of the dev so I strongly disagree with that argument.2 points
-
currently I'm back working on the ImageManipulator. I've put it into a module that extends PageImage. It integrates nicely into PWs workflow. There are only a few things that I have to solve before I can release it: finishing and testing the watermark-methods write documentation and some examples provide support for imageVariations, namely: removeVariations() with point 3, I already have a method that can be called when in PIM-mode (PageImageManipulator-mode) which unlink all PIM-created files, but I think it would be more comfortable if a user calls one of the PageImage-methods getVariations() or removeVariations() if the PIM-created variations are included in the collections. EDIT: in the meantime, we have had a release already: http://processwire.com/talk/topic/4264-release-page-image-manipulator/ ----- here are a screenshot of my current Testpage2 points
-
@lowlines: you're probably already aware of this, but if you've got a sitemap planned out already and just want to quickly create matching pages, Batcher is very helpful for stuff like that. You should check it out if you haven't already.2 points
-
Hi lowlines and welcome to PW. Not sure if you have seen this module or not: http://modules.processwire.com/modules/after-save-actions/ but it allows you to control what happens after a page is saved. Not sure exactly what would be your best option, but you should be able to hook into before save, eg: $this->pages->addHookBefore('save', $this, 'setPublished'); The setPublished function would then remove the unpublished status for the page. Does that help at all? Also, have you seen: http://processwire.com/api/hooks/ http://processwire.com/api/hooks/captain-hook/ EDIT: Have a read of this: http://processwire.com/talk/topic/2331-doing-additional-logic-after-saving-a-new-page/?p=21881 Talks about doing additional logic after saving a new page and so I think might suit your needs. Might be the addHookAfter('added' that you are looking for, although do you really want to publish a page that has just been created and still only has a title and name field assigned?2 points
-
It's my first post in this area and this barely validates as a "showcase case", but: I've finally managed to update my own Web presence, resulting in flamingruby.com. It's primarily a blog, but some of my projects are on display there too. This site has actually been up for months already -- wasn't going to post it here, but thought it'd be nice to prove that I've actually built something with PW after all.. Being responsive is fairly standard stuff these days. In this case no frameworks were involved, though; it's all hand-made, built from mobile first perspective and based on content alone, instead of predefined breakpoints. Some details I'm still not happy about, so it'll probably get tweaked every now and then, but at the moment things are pretty much in a stable state. Since it's a personal project, I've been slowly adding small tricks here and there, none of which really count as anything "special." One addition made just today, mostly as a proof-of-concept, is a combination of a simple module and new subdomain (static.flamingruby.com) to automatically serve assets from (at least in theory) cookie-free location. This is described in more detail here. For home page I built an importer module (with AngularJS GUI, which was actually quite fun) that periodically pulls content from various feeds.. a bit like what Nico did with his social timeline, but nowhere as cool as that. At the moment content is being pulled from GitHub (for which I had to put together MarkupLoadAtom) and Twitter (which kindly killed it's RSS support just in time, so I'm using rssitfor.me instead.. although that site interestingly spits out Atom and not RSS like one would expect.) That's just about it.1 point
-
ProcessDateArchiver ProcessWire Date Archiver Process Automatically archives pages based on a Datetime field (e.g. /news/2013/01/03/some-news-item/). Behavior - When you add a page with a specified template, the module will automatically create year/month/day archives for it. - When you change the date in a specified Datetime field, the page is automatically moved to the correct year/month/day archive. - When moving or trashing a page, the module will automatically clean up empty year, month and day archives. How to create an archiving rule 1. Go to the Setup -> Date Archiver screen in the ProcessWire admin. 2. Click on Add New Archiving Rule. 3. Specify the template that should be archived (typically the news-item template). 4. Specify the Datetime field that should be used to determine the date to archive by. 5. Specify the template that should be used for creating year archives. 6. Optionally specify the template that should be used for creating month archives. 7. Optionally specify the template that should be used for creating day archives. 8. Click Add Rule. Tips and tricks - Configure the archive templates that will contain other archives to sort its children by name. - Configure the archive template that will contain the news items to sort its children by the specified Datetime field. - You will improve usability if you dont allow the user to create date archives manually. How to Install 1. Install the module by placing ProcessDateArchiver.module in /site/modules/. 2. Check for new modules on the Modules screen in the ProcessWire admin. 3. Click Install for the Date Archiver Process. Module download: https://github.com/u...hive/master.zip Module project: https://github.com/u...ssDateArchiver/1 point
-
This module enables you to limit edit access (by role) to any field in the page editor. This essentially provides field level access control on top of the existing access control system. It removes access to fields within a template, which is something that the built-in access control does not currently do in ProcessWire. This gives you a nice and simple granular control of fields. For instance, you might have two users (with different roles) that have access to edit a page, but only one of them could edit a particular field you had limited access to. Another example might be if you (the superuser) wanted to keep a notes field that only you would see in the page editor. But those are just simple examples, and the possibilities are quite broad. I've been wanting to find a way to provide field-level access for awhile, so this module has been on my mind for a bit. But what motivated me to finish it was a need that came up earlier today by Raymond Geerts in this thread where he needed the ability to limit access to fields on the page's settings tab... this module would do that quite nicely. http://modules.processwire.com/modules/page-edit-field-permission/ https://github.com/ryancramerdesign/PageEditFieldPermission How it works This module hooks in to modify the behavior of Page::editable, which is used throughout ProcessWire, but most notably by Page Edit. This module looks for permissions in the system that follow the name format of page-edit-[field] where [field] is the name of an existing field in the system. When it finds such a permission during a Page::editable call, it checks to see if the roles from the current user have this permission assigned. If they do not, then permission to the relevant field is refused, thereby preventing edit access to the field. This module also hooks into the Page Edit process and simply removes fields that the user doesn't have access to edit, before the form is rendered or processed. How to use it Once the module is installed, you get a set of checkboxes on the module configuration screen. Check the boxes next to each field that you would like it to create permissions for. (Alternatively, you can create the permissions yourself, so this is just a shortcut). You should only create permissions for fields that you intend to limit access to. Once your new page-edit-[field] permissions are created, any non-superuser roles that previously had access to edit those fields will no longer have access to edit them. To give them access, you must edit a role and check the box for the relevant permission.1 point
-
Hi all, I'm a big fan of the Sublime Text 2 text editor and of course of huge fan of ProcessWire, so I went ahead and created a library of PW snippets to be used with the ST2 Snippet system. I followed the PW cheat sheet, and created Advanced and Basic versions. The Advanced version contains only those seen in the advanced mode of the cheat sheet, so if you want the full set, you'll want to get both Basic and Advanced. They are on GitHub here: https://github.com/evanmcd/SublimeProcessWireSnippetsBasic https://github.com/evanmcd/SublimeProcessWireSnippetsAdvanced I've just submitted the Advanced set for inclusion into Package Manager, so hopefully that will be added soon. See the README for more info. Any feedback welcomed1 point
-
More and more, processwire has become my personal haven... I do almost no commercial work with it (I work as a dev, and for payed side-projects I suffer the dread of joomla droppings ) Made this "thing": - http://www.lisboncorrespondent.com/ This is a blog (of sorts) for my father, with make-pretend postcards sent from Portugal. It is essentially a way for me to experiment with and learn a few techs/tools: css 3d transforms (and respective headaches, cross-browser issues, etc) The wonderful angularJS framework Yeoman (build system for js apps, with grunt + bower) Processwire, of course Processwire is amazing for every crazy thing I may ever think up, and using it as a simple RESTy service provider is incredibly simple. Gotchas: This will most likely be a perma-beta site - it is for trying stuff No history back/forward or direct urls - angularJS makes it easy, but it wasn't really my concern. Will have to happen someday, though No SEO whatsoever - I'm perfectly aware that a "blog" in a one page app is a no-no, but again, just toying around Tested with Chrome, Firefox and IE 10, OSX and Win - further compatibility (and mobile) to come Hope you enjoy. And thank you, Ryan, for the wonderful gift of processwire1 point
-
1 point
-
Would tHis could be good way to manage online menu for my restauranto Roderigo Kitchen? Maryla always yell we need online menu we need online menu now customer want to order online and pick up but many customer want pick up Marya she must know. I want customer to come to Roderigo Kitchen for food but want to keep customer happy but Maryla pastor Goodwin say no breast for customer anymore so business need online menu. I say we give customer special surprise after they yelp.com reviews for Roderigo Kitchen. Seem to me this flexibillie page design sound like let me you build menu no? Would cemente5 software be to look at well?1 point
-
1 point
-
The wrapper needs a double pipe, to split. || Will correct this issue soon. Gonna dive into the other issue tomorrow. Thank you for your report.1 point
-
@ryan: I'm afraid that's quite an overstatement, but thank you very much1 point
-
1 point
-
Thank you for your input. My point is still: if we can delete a file with a button, I don't see why we don't have a replace button. Perhaps I am just naive.1 point
-
@host I got hit by the scope again! I guess I should finally start learning PHP from the ground up. Thanks a lot for your suggestion, the following code is indeed working: $parent_id = wire('input')->get->parent_id; echo "id: " . $parent_id; // => 1010 Cheers, Stefan1 point
-
Thanks for your help, but I'm not sure that's what I'm after. I don't want to add edit links to my generated pages, I want to add an extra edit link to the page tree in the back-end so that I can click "modal edit" and have the regular page editor load but in a modal window so I don't have to leave the page tree. This may well gives some pointers though, so thanks.1 point
-
Last thing I want to add is that ProCache is not active when a user is logged in, meaning their requests are all dynamic. Template cache works the same, though can be configured to cache requests for logged in users. MarkupCache is always cached, and doesn't care if the user is logged in or not.1 point
-
I personally do what Apeisa suggested: use ProCache with occasional bits of MarkupCache where it makes sense (like caching renders of large <select> lists or that sort of stuff). Though keep in mind, MarkupCache is only used when ProCache isn't. So MarkupCache is only there to speed up some elements in non-cached page renders. Many sites simply don't have anything that benefits form MarkupCache, so don't make it part of your strategy to use MarkupCache until you find a need for it. ProCache won't be used on any POST requests, so that it doesn't interfere with front-end forms, logins, etc. (Template cache can also be configured to do this). I also usually configure ProCache to not run when specific GET variables are present (or all GET variables, if preferred). This enables you to consider any request containing GET or POST variables as truly dynamic (never cached), and any requests without them as potentially cached requests. ProCache can also cache requests that use URL segments. As a result, in order to increase the pool of potentially cached pages, I will use URL segments instead of GET variables for some high volume requests. Given all this, my suggestion is to use ProCache to cache the default view of all pages where possible. But consider any requests containing POST/GET variables as non-cached, dynamic requests. And if you have any components in your page that are slow to render (like a giant navigation tree or something) then use MarkupCache with those. If your cached pages have elements that need to change daily, hourly, every 10 minutes, etc., then set your ProCache expiration time accordingly. Using Javascript for some elements also enables you to make a cached request look dynamic.1 point
-
I'm thinking this change might be a good idea there? // build a selector to find matching pagerefs // @todo should $selector include check_access=0 or even include=all? $selector = 'include=hidden, '; if($field->findPagesSelector) { // remove the existing include=hidden, only if selector specifies a different include=something if(strpos($field->findPagesSelector, 'include=') !== false) $selector = ''; $selector .= $field->findPagesSelector . ", "; }1 point
-
1 point
-
When creating a new page, there is a get variable set: parent_id=xxxx You should be able to use $input->get->parent_id to do what you want.1 point
-
I would go with ProCache and some MarkupCache here and there (forms with dynamic options, categories lists etc). And of course enough horsepower on server.1 point
-
Greetings, When it comes to flexibility in layout, I can't think of a system that is better than ProcessWire. Let me describe an example of what I had to do for a project I just completed for an arts organization with variations in their "event" pages. Sometimes, these events had multiple images, sometimes only one. Same for text: sometimes the event had text and other times it did not. Then there are combinations of these. (I'll be posting this as a case study soon). Using the same template, I had to shift the layout depending on which combination is true for that event: - Multiple images and text: I display text to the left and a lightbox gallery to the right of the text. - Single image and text: I display text to the left and display a static, full-size image to the right of the text with no lightbox. - Multiple images and no text: I display a lightbox gallery on the left (where the text woukd normally go). - Single image and no text: I display a static, full-size image on the left (where the text would normally go) with no lightbox. Because of the design freedom of ProcessWire, I was able to build some logic into my templates to detect what is going on and render different outcomes. Of course, in my examples above I have coded these variations. I have not allowed the client (for example) to decide randomly where to insert text and/or galleries or single images. In my opinion, I would advise any client against this kind of strategy, as it actually ends up limiting -- not expanding -- each element, and I think it leads to messy sites. As diogo said, there is value in explaining the need to constrain in some ways. Thanks, Matthew1 point
-
In my experience, clients understand and accept very well when you tell them that you created some constrains on purpose. The important is that they look at their website and their friend's website and see why theirs looks much better.1 point
-
I've never come across a client that didn't prefer a rich text editor to the alternatives. The reality is, they like RTEs because it's something they are already familiar with and it's easy for them to use. So I think a better goal is to give them what they want, but place limits upon it so that it can't produce a mess. Just because RTEs+clients can create a mess doesn't mean we have to let them do it. Both our TinyMCE and CKEditor rich text inputfields come very much restrained and prevent the client from creating a mess. CKEditor4 and it's ACF (advanced content filter) seem particularly adept at solving this problem. If you can convince a client to use an LML (Markdown, etc.) or some method of creating content in blocks, then that's fine. But once the next guy comes around showing them "look what you can do in my CMS–it's like using Word", you may be at a disadvantage. Other factors to consider: 1) content maintained by blocks may be significantly less portable through future CMS changes, web service/syndication feeds and such; 2) it may be more difficult to maintain site-wide consistency with the designer's original vision if a site's main content area is a mashup of content blocks. Personally, I would avoid trying to pursue a blocks strategy for most content editors, whether in a CMS that is built around the concept, or via trying to build everything around Hanna Codes. Instead, let the designer do their job and determine consistent and well thought placements for photo galleries, navigation, etc. I see Hanna Code as being better for the exceptions of needing something somewhere, and not something that editors should have to keep as part of their vocabulary.1 point
-
This doesn't have anything to do with permissions, since you don't want to use the admin. The process for this is triggering the PHP code, usually by submitting a form. Here is a very simple example: <?php // on the top of the template file, before any code that echoes content if($input->post->submit){ $title = $sanitizer->text($input->post->title); $p = new Page(); $p->template = $templates->get("basic-page"); $p->parent = $pages->get(1); $p->title = $title; $p->save(); } ?> <!-- later on, echo this form --> <form name="input" method="post"> title: <input type="title" name="title"> <input type="submit" value="Submit" name="submit"> </form>1 point
-
Okay, so here's what I came up with: Goal: Make a branch of pages in the Home tree completely hidden from a "client" role, say of Menus or Sidebars, but that is visible from a tab in the admin's primary menu so that the client is just dealing with pages in the "Home" tree. The end result being just "Pages," "Menus," and "Sidebars" in the primary admin menu. Steps: 1) I make a template called "node" for any parent page that starts a branch of pages that shouldn't be viewable in the Home tree to the client role. This isn't necessary but I feel like it's helpful because now these pages don't resemble the regular page template if the user somehow stumbles upon them. 2) I make a page called "Menus" and assign it the "node" template in the Home tree. All my custom menus are children of this page. 3) I make a page called "Menus" as a child of the hidden Admin page in the Home tree. This causes PW to make a tab with the message about not having a process assigned to it. 4) I make a module that assigns a process to the new template: (http://processwire.com/talk/topic/1272-new-page-nav-in-admin/): class UtilityMenuList extends Process { public static function getModuleInfo() { return array( 'title' => 'Custom Menu List', 'summary' => 'List all custom menus.', 'version' => 100, 'permission' => 'page-edit' ); } public function execute(){ $pl = $this->modules->get("ProcessPageList"); $pl->set('id',1057); // or any other parent page return $pl->execute(); } } Here we set the ID to the "Menus" page from step 2. This is the branch of pages we want to appear on the Menus tab. 5) We go back to the Menus admin page from step 4 and choose UtilityMenuList from the Process field. This makes PW show a Home tree that only includes the Menus branch. 6) Now we want to exclude the Menus branch from being visible on the Home tree, since that should only show "regular" Pages. I followed Soma's tutorial here for extracting branches from the JSON, since it's not apparent how to hook into ProcessPageList according to this thread: http://processwire.com/talk/topic/1272-new-page-nav-in-admin/. We create another module: <?php /** * Utility Hide Nodes * * Hides pages with a node template from display in the admin. * * ProcessWire 2.x * Copyright © 2010 by Ryan Cramer * Licensed under GNU/GPL v2, see LICENSE.TXT * * http://www.processwire.com * http://www.ryancramer.com * */ class UtilityHideNodes extends WireData implements Module { public static function getModuleInfo() { return array( 'title' => 'Hide Node Pages', 'version' => 100, 'summary' => 'Example module to hide page in the admin per user per page. Add a page field "pagelist_hidden" with a PageListSelectMultiple input type to the user template. Select or add pages you want to hide in the admin.', 'href' => '', 'singular' => true, 'autoload' => true ); } public function init() { // only add hook only if the render parameter is set // (as used by ProcessPageList) if(!isset($_GET['render'])) return; $user = $this->user; $roles = $user->roles; // loop thru each role foreach($roles as $role) { if (!$role->pagelist_hidden) return; } $this->addHookAfter('ProcessPageList::execute', $this, 'pageListHiddenPages'); } public function pageListHiddenPages(HookEvent $event){ $user = $this->user; $roles = $user->roles; foreach($roles as $role) { foreach($role->pagelist_hidden as $hidden_page) { $hidden[] = $hidden_page->id; } } // make sure it's an ajax request if($this->config->ajax){ // manipulate the json returned and remove any pages found from array $json = json_decode($event->return, true); foreach($json['children'] as $key => $child){ if(in_array($child['id'],$hidden)) unset($json['children'][$key]); } $json['children'] = array_values($json['children']); $event->return = json_encode($json); } } } 7) I altered Soma's code to make it work with roles. We go to the Role template instead of User and add a new field called "pagelist_hidden" of the type Pages, with the following settings: Details = Multiple Pages (PageArray) and InputFieldType = PageListSelectMultiple. This will let us choose specific pages to make hidden from the Home tree on a role-by-role basis. 8) In my case I have a "client" role, so I assign this field to the Role template and then pick my Menus branch on the "client" role. 9) If I log in as the client role, the Menus branch doesn't appear at all in the Home tree, but I can still see it in the branch that gets outputted under my new Menu tab. So as a result we can add as many tabs as we need (potentially to create the illusion of more content types beyond pages) and hide as many branches thru the admin interface by simply adding them to the client's user role. The Menus parent page still appears on this tab, which is unfortunate but not so bad. If this were a Blog section, it would still make sense visually. I just set the parent to be uneditable, that way the client can't mess with it, but the children are still editable. Next step would be... can we somehow paginate a branch? Anyhoo it's pretty neat so far. Edit: Altered Soma's code to work with roles & not individual users.1 point
-
Sweet, I'll check that out tomorrow. RE: the article; I appreciate the article's discussion of a "master geography" or single kernel of truth, suggested by the system, as the basis for all relationships between content types. I also agree with Ryan's comment in the article about how we need a master tree so that content doesn't get disconnected from the URL maps that the Web/Google depends on. I guess when I say I'd like to bucket out content in the admin, I don't mean to actually separate the content from the "home" tree. That is, it looks like all pages, no matter what templates they use, live off the "home" tree in PW and are connected to it, whether they generate real URLs or not. What I'd like to try and do is make separate tabs/admin pages for content like sidebars, widgets/blocks, and menus since they don't have URLs in the front end, and definitely do behave differently than regular pages in the system (since, for example, there are things like custom menus, global sidebars, and global widgets/blocks and so on). I think this might be as easy as having a page called "Sidebars" in the hierarchy that's hidden from the "home" tree (excuse my lack of familiarity with the PW terminology here), but made visible, with all its children (presumably the individual sidebars that can be assigned to pages throughout the site, and their child widgets), if you visit a tab like "Sidebars" in the main admin navigation. Same for menus. So really, for me, it'd just be a matter of making a new admin page that can be linked to from the main navigation, and then listing out a particular subtree of the home tree. As far as philosophy's concerned, my driver's really the client; my experience is that they have less success searching for stuff that behaves like an attachment to the real content in a tree than in its own cordoned-off little area.1 point
-
Yep, this is great module. I also want to encourage people to write their own import scripts. It is simpler than you can believe and you can re-import easily.1 point
-
1 point
-
Just thought of a module I might want to build - just wanted to share the idea and see if anybody else would be interested. The Page List tree-view is great for most things - but it's not necessarily the ideal interface for things that aren't structured. For things that are just flat lists, I'd like to have a tabular admin interface - a grid view with columns, and eventually with sorting and filtering functions, though not necessarily in the first version. I'd like to have an admin interface from which you can create table views as needed - e.g. give it a title, select the Template, select the parent Page, and optionally enter a custom selector. Tabular views would be accessible from the "Pages" menu. Thoughts?1 point
-
Thanks for posting Soma, this is an interesting approach and not one I've seen before, but it looks great. The underlying concept and result is similar to the approach I usually use. Since you posted a good description, I'll try to do the same for mine. The only reason you see head/foot files in the default PW profile is because it seems to be simpler for new users to grasp. But I almost never use that approach in my own sites. Like your system, I have a main.php file which is my main markup file. But unlike your system, main.php is included from all the other template files (rather than main.php including them). The other template files focus on populating the key content areas of the site, specific to the needs of the template. Examples of key content areas might include "main" (for center column/bodycopy) and "side" (for sidebar/related info), though often includes several other identified areas. But I'll keep it simple in this case. Here's how it works: basic-page.php <?php $outMain = "<h2>{$page->subtitle}</h2>" . $page->body; if($page->numChildren) $outMain .= $page->children->render(); // list the children $outSide = $page->sidebar; include("./main.php"); main.php <html> <head> <title><?php echo $page->title; ?></title> </head> <body> <h1><?php echo $page->title; ?></h1> <div id='main'><?php echo $outMain; ?></div> <div id='side'><?php echo $outSide; ?></div> </body> </html> The benefit of this approach is that basic-page.php can setup whatever it wants in the key content areas ($main or $side) whether simple like in this example, or something much more complex. I actually prefer for the variables representing the key content areas to be optional. In the scenario above, $outMain and $outSide would have to be defined by every template or they would end up as uninitialized variables in main.php. As a result, I actually use $page as an anonymous placeholder for these variables (making sure they don't conflict with any existing field names) and then let main.php assign defaults if the calling template didn't specify one of them. For example: basic-page.php <?php $page->outMain = "<h2>{$page->subtitle}</h2>" . $page->body; if($page->numChildren) $page->outMain .= $page->children->render(); // list the children // note: no $outSide specified include("./main.php"); main.php <?php // setup defaults when none specified if(empty($page->outMain)) $page->outMain = $page->body; if(empty($page->outSide)) $page->outSide = $page->sidebar; ?> <html> <head> <title><?php echo $page->title; ?></title> </head> <body> <h1><?php echo $page->title; ?></h1> <div id='main'><?php echo $page->outMain; ?></div> <div id='side'><?php echo $page->outSide; ?></div> </body> </html> Final thing to point out here is that main.php is the only template actually outputting anything. Because basic-page.php (or any other template) is determining what's going to go in that output before it is actually sent, your template has the opportunity to modify stuff that you might not be able to with other methods. For instance, the <title> tag, what scripts and stylesheets are loaded, etc. Here's the example above carried further to demonstrate it: basic-page.php <?php // make a custom <title> tag $page->browserTitle = $page->rootParent->title . ": " . $page->title; $page->outMain = "<h2>{$page->subtitle}</h2>" . $page->body; if(count($page->images)) { // display a clickable lightbox gallery if this page has images on it $config->scripts->add($config->urls->templates . "scripts/lightbox.js"); $config->styles->add($config->urls->templates . "styles/gallery.css"); $page->outMain .= "<ul id='gallery'>"; foreach($page->images as $i) { $t = $i->size(100,100); $page->outMain .= "<li><a href='{$i->url}'><img src='{$t->url}' alt='{$t->description}' /></a></li>"; } $page->outMain .= "</ul>"; // add a note to $page->title to say how many photos are in the gallery $page->title .= " (with " . count($page->images) . " photos!)"; } if($page->numChildren) $page->outMain .= $page->children->render(); // list the children include("./main.php"); main.php <?php // if current template has it's own custom CSS file, then include it $file = "styles/{$page->template}.css"; if(is_file($config->paths->templates . $file)) $config->styles->add($config->urls->templates . $file); // if current template has it's own custom JS file, then include it $file = "scripts/{$page->template}.js"; if(is_file($config->paths->templates . $file)) $config->scripts->add($config->urls->templates . $file); ?> <html> <head> <title><?php echo $page->get('browserTitle|title'); // use browserTitle if there, otherwise title ?></title> <?php foreach($config->styles as $url) echo "<link rel='stylesheet' type='text/css' href='$url' />"; foreach($config->scripts as $url) echo "<script type='text/javascript' src='$url'></script>"; ?> </head> <body> <h1><?php echo $page->title; ?></h1> <div id='main'><?php echo $page->get('outMain|body'); // use outMain if there, or body otherwise ?></div> <div id='side'><?php echo $page->get('outSide|sidebar'); // use outSide if there, or sidebar otherwise ?></div> </body> </html> More than half the time, I'll actually just re-use page variables like $page->body and $page->sidebar rather than $page->outMain and $page->outSide. That way there's no need to consider defaults, since $page->body and $page->sidebar untouched technically are defaults. <?php $page->body = "<h2>{$page->subtitle}</h2>" . $page->body . $page->children->render(); But technically you've got a little more flexibility using your own self-assign anonymous variables like outMain and outSide, so figured I'd use that in the examples above. outMain and outSide are just example names I came up with for this example and you could of course name them whatever you want.1 point