Leaderboard
Popular Content
Showing content with the highest reputation on 08/16/2012 in all areas
-
Awhile back, I made an Ajax API for querying pages in the admin via the ProcessPageSearch module. It is used by [for example] the PageAutocomplete Inputfield. I thought this capability would be useful on the front-end too, so this module brings it to the front-end as a page in your site that you can put wherever you want to. The way you use it is exactly the same as the one in ProcessPageSearch, but this one is a little more strict, given that it's publicly available on the front-end. By "more strict" I mean that you have to define what you want to allow in terms of input and output in the module's configuration. The web service takes it's query from GET variables in the URL and returns results in JSON format. It installs a page called /service-pages/ in your site, and you are welcome to move that page wherever you want. Here is the official page at modules.processwire.com: http://modules.processwire.com/modules/service-pages/ Once installed, you should view the /service-pages/ page that it installs because it outputs detailed instructions and examples on how to use it in your own projects. But here's a few excerpts from what you'll find on that instructions page: Input The /service-pages/ page can be queried with GET variables in the URL to return JSON-format results. The query string should follow a ProcessWire selector format ([field][operator][value]), but modified a bit for use in a URL query string. Here are a few format examples: Specify a single value: ?field=value Specify multiple fields and values to match: ?field1=value1&field2=value2&field3=value3 Specify multiple fields where at least one must match the value. Note use of "," rather than "|", something we had to settle for to make it work as a URL key: ?field1,field2,field3=value Specify one field with multiple possible values (it's fine to use "|" as a separator here): ?field=value1|value2|value3 Note that unlike regular ProcessWire selectors, multiple field=value sets are split with an ampersand "&" rather than a comma ",". Allowed Values The allowed values for field are set with the module configuration. You may also specify the following modifier keyword=value pairs: sort=[field] (Specify field name to sort results by) debug=1 (Enables debug mode producing human readable output) limit=[n] (Specify the max number of pages to return) start=[n] (Specify the result number to start with) include=hidden (Include pages that are 'hidden') Allowed operators The operator demonstrated by the "=" sign in the examples above may be replaced with any of the following operators in the query string: = Equal to != Not equal to < Less than > Greater than <= Less than or equal to >= Greater than or equal to *= Contains the exact word or phrase ~= Contains all the words %= Contains the exact word or phrase (using slower SQL LIKE) ^= Contains the exact word or phrase at the beginning of the field $= Contains the exact word or phrase at the end of the field As an example, this ProcessWire selector: template=property, body*=luxury, bedrooms>5, bathrooms<=3 ...would be specified as a query string to this web service like this: ?template=property&body*=luxury&bedrooms>5&bathrooms<=3 Allowed templates For security, the search will only be performed on pages using templates that are defined in the module's configuration. Output The returned value is a JSON format string in the following format (populated with example values): { selector: "title*=something, template=basic-page, limit=50", total: 2, limit: 50, start: 0, matches: [ { id: 1002, parent_id: 4525, template: "basic-page", path: "/test/hello/", name: "hello" }, { id: 1005, parent_id: 4525, template: "basic-page", path: "/test/contact/", name: "Contact Us" } ] } Each of the 'matches' values will also include all the fields you have specified to appear with the ServicePages module configuration. If an error in the query prevented it from being performed, a JSON string in this format will be returned: { errors: [ "Error message 1", "Error message 2 (if there was one)", "And so on..." ] } The web service honors user view permissions. As a result, if you are accessing this service from a superuser account, you are likely to get pages that others users may not see. Superusers get an "include=all" automatically, unless you override it with an "include=hidden". Returned field values The following field values will be returned for all matched pages: id (integer) parent_id (integer) template (string) path (string) name (string) Any other fields may be included from the module's configuration screen. Pagination To paginate, simplify add a "page[n]" url segment to the request URL, i.e. /service-pages/page2/?template=basic-page&sort=name7 points
-
Since a latest updates to TinyMCE inputfield there's an option to add custom plugins from outside the core to TinyMCE on a per field basis. Here's an example how to add the bramus_cssextras plugin. Ok download the plugin http://www.bram.us/p...xtras/#download 1. create a directory in your site folder i.e. "/site/tinymce" 2. create a plugins folder in it i.e. "/site/tinymce/plugins" 3. put the folder "bramus_cssextras" in there 4. put a content.css in the "tinymce" folder (this is where you can define classes or id's, like: p.lead {...}, ul.list {}, h2.red{ ... } ) (see bramus_cssextras homepage for further infos) 5. now go to the TinyMCE field you want to use it. Under tab "Input" you'll see a "TinyMCE Advanced Configuration Options" collapsed. Open it. 6. add the buttons to one of the theme_advanced_button fields: "bramus_cssextras_classes,bramus_cssextras_ids" if you don't need id's leave it out 7. add the content.css to the content_css field setting like: "/site/tinymce/content.css" 8. add plugin to "Third-party plugin" textarea field like: "bramus_cssextras: /site/tinymce/plugins/bramus_cssextras" as one line. Done. You should now be able to select the class "lead" when cursor inside a <p> tag. Add as much css classes or id's to the content.css as you wish, bramus_cssextras will autodetect them. Have fun.4 points
-
I tested this in one project and it works great! I implemented the WillyC improvements and added the Session prefix to the name. Code is here: <?php class SessionLdapAuth extends WireData implements Module, ConfigurableModule { public static function getModuleInfo() { return array( "title" => "LDAP Authentication", "version" => 100, "summary" => "Allows uses to be authenticated via LDAP", "permanent" => false, "singular" => true, "autoload" => true ); } public function init() { $this->session->addHookAfter('login', $this, 'login'); } public function login($event) { if ($event->return) return; // they are already in $name = $event->arguments[0]; $pass = $event->arguments[1]; $conn = ldap_connect($this->data['host']); if ($conn) { $bind = @ldap_bind($conn, "$name@{$this->data['accountDomainName']}", $pass); if ($bind) { // success // check if they area lready a user in PW $user = wire('users')->get("name=$name"); if($user->id) { $user->pass = $pass; if($user->isChanged('pass')) $user->save(); $user = wire('session')->login($name, $pass); $event->return = $user; return; } else { // create a new user $user = wire('users')->add($name); $user->pass = $pass; $user->addRole('guest'); $user->save(); wire('users')->setCurrentUser($user); $event->return = $user; return; } } else { // fail $event->return = null; return; } } else { // could not connect throw new WireException($this->_('Could not connect to LDAP')); } } static public function getModuleConfigInputfields(array $data) { $inputfields = new InputfieldWrapper(); $field = wire('modules')->get('InputfieldText'); $field->attr('name', 'host'); $field->label = 'Host'; if (isset($data['host'])) $field->attr('value', $data['host']); $field->description = 'The LDAP server hostname'; $inputfields->append($field); $field = wire('modules')->get('InputfieldText'); $field->attr('name', 'accountDomainName'); $field->label = 'Account Domain Name'; if (isset($data['accountDomainName'])) $field->attr('value', $data['accountDomainName']); $field->description = 'The LDAP server domain'; $inputfields->append($field); $field = wire('modules')->get('InputfieldText'); $field->attr('name', 'accountDomainNameShort'); $field->label = 'LDAP server domain (short)'; if (isset($data['accountDomainNameShort'])) $field->attr('value', $data['accountDomainNameShort']); $field->description = 'The LDAP server hostname'; $inputfields->append($field); $field = wire('modules')->get('InputfieldText'); $field->attr('name', 'baseDn'); $field->label = 'Base DN'; if (isset($data['baseDn'])) $field->attr('value', $data['baseDn']); $field->description = 'The LDAP server DN'; $inputfields->append($field); $field = wire('modules')->get('InputfieldCheckbox'); $field->attr('name', 'startTls'); $field->label = 'Use TLS'; $field->attr('value', 1); if (isset($data['startTls'])) { if ($data['startTls']) $field->attr('checked', true); } $field->description = 'Check this option to enable TLS security'; $inputfields->append($field); return $inputfields; } }4 points
-
2 points
-
It won't affect images or files attached to the page if you change the title or name fields - it's all tied together using a unique ID so you can rename things as much as you like. You would need a custom module to auto-generate a URL concatenated from the fields in question and it would depend on how you have certain things set up. I would suspect Make and Model would be Page fieldtypes (see this video, but you'd want to set it up as a Select or Autocomplete rather than a multiple select). The title field itself would be best left as a stock number I think as this can easily be outputted as something like "Stocknum - Make Model" in the <title> tag in your template (which I'm guessing you've already worked out), it's just the URL you'll need a module for and you'll be happy to know that even that shouldn't be too hard. The module would be something like this: <?php class BuildUrl extends WireData implements Module { /** * Basic information about module */ public static function getModuleInfo() { return array( 'title' => 'Build URL', 'summary' => 'Builds a URL on page save based on specific fields.', 'href' => '', 'version' => 001, 'permanent' => false, 'autoload' => true, 'singular' => true, ); } /** * Populate the default config data * */ public function __construct() { } /** * Initialize the module and setup hooks */ public function init() { $this->pages->addHookBefore('save', $this, 'buildUrl'); } /** * Checks if we're in maintenance mode and performs any neccessary redirects * * @param HookEvent $event */ public function buildUrl(HookEvent $event) { // Accesses the $page object $page = $event->object; // We only want this to apply to a certain template if ($page->template->name == 'yourtemplatename') { $page->name = $page->make->name . '-' . $page->model->name. '-' .$page->stocknum; } } } The code above is untested but should give you a bit of a head start. The code only wants to run before save on a page using a certain template - it then gets the name from the "make" field (so it checks the make and fetches the name value from that associated page) and the same for the "model" field, then attaches the stocknum field (just a plain text field I guess) to the end, concatenated with hyphens. Because it runs before page save there's also no need to call save, but some extra checking would be advantageous as some of those fields won't be populated when the page is first saved (i.e. brand new). To install the module, whack that code in a file called BuildUrl.module and place it in your site/modules directory. Then go to the modules section of the admin and check for new modules, then install it (after making changes to suit your fields and template name). EDIT: Some of the settings at the top (autoload, singular) might not be right as I was doing this in a hurry and don't have more time tonight, and I'm not sure the empty __construct function is required, but left it in in case it broke without it. I'm sure someone else who's around later will improve on it with other suggestions2 points
-
We'll use this thread to discuss PW 2.3 features as they are being worked on. I've just added one of the first components. This is the "Page Path History" module. It's now in the PW core as a beta module (uninstalled by default). If you are interested in helping to test, just install the module from Admin > Modules > Page > Page Path History (after doing 'Check for new Modules'). The Page Path History module keeps track of the previous URLs for any pages that have been moved or renamed. It then sets up automatic redirects (301, permanent) to ensure the old URLs redirect to the new ones. This is best demonstrated by a few examples: Lets say you had the page /about/contact/ and you moved it to /contact/. With the Page Path History module installed, anyone accessing /about/contact/ will get redirected to /contact/. You had a page called /our-products/ and you renamed it to be /products/. Any accesses to /our-products/ will now get redirected to /products/. Those are simple examples, but this module can handle more complex situations too: Lets say you had the page /our-products/furniture/whoopie-cushion/ and you did like in the previous example and renamed /our-products/ to be /products/. The /our-products/furniture/whoopie-cushion/ URL will now redirect to /products/furniture/whoopie-cushion/ Later on you decide to rename /products/ to just /inventory/. All the /our-products/ and /products/ URLs will continue to work with redirects. You decide that whoopie-cushion really belongs in /services/ rather than /inventory/, so you drag it to /services/whoopie-cushion/. It's old URL in /inventory/furniture/whoopie-cushion/ redirects to it's new URL. TL;DR (am I doing this right) -- you can move or rename any pages and all the old URLs will redirect to the new, automated behind the scenes, without any thinking on your part.1 point
-
1 point
-
Ok got it. I updated the code above, it produces valid nested ul and even some indentation. Don't even ask why it works, it just works. It's magic.1 point
-
You're having a function in a function and some complexity not really needed here. This is the simplest way: function siteMap($page, $output='') { $output .= "\n\t<li><a href='{$page->url}'>{$page->title}</a>"; if($page->numChildren) { $output .= "\n\t\t<ul>"; foreach($page->children as $child) $output .= str_replace("\n", "\n\t\t", siteMap($child)); $output .= "\n\t\t</ul>"; } $output .= "\n\t</li>"; return $output; } $homepage = $pages->get("/"); $siteMap = siteMap($homepage); echo "<ul>".$siteMap."</ul>"; Edit: Screw it I got something wrong. Edit: updated to really work.1 point
-
Thanks guys, awesome replies and a real insight into how the hooks system works. I'll have a tinker with these ideas and see how I go. Love the way you can hook into PW at different stages and do almost anything. One thing I have struggled with a bit is getting my head around the way the page, pages etc objects work, what they contain and when, but I guess that's just a matter of trying things out. Apeisas commented code above for example was helpful... // $page will keep the page that user has just saved $page = $event->arguments[0]; as I was wondering exactly what $event->arguments[0] was all about! Thanks again guys, the answers on this forum are amazing.1 point
-
1 point
-
One other thing about this module that's maybe interesting from a module development standpoint: It installs a page (/service-pages/), and the template for that page loads and runs the ServicePages module when it is viewed. So it installs the means to run itself, and it's not autoload. I might be wrong, but can't think of another module that does this, and maybe it's a good pattern. At least, I thought it was fun when building it. I've been thinking about building a module starter kit that includes skeletons for various types of modules and install/uninstall patterns (ready to build from), and this type of pattern would be one among a few others.1 point
-
It's neat that the framework can take care of that stuff, but there's nothing stopping you from using sass, less, stylus, coffeescript and whatnot in your projects today, be it with PW projects or other. If you are on Mac you can check out CodeKit. I'm on Windows myself so i haven't used it but i've heard good things. Also, there are many other tools available on all platforms that can take care of compilation, concatenation, minification etc.1 point
-
1 point
-
Sure. I'll put it to github soon. We have few ideas to develop it further. Things like bringing more user details like email, but most importantly map ad groups to roles.1 point
-
Sounds like you may be beyond this need, but just wanted to mention those < > brackets are probably the most important ones to encode (for security), and one of the main reasons to use the HTML entities textformatter. But Textformatter modules are super-easy to create and make them do whatever you want. You can just copy /wire/modules/Textformatter/TextformatterEntities.module to /site/modules/TextformatterGazley.module. Then edit it and change the class name to TextformatterGazley and change the module's title (in the getModuleInfo function). Modify the format() function to do whatever you want. For instance, you could entity-encode and then just decode the < and > entities, if that was your need: public function format(&$str) { $str = htmlentities($str, ENT_QUOTES, "UTF-8"); $str = str_replace(array('<', '>'), array('<', '>'), $str); } Decoding those < and > entities is definitely not something to do with untrusted user input though.1 point
-
This is little different, since you are creating a new page. My comments below with code: public function init() { // now we want to hook after page save, since we are not manipulating the saved page, but creating/removing others $this->pages->addHookAfter('save', $this, 'afterPageSave'); } public function afterPageSave($event) { // $page will keep the page that user has just saved $page = $event->arguments[0]; // you probably want to have some conditions whether or not to do something. If you don't have any conditions here, then you go into a loop. if ($page->id == 12345) { $p = new Page(); $p->template = $this->templates->get("basic-page"); $p->parent = $page; $p->title = "New page under the saved page"; $p->save(); } // Removing of pages, could be in the same if or then some other conditionals. Now we check if field "delete_children" is checked (or has value of 1) if ($page->delete_children == 1) { foreach($page->children() as $p) { $p->delete(); } $this->message("Children removed."); $page->delete_children = 0; $page->save(); } }1 point
-
Soma - scratch the above - I had the path string wrong. My bad. Thanks again!1 point
-
You can add additional configuration in the field setting "tinymce advanced setting" under input tab. There you have a field you can enter key:value for configuration. Like skin-variant: silver The value doesn't need apostrophs.1 point
-
Jeez, I just saw the paragraph stripper! Sorry to waste the bandwidth More senior moments. Chatting away to myself like this is the first sign of madness. I blame RoR.1 point
-
I'm not of much help on the rest of this topic, but since you asked Soma I think the phrase you are looking for is "level of complexity". Your English is still infinitely better than my Swiss1 point
-
@ryan - I did exactly that.. a redirect template, but instead of a field for a url, I used a page input field. Works wonders. Totally happy with this solution, even the redirect is ok IMO. Although easy (like you said) to modify the navigation output to give preference to the page field url instead. I agree wholeheartedly that the navigation in almost all cases should reflect that page tree, and normally that is what happens. This is exactly why I love PW. No joke. I feel like anything is possible and I always end up with an awesome solution that doesn't complicate things.1 point
-
See the section on this page "Using the API to add or remove repeater items": http://processwire.com/api/fieldtypes/repeaters/ (though let me know if I've misunderstood the question) Already did awhile ago.1 point
-
Turns out Marions idea was right, the "real" original image dimensions were 4272 × 2848 – oh, and by the way, the forum is missing an animated smiley banging his head to a table.1 point
-
I generally try to use as little echo lines as possible. My code will be more like this <ul> <?php foreach($some as $else): ?> <li><?=$else;?></li> <?php endforeach;?> </ul> that way i don't have to worry about indention ...1 point
-
Here's a start on creating modules documentation. I still need to write a whole section on hooks, but it's fairly complete in other areas. Please feel free to edit/add to this. http://wiki.processwire.com/index.php/Module_Creation1 point
-
I like the idea of field groups, but perhaps in another approach: Grouping them in the fields overview. On more complex sites I have 30-40 fields which I group by adding prefixes to them like contact_address, contact_person and so on. But it would be nice to define a field group "contact" and sort the field there (collapsible and tabbable perhaps?). Then the possibility to clone whole groups would be ... wait for it ... legendary ;-)1 point
-
Some recent additions for 2.3 that are now in the dev branch (I could use help testing if anyone has time): Added "required" support to all fields I've enabled required field support for all fields in ProcessWire (no need for advanced mode either). Now you get a "required" checkbox on the "input" tab of any field in Setup > Fields > [field]. If you are dealing with a published page and save it, you'll get an error if any required fields are blank. The page will still be saved. So it's more of something to annoy you into completing the required field. But if you are dealing with an unpublished page, it won't let you publish it (in the page editor) until you complete all required fields. While seemingly a small thing, the scope is more broad than it sounds as it applies to a lot of different Inputfields. I could use help testing this one out to make sure I haven't missed anything or introduced any new side effects or issues anywhere in ProcessWire. Other additions Fieldsets can now take advantage of column widths, enabling you to have multiple fields in a column. Fixed some bugs that occurred with fieldsets in tabs and fields getting brought into fieldsets they weren't supposed to. Add Interrobang's PHPdoc comments. Add ability to disable PW from throwing an exception when you call an unknown method (for porl's Twig module and other future ones like it). Clean up and optimize the /wire/templates-admin/styles/inputfields.css - it had some redundancy before. Also added a style to call out required fields. Other admin themes may want to do something similar (see the InputfieldStateRequired style in that file). Some other small things in the commit log (Apr 07-Apr 12)1 point
-
I have learned to read a new language called WillyC. This was no easy feat but with some perseverance i finally succeeded. Writing is still to be mastered though.. :0 What's the biggest thing you have learned?1 point
-
FTFY: Soma is faster than anyone. Ryan's main philosophy is to be 'loved by everyone', thus having like 5k posts, 600 karma and not making difference between question about PW core and children() query Antti is always bragging about how awesome his life is, with all that saunas there. Pfsh please. Pete is on twitter once a year.1 point
-
Here is the first release version of the Blog Profile! http://modules.proce...s/blog-profile/ It is now up on GitHub as well: https://github.com/r...ign/BlogProfile Below is a lot more talk about this blog profile and how it works, but if you just want to install the profile and test it, it's not necessary to read anything further unless you want to. I've simplified this a lot from where it's been. It does all the same stuff on the front-end, but the code behind the site is no longer a huge departure from the basic profile. I've rebuilt this profile 3 times trying to find the right balance between making it as flexible as possible and making it as easy to understand as possible. I think it's got a better balance now than before. It's now at a point where it does everything it always has, but the template code behind it should be a lot more accessible and easy to understand. There is no longer a separate module or API variable. Everything here just happens in /site/templates/ files. Consistent with making it simpler, I've also removed the drag-n-drop theme support. While it was cool to have, it always felt a little dirty introducing some kind of proprietary theme support that was so different from the way I'd build any other site. This thing is pretty darn simple to theme as it is (just edit a CSS file). Maybe we'll take it further in the future, but we don't have many PW site profiles out there right now (1 or 2?) and so I decided this profile needed to stay more accessible on the back-end. How the template files work In ProcessWire there are any number of ways you can use your template files. In this case, we are using our template files (in /site/templates/) to populate 3 variables ($content, $headline and $subnav) and then including an HTML file (main.inc) to output them in the right places. The $content variable represents the center (body) column, the $headline variable represents the text headline of the page, and the $subnav variable represents the navigation that appears in the left sidebar. Once one or more of these variables is populated, the template file includes the /site/templates/main.inc file. That main.inc file is just a big HTML file that outputs the $content, $headline and $subnav variables in the right places. We've made an attempt here to separate most of the logic used in the template files from the output. Most of the markup is generated from files in /site/templates/markup/. These files are included from the template files to output specific things like a blog post, comment, etc. Because a lot of output needs are similar among the various template files, we've created a file called /site/templates/blog.inc that has a few shared functions in it. If you look in any of the template files, you'll see that most of them include blog.inc as the first thing. This blog.inc file also initializes our $content, $headline and $subnav variables, mentioned earlier. Outline of /site/templates/ with this profile /site/templates/blog.inc Shared blog-specific functions included by most site templates. /site/templates/main.inc The main HTML markup file through which everything is output. /site/templates/markup/ Contains PHP files that generate markup for specific things like posts, comments, etc. This is separated from the site templates to make it simpler for you to modify the markup if you want to. This is primarily used by the blog.inc functions, but also included by a couple templates as well. /site/templates/skeleton/ This is the Skeleton CSS framework. It is identical to the one they distribute except we added a wider viewport to it. You probably wouldn't have much need to edit anything in here. /site/templates/styles/ Stylesheets used by the blog profile. The most useful one in here would probably be theme.css, which contains all the color definitions for the profile. /site/templates/scripts/ Javascript files used by the blog profile. Not much is happening in here at present.1 point
-
1 point
-
I've actually got a lot of updates coming for the PageLinkAbstractor module that I was working on in the last couple weeks. Beyond what it was doing before, it now also keeps track of links to deleted pages and deleted images or files. When it detects a broken link, it logs it and optionally emails you about it. It also keeps an alert at the top of the admin screen telling you about it with a link where you can go review it. Once you fix the broken links, it detects they've been fixed and clears the log of fixed errors. Here's a couple of scenarios that it covers: 1. Page /about/ links to /products/widget/ in the bodycopy (TinyMCE) field. The /products/widget/ page gets moved to the trash or deleted. Since /products/widget/ is gone (or at least, not accessible to anyone) the link is broken. 2. Page /about/ has a photo embedded in the bodycopy (TinyMCE) from the /events/bbq-fest/ page. That photo gets deleted from the /events/bbq-fest/ page, which causes a broken image to appear on the /about/ page. Both of those errors would be automatically detected, logged, and emailed to you, so that you can fix them. It's keeping track of this stuff so that internal broken links don't ever get to persist. With these additions, the module is also being renamed to LinkMonitor, LinkNotifier or LinkPolice (still deciding), as I think PageLinkAbstractor is just a bit too technical sounding.1 point
-
soumd problamatic to.me 888 what.wil be if put page.in trash,change.name n tamplate whilst.in trash then un-trash to new pare T? what.abt the recersive gramdchildrens?1 point
-
It's arabic, I believe... and particulary for this: 'يودا من حرب النجوم', translate.google.com said it means 'Yoda from Star Wars'. Other than that, I give +1 to using english. We are international here and we won't understand each other, if we start talking our native languages (except Ryan and few others, there would nothing change. )1 point