Leaderboard
Popular Content
Showing content with the highest reputation on 08/22/2012 in all areas
-
Modules directory: http://modules.processwire.com/modules/facebook-login/ Github: https://github.com/apeisa/FacebookLogin I didn't have any real reason to build this. I actually started to just browse the documentation of OAuth implementations and discovered that Facebook really does make this easy: http://developers.facebook.com/docs/authentication/server-side/ (header "Example" on bottom of the page) so I decided to implement it. It was also nice way to test the Ryan's method of module that creates page which executes itself (like Ryan's new ServicePages module).4 points
-
I often need to find the closest parent Page of a particular type, and I found that something equivalent to jQuery's closest() function was not available. It's a simple addition to the Page class: /** * Return this page's closest parent matching the given selector. * * If no parent matches the given selector, this function returns a NullPage. * * @return Page * */ public function closest($selector) { $parent = $this->parent(); while($parent && $parent->id) { if ($parent->matches($selector)) { return $parent; } $parent = $parent->parent(); } return new NullPage(); } Please consider including this in the next release.2 points
-
Hi all, My second site made using Processwire - there are still some bits to do such as using a custom video player and tidying some things up but here's what we have so far: (Sorry forgot to add, the site is mildly NSFW) http://marieschuller.com/ Thoughts / criticisms welcome! Thank-you.2 points
-
Good ideas Ralf and Slkwrm. I've added a Language Packs link to the main ProcessWire download page. We may go further with some of these ideas when there is time too.2 points
-
Using your existing example, you could do it this way, which is a little simpler and less code. Basically you'd just add your own 'totalPages' temporary variable to each category… and use that in your output. That way you don't have to retrieve those categories any more than once (it would execute faster too). $categories = $pages->find("template=kom_catlanding"); foreach($categories as $category) { // populate your own made-up variable: totalPages $category->totalPages = $pages->count("template=kom_project, project_services=$category"); } echo "<ul id='catcloud'>"; foreach($categories as $category) { echo "<li><a href='$category->url' class='$category->totalPages'>$category->title</a></li> } echo "</ul>"; If you wanted to sort them by count or something, you could do this: $categories->sort('-totalPages'); // sort most to least2 points
-
Based on what I'm understanding from your last message, I think you should skip keeping the separate table. It just sounds like extra, unnecessary work, unless there's something more to this project that I don't yet understand. Instead, I think you should have your cron job execute a script that bootstraps ProcessWire and takes care of all the adding, updating and deleting of records consistent with the web service you are reading from. This is something that I think ProcessWire is particularly good at, because it's been designed for this from the beginning (it's something I have to do with a lot of my client work). Whether XML or JSON doesn't matter much, as PHP includes the ability to read from either type quite easily. Though like the other guys here, I generally prefer JSON just because it's less verbose and less fuss. If JSON, you'll pull the feed and use PHP's json_decode() to convert it to an array. If XML, you'll use PHP's SimpleXML to convert it to an array. Once you've got the array of raw data, you'll iterate through it and add, update, or delete pages in ProcessWire to make it consistent with the data you are pulling from the web service. Live, working example I think that the best way to demonstrate it is with a live, working example. This one uses the existing modules.processwire.com/export-json/ feed. You might also want to see the feed in human-readable mode to get a better look at the format. Below is a shell script that bootstraps ProcessWire, reads from that feed and maintains a mini "modules directory" site, on your own site. I made this feed so that it can be tested and used on a brand new installation using the basic profile (included with PW). If left how it is, it'll create a mini modules directory site below the '/about/what/' page and use the template 'basic-page' for any pages it adds. But you can run this on any ProcessWire installation by just editing the script and changing the parent from '/about/what/' to something else, and changing the template from 'basic-page' to something else, if necessary. This script assumes that the template used has 3 fields: title, body, and summary. The 'basic-page' template in PW's default profile already has these. If you adapt this for your own use, you'd probably want to change it to use more specific fields consistent with what you need to store on your pages. In this example, I'm just building a 'body' field with some combined data in it, but that's just to minimize the amount of setup necessary for you or others to test this… The purpose is that this is something you can easily run in the default profile without adding any new templates, fields, pages, etc. 1. Paste the following script into the file import-json.php (or download the attachment below). For testing purposes, just put it in the same directory where you have ProcessWire installed. (If you place it elsewhere, update the include("./index.php"); line at the top to load ProcessWire's index.php file). 2. Edit the import-json.php file and update the first line: "#!/usr/bin/php", to point to where you have PHP installed (if not /usr/bin/php). Save. 3. Make the file executable as a shell script: chmod +x ./import-json.php 4. Run the file at the command line by typing "./import-json.php" and hit enter. It should create about 95 or so pages under /about/what/. Take a look at them. Run it again, and you'll find it reports no changes. Try making some changes to the text on 1 or 2 of the pages it added and run it again, it should update them. Try deleting some of it's pages, and it should add them back. Try adding some pages below /about/what/ on your own, run it again, and it should delete them. import-json.php #!/usr/bin/php <?php // replace the path in the shabang line above with the path to your PHP // bootstrap ProcessWire. Update the path in the include if this script is not in the same dir include("./index.php"); // if you want to run this as a PW page/template instead, remove everything above (except the PHP tag) // save our start time, so we can find which pages should be removed $started = time(); // keep track of how many changes we've made so we can report at the end $numChanged = 0; $numAdded = 0; $numTrashed = 0; // URL to our web service data $url = 'http://modules.processwire.com/export-json/?apikey=pw223&limit=100'; // get the data and decode it to an array $data = json_decode(file_get_contents($url), true); // if we couldn't load the data, then abort if(!$data || $data['status'] != 'success') throw new WireException("Can't load data from $url"); // the parent page of our items: /about/what/ is a page from the basic profile // update this to be whatever parent you want it to populate... $parent = wire('pages')->get('/about/what/'); if(!$parent->id) throw new WireException("Parent page does not exist"); // iterate each item in the feed and create or update pages with the data foreach($data['items'] as $item) { // see if we already have this item $page = $parent->child("name=$item[name]"); // if we don't have this item already then create it if(!$page->id) { $page = new Page(); $page->parent = $parent; $page->template = 'basic-page'; // template new pages should use $page->name = $item['name']; echo "\nAdding new page: $item[name]"; $numAdded++; } // now populate our page fields from data in the feed $page->of(false); // ensure output formatting is off $page->title = $item['title']; $page->summary = $item['summary']; // To keep it simple, we'll just populate our $page->body field with some combined // data from the feed. Outside of this example context, you'd probably want to // populate separate fields that you'd created on the page's template. $body = "<h2>$item[summary]</h2>"; $body .= "<p>Version: $item[module_version]</p>"; foreach($item['categories'] as $category) $body .= "<p>Category: $category[title]</p>"; $body .= "<p><a href='$item[download_url]'>Download</a> / <a href='$item[url]'>More Details</a></p>"; $page->body = $body; // print what changed $changes = $page->getChanges(); if(count($changes)) { $numChanged++; foreach($changes as $change) echo "\nUpdated '$change' on page: $page->name"; } // save the page $page->save(); } // now find pages that were not updated above, which indicates they // weren't in the feed and should probably be trashed $expired = $parent->children("modified<$started"); foreach($expired as $page) { echo "\nTrashing expired page: $page->name"; $page->trash(); // move to trash $numTrashed++; } echo "\n\n$numAdded page(s) were added"; echo "\n$numChanged page(s) were changed"; echo "\n$numTrashed page(s) were trashed\n"; import-json.php.txt Running the script as a cron job: You can instruct your cron job to run the script and it should be ready to go. You may want to move it to a non web accessible location for more permanent use. You'll also want to update your bootstrap "include()" line at the top to have the full path to your ProcessWire index.php file, as your cron job probably isn't executing it from the web root dir like you were manually. Running the script as a template file: You can run this script as a template file on a page by removing the include() line and everything above it with this line: <pre><?php Place it in your /site/templates/ directory, add the template from PW admin, and create a page that uses it, then view it.2 points
-
Actually this page already exists in modules section http://modules.proce.../language-pack/ But if such questions arise it's clear that something can be improved. Maybe it's time to proclaim more explicitly that PW is multilingual. I found two places where it's mentioned on a homepage, but, honestly I would never think at the first glance that PW supports a dozen languages. Country flags or something noticeable placed on a homepege would be great and a dedicated link to language packs section too. What do you think, guys?2 points
-
Hi together, i made my first steps with PW an as i know one of the first "problems" i had was the translation. I know that PW has a german translation but who the .... could i find that??!! So i (and certainly much more others) would be VERY very happy when we could have a subpage for Languages in the Download-section?? Like the Post from Nico The structure could be as follow: Language Name - the percentage of finish - untranslated (count) - last change - a download link somthing like this: https://translations.launchpad.net/roundcubemail/+translations What do you guess??2 points
-
Hi. I'm new here and started today to take a look at processwire. I created some fields (repeater, float, datetime...) to insert jobs I've done for my customers. Later I want to get a report of them. I can fill up all needed fields by hand, but is there a way to 1. fill my field "total time" with an calculated value based on my fields "start datetime" and "end datetime"? 2. fill my field "hourly rate" based on the value of my fieldvalue of "user" with wich I want the value of my field "hourly rate" out of the depending user data? Maybe it should be better to set up an form in the frontend to insert all this values and prefill the wanted fields with a little ajax? Any suggestions? Thanks for your help.1 point
-
You can find it in the Roles module options. You need a field "What fields should be displayed in the page listing?", it's hard to overlook it. There you can choose your field. For some reason it shows all available fields, not only those you added to your Role template. Not sure it should be this way, got to ask Ryan about it.1 point
-
I want a $page->nextUntil(); and $page->prevUntil(); ...and if possible a $page->parentsUntil();1 point
-
Couldn't the $page->parents() be used to do this? $found = $page->parents->find("template=overview"); $theone = $page->parents->find("template=overview")->first();1 point
-
It's not clear to me whether you are intending to get 'FieldtypeModules' (as your code says) or 'FieldtypeTemplates' (as your text says), but I don't think that either is what you want. Though you are probably getting the error because those are 3rd party modules that aren't installed by default. If your module needed a 3rd party module installed, then you'd want to have it called out in the 'requires' section of your getModuleInfo() function. But don't think about that much now, because FieldtypeModules/FieldtypeTemplates is not what you want here. Fieldtypes are only applicable to handling data with pages. In this case, you are building a collection of Inputfields to hold your module's configuration data. So what I think you are wanting is something like this: if(!isset($data['mailChimpTemplates'])) $data['mailChimpTemplates'] = array(); // default value $field = $modules->get('InputfieldAsmSelect'); // or InputfieldCheckboxes? $field->name = 'mailChimpTemplates'; $field->label = 'Select what templates to use'; foreach(wire('templates') as $template) { $field->addOption($template->id, $template->name); } $field->value = $data['mailChimpTemplates']; $inputfields->add($field); During your module's regular execution, when you want to access your mailChipTemplates variable, you'll just want to remember that it is holding template IDs rather than template objects. If you wanted to make it hold template objects instead, you could put this in your init() function: $templates = $this->mailChimpTemplates; foreach($templates as $key => $id) { $templates[$key] = wire('templates')->get($id); } $this->mailChimpTemplates = $templates;1 point
-
Thanks for testing guys. I merged all the dev stuff into the master branch yesterday and it's now 2.2.51 point
-
1 point
-
I hope to get some time to finish that data import module. Although I feel like dropping XML support and make it work well with JSON first. JSON is so much simpler data model without all those attributes and other nasty surprises that XML is full of.1 point
-
Why not just specify it in your html output: <a target="_blank" href="<?=$page->get('redirect_url|url')?>"><?=$page->title?></a> If you need an option to choose between opening your redirect page in a new tab/window and the same window you could add a new field to your redirect template, let's call it "blank" and the caption "Open in a new window?" with the type of checkbox. And then check against it in your code. So it would look something like this: $blankAttr = $page->blank ? 'target="_blank"' : ''; <a <?=$blankAttr?> href="<?=$page->get('redirect_url|url')?>"><?=$page->title?></a> Edit: also it should be possible to detect whether your url is intenal or external using some tricky regexp and avoid using additional field, but my knowledge of regexps is very limited so can't advise here. Cheers.1 point
-
Not sure this is what you need, but maybe this post of Soma can help. I didn't use this approach and not sure it makes exactly what you want, but it seems like using it or something similar you could have both category landing pages and service items right under your /leistlungen/ page using urlSegments. You will need a code in your /leistlungen/ page's template that would check if the value of your urlSegment maps to category page (make sure it uses kom_catlanding category template). If so then serve the output for category's landing page. If then urlSegment maps to service item page then serve it. If your service item pages are direct children of /leistlungen/ then, I think, PW should serve them automatically without additional check for it on your part. Wrote it off the top of my head. The wise part of community, please, tell me it's not gibberish1 point
-
Hi, iensteinsboi and welcome! I remember reading your tutorials while learning basics of MODx. Thank you! They were very helpful. You will be amazed of simplicity of ProcessWire and really friendly community here and hope you will soon become a convert. Yeah, I know you love both Drupal and MODx, but I'm sure you will fall in love with ProcessWire as well1 point
-
I guess you got this thing because you used AND operator, not &&. AND has less priority then && and combined with = (assign operstor) instead of == (equality comparison operator) it gave you this strange behaviour. I guess you could also do this, granted your $page->show_url takes values only of 1 and 0: if ($page->project_url && $page->show_url) { //do your thing }1 point
-
Thanks, Pete & Ryan. It was nice while it worked, but it seems to me that it added a bit of admin UI complexity too. Since the number of nested repeaters used was pretty homogenous anyway, we're going to move to a set number of static text fields for those sub-listings. Appreciate the quick support.1 point
-
Hey Ryan, As to the SEO juice of a photo, it's basically in the image file name and the ALT text. Your second suggestion is the better one because it will render a page that has the image and the ALT text whereas the first one would simply get a reference to the unadorned image. Cool suggestions though - as they're not IMG tags, they won't instigate an automatic download. Nice trick! Thanks --Gary1 point
-
I also thought about this in particular when creating an online gallery, it's not as easy but possible. I'm not sure about sizes and page loads as I think google indexes without loading images, I think that's was their image search does. Only limit I know is for tablets and phone that will crash on about 500kb, images are different. The concept would be simple but will require some work and figuring out. You generate a gallery 1 page a image that works with normal urls and segments, then progressively enhance it using ajax to create the page (image page) loading and replacing of the content. In the templates you create a image view with caption that is returned if loaded via ajax. If not requested via ajax you add header and footer from the rest of the site. You can test this with the $config object. A view might look like this (pseudo code): if(!$config->isAjax) { include("./header.inc"); } // get what image should be displayed from ajax request (post) if($config->ajax) { $imgcat = $input->post->category; $imgname = $input->post->imgname; $img = ... // do some magic to get image and output it. } else { // alternatively get the image from urlSegments $imgcat = $sanitize->name($input->urlSegment1); $imgname = $sanitize->name($input->urlSegment2); $img = ... } echo "<figure>"; echo "<img src='{$img->url}' alt='{$img->alt}'/>"; echo "<figcaption>{$img->description}</figcaption>"; echo "</figure>"; if(!$config->isAjax) { include("./footer.inc"); } If a visitor comes through google with the urls segment url, you can do some jquery/js magic to check the url and if usr has js he will get redirected to a url that can fully use your ajax gallery. So if google comes it will browse a regular "static" version, if a visitor comes with js he will get enhanced features. You could also go as far to implement some plugin that allows for history either using hashs or push state. I don't know if there a jquery gallery that would help on this, or if you would have to code it yourself.1 point
-
How much SEO value to photos have anyway? I would think the SEO value would come from the descriptions of those photos, not the photos themselves. So by alternate links and/or sitemap, I was thinking something like this: <li><a href='/path/to/photo.jpg'>Description of photo</a></li> or <li><a href='/path/to/page/photo-jpg'>Description of photo</a></li> In the second example, 'photo-jpg' would be a URL segment and it would instruct the page's template to just display the 1 photo having that name, and with description (in alt tag and/or in the content area).1 point
-
This sounds like a fun project! Does the data need to stay in this external table, or can it live in ProcessWire instead? If the data can live in ProcessWire, your cron job could very easily update the data by just bootstrapping ProcessWire. Bootstrapping is as simple as: include("/path/to/pw/index.php"); One-time importing data from an external source is also very easy to do via the API. So if you can do it, I would just let the data live in ProcessWire instead of an external database, and it'll make the whole job a piece of cake. But if that data needs to stay external, then Sinnut's solution is a good way to go. You would use the DB's primary key (or some other unique column) to serve as the urlSegment that loads the page. You'd setup one page/template to handle all that data, and it would find it like this: $key = (int) $input->urlSegment1; if(!$key) throw new Wire404Exception(); $result = $yourDB->query("SELECT make, model, year FROM your_table WHERE id=$key"); if(!$item->num_rows) throw new Wire404Exception(); list($make, $model, $year) = $result->fetch_row(); echo "<ul>"; echo "<li>Make: $make</li>"; echo "<li>Model: $model</li>"; echo "<li>Year: $year</li>"; echo "</ul>"; Note: enable URL segments on the template where this code is (on the URLs tab), as URL segments are not enabled by default. This is another reason why it may make a lot of sense to keep all the data in ProcessWire. But if you can't do that, it won't be a problem: all you need is for your pages to contain a reference to the primary key of row they map to in your external table. I would suggest using the built-in "name" field for those pages to map to the primary key in your external table, because you know it'll be unique and relevant. But you could always create a separate integer or text field in ProcessWire do handle it too. But lets say you use 'name', then your page templates could load the data like this: $result = $yourDB->query("SELECT make, model,year FROM your_table WHERE id='{$page->name}'");1 point
-
Generally 'product' and 'review' would be two different entities which relate one-to-one or one-to-many. If i understand correctly the products are in your custom table fed by an external resource and you want to make product reviews in the form of PW pages that link to products and use (some of) it's data? Maybe you can tell in a little bit more detail how you would want things to look and work in the front-end (url structure etc.) and in the back-end. www.mynewproject.com -/reviews/ <- list reviews, do some category stuff --/iphone5/ <- single review, PW page which uses some data from custom table1 point
-
If it's a table in PW DB you can do SQL queries like this: $result = $this->db->query("SELECT id, name, title, url FROM yourtablename WHERE id=$id"); Some modules use this , if you look at ProcessRedirects for example https://github.com/apeisa/ProcessRedirects1 point
-
Thanks joshuag. The PageLinkAbstractor module has been expanded and renamed to LinkMonitor. I've been using it for a couple of weeks locally and still have a few bugs to work out, but overall I think it'll be a nice addition. Has anyone had a chance to try out the dev branch yet? I'm thinking about merging it into master here pretty soon, and just want to make sure I'm not the only one that's used it.1 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
-
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
-
Few things that are "nice to know" when building PW modules: Autoload and non-autoload modules: autoload ones are loaded on every page load. So if you need to hook into core, then you probably need autoload. Non-autoload modules are run only by request: $modules->get("myUberModule")->doSomething() When you need hooks? Well.. common things are "do something when page is saved", "alter the output that is generated", "do something before page is accessed" etc.. Actually there is quite a many hooks and best way to find right hook for you need is to ask for it here. Building modules is pretty similar to working with templates. Nothing "special" there. Few notes though: You cannot directly access the PW API variables like $pages, $session, $input etc.. Those are available at $this->pages or wire('pages'). If you have static method(s) in your modules then you need wire('pages') there - so if you want to play it safe always use that (it works on command line scripts also) Modules can have settings - those are very easy to implement (just look examples from other modules that have settings) Modules are cool. init() is run before page is loaded, so if your autoload module needs to know the current page, that is available at ready() method. Forums is your friend, just ask and someone (probably Soma with his quick editing skills) will surely help.1 point
-
Hi Gazley, I think you're doing it the right way by looking at other modules. I'm still new to ProcessWire and just built my first module, will continue to improve it. After reading the docs, I started looking at modules in wire/modules and also downloaded some modules already developed by the pro's ;-) What helps me a lot is to look at the extended classes and implemented interfaces. The code there is pretty well commented! So for example, check out extended classes like "WireData" (Data.php in the core directory), "Wire" and the implemented interfaces. A lot of the magic happens there I still have to learn a lot more about Pw, but once you understand how it works... it is really fun coding and building a module, because the architecture of Pw is amazing!1 point
-
Thanks Oliver. I think the issue here is this: // offer user roles to choose $roles_field = Wire::getFuel('fields')->get('roles'); $field = $roles_field->getInputfield(Wire::getFuel('page'), $roles_field); // HERE $field->label = __("User roles", __FILE__); $field->description = __("Roles given to users created for this type of login by default", __FILE__); $field->value = $value; $field->name = 'user_roles'; return $field; Note the line I labeled 'HERE'. You are asking it to get an inputfield for the 'roles' field in the context of $page. At that time, $page is /processwire/modules/ (template admin) and that page has no 'roles' field. So I think this is unpredictable. Instead, I would suggest doing this: // offer user roles to choose $field = wire('modules')->get('InputfieldCheckboxes'); $field->attr('name', 'user_roles'); $field->label = __('User Roles')); $field->description = __("Roles given to users created for this type of login by default"); foreach(wire('roles') as $role) $field->addOption($role->id, $role->name); $field->attr('value', $user_roles); Just tested here and it works. Also, unrelated, but had a couple other things I wanted to mention: Wire::getFuel('something') is the same as wire('something'). The wire('something') is newer syntax, and you'll usually see the older syntax in the core. But I find wire('something') easier to read, so just wanted to mention that you don't have to use Wire::getFuel() unless you want to. For language translation, __('something'); and __('something', __FILE__); are equivalent. Specifying the __FILE__ saves a little overhead, as PW doesn't need to figure it out on it's own. But for something like a module config, or even your own site templates, it probably doesn't matter much. I've mainly been including the __FILE__ part in getModuleInfo() functions because those do have potential to be called on each request, so every little optimization helps there. Note that none of this is applicable to the $this->_('something'); syntax, but if course that syntax can't be used in a static function. For the top of your getModuleConfigInputfields($data) function, I recommend including something like this: $defaultData = array( 'user_roles' => array(), 'consumer_key' => '', 'consumer_secret' => '', ); $data = array_merge($defaultData, $data); That initializes defaults and makes any corresponding values in $data overwrite them (if present). But if values aren't present, then you don't have to worry about PHP complaining about uninitialized indexes when you are in PW debug mode.1 point