Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 12/09/2014 in all areas

  1. Sup. FieldtypeOpenWeatherMap [GitHub] This module fetches and stores current weather data from the OpenWeatherMap.org service and helps you manage icon markup. To limit requests, OpenWeatherMap.org’s JSON-response is cached in the database and only refreshed once the field is accessed and the cache has a certain age that you define. The fieldtype is sadly not multilingual, but you can configure the language of the weather descriptions OpenWeatherMap.org provides you with. It would not be hard to make the output multilingual by referencing weather codes and translating them with ProcessWire’s built in tools. You install FieldtypeOpenWeatherMap just like any other module, by placing the two files into ProcessWire’s modules directory. Once installed, you want to create a new field of the type OpenWeatherMap and assign it to a template. The template now has a text field that stores a city id. In the field settings, you may configure how and when the data is requested. That is, the requested language, units (eg. °C/°F/K) and the cache duration. The module does not provide you with built in icons or otherwise limits you to predefined markup (which I consider a good thing ). The icon in my example above is courtesy of Alessio Atzeni’s Meteocons (custom free license). To make generating icon markup a little easier, you can configure your own markup snippets in the module configuration: As you can see, in this example I’m using an icon font whose appearance is defined elsewhere in my CSS, but you’re free to put in image urls or just unicode entities or whatever. Rendering it is now quite simple. The following markup would result in something like the image above: <?php $w = $city->weather; $temp = round($w->temperature); ?> <p><?php echo "{$w->renderIcon()} {$w->description} at {$temp} °C"; ?></p> <h2><?php echo $city->title; ?> <span class="ico-rightarrow"></span></h2> <!-- irrelevant line --> The variable $w is now a WeatherData object that exposes the following properties: json //The raw JSON response from OWM timestamp //The time of the request city_id //The city id you entered in the admin sunrise //The time of sunrise sunset //The time of sunset main //The main weather name, e. g. “Rain”, in the configured language description //A slightly longer, more precise description like “occasional rain” iconcode //The internal icon code for this weather temperature //The temperature in the format you requested min_temperature //... max_temperature //… wind_speed //I believe the wind speed is also affected by the unit settings. As well as the method renderIcon(), which you already know. If you access a WeatherData object as a string, you will get the city id. This is so that the city id will correctly appear in the admin page edit form. I should mention that there is some more information in the JSON, such as wind direction. The module also exposes the method multiRequest(PageArray $pages, $fieldname). If you want to fetch data for a bunch of pages at the same time, you may want to use that so as to reduce unnecessary requests to the service. I haven’t really used this yet, so consider it experimental, I guess. As of now, this also disregards the cache freshness. If you’re still reading, there’s a chance you might be interested in using this. Allow me to clarify that right now there is no support for forecasts or historical data (yet?). Sorry :> Here’s the GitHub link: FieldtypeOpenWeatherMap.
    10 points
  2. minor update 2.1.5 added external links, if available, below description to project (github), direct download and forum support thread.
    5 points
  3. +1 for producing markup-agnostic output. I think most (all?) modules that generate markup should have at least the option of having them output an object rather than specific markup.
    3 points
  4. Hi Richard, If you use the pageField method, then every "tag" creates a page that has a unique name. Example (green-energy, shark-sandwiches, turtle-soup). The autocomplete field presents the user with the page title, so they would select tags like (Green Energy, Shark Sandwiches, Turtle Soup). Same applies for adding new tags. Now you can use UrlSegments to find pages with your multi-word tags because they will be in a format like /domain/tags/green-energy/
    2 points
  5. So I think what you are saying is that you need a different format for your site links (that is what google calls these links to sub pages). Not sure of the rules on this, but in my experience change the order of your title tag so it reads: About | Marinus de Beer - Spatial Design Using the pipe vs the dash is probably not critical, but I prefer it. Google should grab the "About" from that and use it for the site link for the about sub page. You should also make sure you have a sitemap.xml and register it with google webmaster tools. Remember that you won't see any changes in google's results until it reindexes your site, which could take hours to weeks depending on your site. Having all the pages of your site available in a sitemap.xml will help with this considerably. Here are a couple of links that might be worth reading (not really read thoroughly myself): http://honestppc.com/adding-sub-links-sitelinks-results-google-search/ https://support.google.com/webmasters/answer/47334?hl=en https://www.hochmanconsultants.com/articles/sitelinks.shtml
    2 points
  6. @Soma no we don't. @Martijn Geerts Its already done. I updated it and included lock/unlock button too. @kongondo When I started with the module I didn't know about the one from geniestreiche. I startet on the base of Nicos ProcessPageDelete.module. I will not put it in the modules directory. I am open to merge the results with geniestreiche. Sent him a message.
    2 points
  7. made some changes. Implements now publish/unpublish button too. Enable/ disable buttons via modules settings. @adrian Thanks. I changed this.
    2 points
  8. You can with a autoload module in the init() method, use the wire("config")->ajax and maybe check for post values etc and return output then exit() if(wire("config")->ajax){ if(wire("input")->post->something){ echo "hello"; exit; } }
    2 points
  9. @makari: This module creates a simple template, you can / should change the html structure as well as the label texts. If you need multi language support you have to change the text like this echo __("the label text here!"). Now you can translate the labels via Processwire Backend. @horst: Thats a good point but first I have to finish another project. I will keep it in mind – as some other things (I did not forget your message ).
    2 points
  10. Thanks for this - awesome. I have used OpenWeather, but not yet with PW and will need to in the next few weeks, so this will be a big timesaver. Another nice set of icons that work seamlessly with OpenWeather are Skycons: http://darkskyapp.github.io/skycons/
    2 points
  11. See options #1 (post to script outside PW directories) and 3 (post to same page) here: https://processwire.com/talk/topic/407-processing-contact-forms/?p=3106 If you go with option #3 you can intercept right within same page, call your module, do your stuff and return the data Btw, in case you were not aware...https://processwire.com/talk/topic/225-how-to-work-with-ajax-driven-content-in-processwire/ if($config->ajax) { // page was requested from ajax // can optionally include external php scripts // call your module and do stuff }
    2 points
  12. Wire Mail SMTP An extension to the (new) WireMail base class that uses SMTP-transport This module integrates EmailMessage, SMTP and SASL php-libraries from Manuel Lemos into ProcessWire. I use this continously evolved libraries for about 10 years now and there was never a reason or occasion not to do so. I use it nearly every day in my office for automated composing and sending personalized messages with attachments, requests for Disposition Notifications, etc. Also I have used it for sending personalized Bulkmails many times. The WireMailSmtp module extends the new email-related WireMail base class introduced in ProcessWire 2.4.1 (while this writing, the dev-branch only). Here are Ryans announcement. Current Version 0.8.0 (from 2024-09-25 -- initial version 0.0.1 was pushed on 2014-03-01) Changelog: https://github.com/horst-n/WireMailSmtp/blob/master/CHANGELOG.md Downlod: get it from the Modules Directory || fetch it from Github || or use the module-installer in PWs admin site modules panel with its class name "WireMailSmtp". Install and Configure Download the module into your site/modules/ directory and install it. In the config page you fill in settings for the SMTP server and optionaly the (default) sender, like email address, name and signature. You can test the smtp settings directly there. If it says "SUCCESS! SMTP settings appear to work correctly." you are ready to start using it in templates, modules or bootstrap scripts. Usage Examples The simplest way to use it: $numSent = wireMail($to, $from, $subject, $textBody); $numSent = wireMail($to, '', $subject, $textBody); // or with a default sender emailaddress on config page This will send a plain text message to each recipient. You may also use the object oriented style: $mail = wireMail(); // calling an empty wireMail() returns a wireMail object $mail->to($toEmail, $toName); $mail->from = $yourEmailaddress; // if you don't have set a default sender in config // or if you want to override that $mail->subject($subject); $mail->body($textBody); $numSent = $mail->send(); Or chained, like everywhere in ProcessWire: $mail = wireMail(); $numSent = $mail->to($toEmail)->subject($subject)->body($textBody)->send(); Additionaly to the basics there are more options available with WireMailSmtp. The main difference compared to the WireMail BaseClass is the sendSingle option. With it you can set only one To-Recipient but additional CC-Recipients. $mail = wireMail(); $mail->sendSingle(true)->to($toEmail, $toName)->cc(array('person1@example.com', 'person2@example.com', 'person3@example.com')); $numSent = $mail->subject($subject)->body($textBody)->send(); The same as function call with options array: $options = array( 'sendSingle' => true, 'cc' => array('person1@example.com', 'person2@example.com', 'person3@example.com') ); $numSent = wireMail($to, '', $subject, $textBody, $options); There are methods to your disposal to check if you have the right WireMail-Class and if the SMTP-settings are working: $mail = wireMail(); if($mail->className != 'WireMailSmtp') { // Uups, wrong WireMail-Class: do something to inform the user and quit echo "<p>Couldn't get the right WireMail-Module (WireMailSmtp). found: {$mail->className}</p>"; return; } if(!$mail->testConnection()) { // Connection not working: echo "<p>Couldn't connect to the SMTP server. Please check the {$mail->className} modules config settings!</p>"; return; } A MORE ADVANCED DEBUG METHOD! You can add some debug code into a template file and call a page with it: $to = array('me@example.com'); $subject = 'Wiremail-SMTP Test ' . date('H:i:s') . ' äöü ÄÖÜ ß'; $mail = wireMail(); if($mail->className != 'WireMailSmtp') { echo "<p>Couldn't get the right WireMail-Module (WireMailSmtp). found: {$mail->className}</p>"; } else { $mail->from = '--INSERT YOUR SENDER ADDRESS HERE --'; // <--- !!!! $mail->to($to); $mail->subject($subject); $mail->sendSingle(true); $mail->body("Titel\n\ntext text TEXT text text\n"); $mail->bodyHTML("<h1>Titel</h1><p>text text <strong>TEXT</strong> text text</p>"); $dump = $mail->debugSend(1); } So, in short, instead of using $mail->send(), use $mail->debugSend(1) to get output on a frontend testpage. The output is PRE formatted and contains the areas: SETTINGS, RESULT, ERRORS and a complete debuglog of the server connection, like this one: Following are a ... List of all options and features testConnection () - returns true on success, false on failures sendSingle ( true | false ) - default is false sendBulk ( true | false ) - default is false, Set this to true if you have lots of recipients (50+) to ($recipients) - one emailaddress or array with multiple emailaddresses cc ($recipients) - only available with mode sendSingle, one emailaddress or array with multiple emailaddresses bcc ($recipients) - one emailaddress or array with multiple emailaddresses from = 'person@example.com' - emailaddress, can be set in module config (called Sender Emailaddress) but it can be overwritten here fromName = 'Name Surname' - optional, can be set in module config (called Sender Name) but it can be overwritten here priority (3) - 1 = Highest | 2 = High | 3 = Normal | 4 = Low | 5 = Lowest dispositionNotification () or notification () - request a Disposition Notification subject ($subject) - subject of the message body ($textBody) - use this one alone to create and send plainText emailmessages bodyHTML ($htmlBody) - use this to create a Multipart Alternative Emailmessage (containing a HTML-Part and a Plaintext-Part as fallback) addSignature ( true | false ) - the default-behave is selectable in config screen, this can be overridden here (only available if a signature is defined in the config screen) attachment ($filename, $alternativeBasename = "") - add attachment file, optionally alternative basename send () - send the message(s) and return number of successful sent messages debugSend(1) - returns and / or outputs a (pre formatted) dump that contains the areas: SETTINGS, RESULT, ERRORS and a complete debuglog of the server connection. (See above the example code under ADVANCED DEBUG METHOD for further instructions!) getResult () - returns a dump (array) with all recipients (to, cc, bcc) and settings you have selected with the message, the message subject and body, and lists of successfull addresses and failed addresses, logActivity ($logmessage) - you may log success if you want logError ($logmessage) - you may log warnings, too. - Errors are logged automaticaly useSentLog (true | false) - intended for usage with e.g. third party newsletter modules - tells the send() method to make usage of the sentLog-methods - the following three sentLog methods are hookable, e.g. if you don't want log into files you may provide your own storage, or add additional functionality here sentLogReset () - starts a new LogSession - Best usage would be interactively once when setting up a new Newsletter sentLogGet () - is called automaticly within the send() method - returns an array containing all previously used emailaddresses sentLogAdd ($emailaddress) - is called automaticly within the send() method Changelog: https://github.com/horst-n/WireMailSmtp/blob/master/CHANGELOG.md
    1 point
  13. Textformatter for Google Maps https://github.com/teppokoivula/TextformatterGoogleMaps This module looks for Google Maps URLs (such as https://maps.google.fi/maps?safe=off&ie=UTF-8&q=disneyland,+paris) within paragraph (<p></p>) HTML tags and automatically converts them to embedded maps. Configurable options include embed type ("static" or "iframe"), API key, responsive embedding and Google Maps for Business settings. Other than that, it's pretty basic stuff. Original regexp for grabbing maps links was posted by Ryan (I believe) here on the forums, but I couldn't find that post anymore. I've altered it to better suit the needs of this module, added some configurable features (part of which, such as makeResponsive() method, are again based on Ryan's TextformatterVideoEmbed module) and so on. Hope someone finds it useful. (By the way: if you're going to use Google Maps for Business settings, please read the notes there carefully. Google doesn't exactly recommend storing your private key the way module settings are stored..)
    1 point
  14. Hey guys, I'm new here, and I'm loving ProcessWire and the community spirit so far. We're just about to start using ProcessWire for our new clients requiring PHP solutions. Moving in a Rails direction, structure in our projects is becoming more and more of a necessity. As such, I've tried to employ some MVCish techniques in creating a boilerplate for ProcessWire for getting projects going quickly. One of the primary goals of this structure is to make it easier to separate logic from markup, and to prevent tags from being split over templates. Keeping `body`, `html`, and structural markup open and close tags in the same file greatly reduces cognitive overhead, and reduces opportunities for mismatching tags to exist. This approach also reduces duplication, and is great for keeping files small, focused, and organised. The main structure of the boilerplate is well defined, and ready to use in production. The repo is available here: https://github.com/fixate/pw-mvc-boilerplate (link updated 2014/01/17) Structure Although not completely MVC (using classes for controllers feels redundant, there are no models, and a full MVC approach will require a fair amount of customisation), it is heavily MVC inspired. Additionally, the structure is an extension of Soma's delegate approach. File structure: ├── site ├── assets ├── modules . . . ├── templates // boilerplate contents here ├── assets // css, js, fonts, images, etc. ├── controllers // variables and functions specific to templates ├── errors ├── partials // markup not specific to any particular template ├── views // layouts specific to a template ├── _init.php // used to load global and template-specific controllers ├── main.php // the 'alternate template' for all templates . . . **NB: This structure has largely been updated and improved - see the UPDATE - 2014/01/17 at the bottom of this post! Controllers Controllers hold template specific variables and functions. There is also a global controller responsible for making global fields, such as SEO fields, available everywhere, as well as being responsible for the actual delegation. Template logic should be handled as much as possible from within controllers. Views Views are responsible for handling markup and output. Views have available to them both the global controller, and their own controller. Logic should be, as much as makes sense, handled in a controller, with the view pulling the results in for display. Partials Partials hold markup not specific to any particular template on its own, such as the `<head>`, header, navigation, scripts, or footer. As with views, it is best to keep these as logicless as possible. _init.php _init.php is responsible for making controllers available to views. Controllers are only included if they exist - sometimes a template-specific controller may not be necessary, in which case you won't need to create one. main.php main.php is the default layout (equivalent to layout/application.html.erb in Rails) into which everything is rendered. This file has been kept small deliberately to let partials and views manage more fine grained markup structures, while this file serves the main site structure. A call to render_view(), defined in global-controller.php, is responsible for delegating rendering to the view of the current template. Additionally, there is a constant defined in globals-controller.php useful for serving different assets depending on if you are working in a local environment, or if your site is live. This is useful for preventing Google Analytics from running in a dev environment, or for using unminified scripts for debugging. This boilerplate eliminates the need to do much configuration when beginning a project, apart from having to change each template's alternate template in the admin. I hope this will assist in quickly organising and developing new projects! ------------------------------ UPDATE - 2014/01/17: ------------------------------ All files for rendering are postfixed with .html.php in good ol' Rails fashion. main.php has been removed in favour of mvc.php. mvc.php requires config/boot.php which then handles which controllers, views, etc. are used the main layout is now found in views/layouts/application.html.php - like Rails again. partials are now kept inside views/ each page template can have its own optional controller, or simply inherit functionality only from ApplicationController ├── site ├── assets ├── modules . . . ├── templates // boilerplate contents here ├── assets // css, js, fonts, images, etc. ├── controllers // variables and functions specific to templates ├── core // core mvc files - base controllers etc. (project specific stuff does not go here) ├── errors ├── views // folder for template files, layout files, and partials ├── layouts // application layout ├── partials // markup not specific to any particular template ├── mvc.php // the 'alternate template' for all templates . . .
    1 point
  15. This is the way I use to integrate both worlds together. 1.- _header.php ( or whatever is called the file that contains your <body> tag ) <head> ... <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.2/angular.min.js"></script> <script>var app = angular.module('myApp', [])</script> </head> <body ng-app="myApp"> ... 2.- yourTemplate.php <script> app.controller('myCtrl', function ($scope) { $scope.myvar = []; $scope.myvar = <?=getChildren("template=yourtemplatename")?>; console.debug("my Object form php",$scope.myvar); }); </script> <!-- now $scope.myvar is accesible --> <div ng-controller="myCtrl"> </div> 3.- getChildren is a function that I include in _func.php function getChildren($pageId) { $pagina = wire('pages')->get($pageId); // fields to be avoided $avoid = array("FieldtypeFieldsetOpen", "FieldtypeFieldsetClose","FieldtypeFieldsetTabOpen","FieldtypeFieldsetTabClose"); // fields that must be returned $wanted = $fields; // selector $paginas = $pagina->find($selector); $arr = array(); foreach ($paginas as $child) { $array = array(); foreach($child->fields as $field) { $array['id'] = $child->id; // if we dont' want all fields back if ( !in_array($field->type, $avoid) && in_array($field->name, $wanted) && (count($wanted)>0) ) { $array[$field->name] = htmlspecialchars($child->get($field->name)); } // we want all fields back if ( !in_array($field->type, $avoid) && (count($wanted)==0) ) { $array[$field->name] = htmlspecialchars($child->get($field->name)); } } array_push($arr, $array); } echo json_encode($arr); }
    1 point
  16. New Module which adds 1 more, but very tiny green buttons to the page list. It saves minimum 3 klicks to change page status from hidden to visible. Edit: update 11.12.14 Module provides up to 3 (more) buttons in page list to toggle status (hidden/visible, published/unpublished and locked/unlocked). Enable/Disable the buttons in the settings (screenshot) ProcessPageStatusToggler.module
    1 point
  17. Worked it out... <?php $tag = $page->name; ?> <?php $matches = $pages->find("tags=$tag"); ?> <?php foreach ($matches as $match) : ?>
    1 point
  18. I like GET because it’s associative and order independent and doesn’t care about missing values. They’re different tools for different jobs ¯\(ツ)/¯
    1 point
  19. very silly! switching around with fields I tested in a field with diabled textformatter. Everything works as expected. @Martijn: finally 9 because it has a flat rooftop. But you are right to use PW it is necessary to be able to count until 8 (or maybe 9)
    1 point
  20. Something to do with the pyramid, as most people think the Giza pyramid has 4 sides, it actually has 8. That's the probable cause of the issue
    1 point
  21. Module for admin and front-end resizing and rasterizing of vector SVG images Requirements IMPORTANT: This module requires Imagemagick and the pecl imagick extension. For anything but simple SVGs, you must make sure imagemagick was compiled with a relatively recent version of rsvg (I know that 2.32.1 works well and presumably anything more recent should also be fine). If you don't manage your own server and the results are not good, check with your host. If everything is set up correctly, the rendered PNGs will be "perfect" representations of the SVGs. See this post below for just how much of a difference rsvg can make. How to use You must add SVG as an allowed file type for a multiple images field. Check the module configuration for a variety of settings for both PNG and JPG output options. In particular be aware of the Rasterized Images Field selector. If you choose "None" only the SVG will be stored in the images field. You can still access rasterized versions via the rasterize() method - see below for details. NB: You need to be running a recent dev version (or 2.4 stable once available) of Processwire that supports field dependencies for the configuration settings to work as expected. Once the module configuration settings are completed: Upload an SVG image and the module will create a rasterized version. You need to save the page to see the rasterized version which can then be accessed via the API like any other image. The module also adds a new method: rasterize() which can be called from your templates like: $image->rasterize(200,0)->url This method optionally resizes the vector version of the image and then rasterizes it so you can scale it infinitely and there will be no loss of quality. Make sure you point it to the svg version in your images field. Modules Directory: http://modules.processwire.com/modules/image-rasterizer/ Github: https://github.com/adrianbj/ImageRasterizer
    1 point
  22. Just committed a small, but I think quite useful option. You can now choose to replace the SVG thumbnail in the admin page edit view with a rasterized version - primarily for speed of display. All the details about the image will still refer to the original SVG, and viewing the full sized version (in the lightbox) will still be the SVG. The reason I added this is that on one site we have been uploading many very complex SVGs and using the rasterize() API method to display them on the site. We still want the originals to be in SVG though so that resizing results in no loss of quality, and also so we can offer the SVG as a downloadable version. The problem was that during page edit, the SVGs were taking too long to render in the browser. Hope this helps others too.
    1 point
  23. Ah, good catch . The API key was a field setting before I put it into the module config. Wonder why I didn’t get that. I assume they’re only shown in debug mode? Thanks for the kind words everyone. I appreciate it :)
    1 point
  24. Super nice module. Awesome. Got some Notices, just to no. Notice: Undefined variable: field in /site/modules/FieldtypeOpenWeatherMap/FieldtypeOpenWeatherMapConfig.php on line 16 Notice: Trying to get property of non-object in /site/modules/FieldtypeOpenWeatherMap/FieldtypeOpenWeatherMapConfig.php on line 16
    1 point
  25. Thanks a lot for this. Reading your former posts, we are glad to have you here at Processwire.
    1 point
  26. I'd say we don't. Maybe @kixie can collaborate with @geniestreiche to enhance the existing module(s)? Whilst I wouldn't want to discourage the enthusiasm of budding module developers, I'd say this is something we need to carefully consider and strike a good balance about. There's enough lessons from our neighbours Drumlapress about this . Just saying..
    1 point
  27. Thank you for these responses. The latest detail is that the installation seems to only work if I select the Default-Beginner template. I was trying to use the mulitlingual, which did not work, nor did the Default-Intermediate. For my part, hey, it is working. For PW, I think you still have a bug somewhere. Hi Ivan, The installer (mysite/install.php) verifies system requirements. Everything is green up to that page. pwired, I actually decompressed the files locally and uploaded them whole via ftp. My webhost provides a somewhat strict interface, allowing only ftp, not ssh and only preapproved apps can be installed (via an installatron interface). I have not outright asked yet, however it seems to me that there is no way to decompress a zip file remotely. The strictness of the access to remote resources might well be at play here. The place in the install.php where it gets uppitty about dbEngine is on the last page of the install sequence, where it is serverside building the form for advanced options. While the following does not seem relevant to the php loading of this last in the series of installation screens, another detail is that InnoDB is NOT supported by my host or my MySQL.
    1 point
  28. The function seems a little overkill, but why not. After all to get the grandchildren you only need something like $grandchildren = $pages->find("parent=$page->children, sort=-modified, limit=20"); That's already a function right there. One can of course wrap it into a function and play around with it.
    1 point
  29. Hey thanks for posting this, how to find grand children is something anyone will bump into sooner or later. Funny though that it needs so much code. I'm gonna wrap my head about it and start digging php scripts to see if this can't be done with less code. Something similar I guess with getting pictures down the page tree ($pages). That works with storing the picture first in a temp variable and then use $page. Guess something similar can be done here.
    1 point
  30. Santa Claus, with a little delay, brought to you an updated Hungarian language pack for ProcessWire 2.5.10, including the strings for the latest improvements, e.g. the threaded commenting system. Totally 7 files changed. The changelog for this release is available on the GitHub Project page, as before. Download the full package via the ProcessWire Modules Directory: http://mods.pw/7h
    1 point
  31. Version two would then be <?php class SaveShortUrl extends WireData implements Module { public static function getModuleInfo() { return array( 'title' => 'Rewrite field after save', 'version' => 2, 'summary' => 'An example module used for demonstration purposes. See the /site/modules/Helloworld.module file for details.', 'href' => 'http://www.processwire.com', 'singular' => true, 'autoload' => 'template=admin', 'icon' => 'smile-o', ); } public function init() { /** * Hook called just before a page is saved * * May be preferable to a before(save) hook because you know for sure a save will * be executed immediately after this is called. Whereas you don't necessarily know * that when before(save) is called, as an error may prevent it. */ $this->pages->addHookAfter('saveReady', $this, 'hookPageSave'); } /** * Save domain info to another field * No need to call page->save() when changing a value * as it will get saved just after this call. * * Make sure there's something in source_url and it has actually changed * with $page->isChanged(what) */ public function hookPageSave(HookEvent $event) { $page = $event->arguments("page"); if($page->template != "basic-page") return; if(!$page->source_url) return; if(!$page->isChanged("source_url")) return; $page->domain = parse_url($page->source_url, PHP_URL_HOST); if($page->domain) $this->message("Saved the domain: {$page->domain}."); } } now you have already a module in the "modules" table in your DB, go to phpmyadmin and remove the entry for "saveShortUrl" Come back and refresh modules, and install the new one.
    1 point
  32. It would be great if the wireMail function could be used for sending emails instead of the php mail function. This way people would be able to use it together with their favourite mail extensions. For example with SMTP support: wiremail-swiftmailer or wiremailsmtp
    1 point
  33. Well, I’ll give you a short example to demonstrate how it all works together. Imagine the following simple setup: Page Tree Home |- Products (template=products) | |- Product 1 (template=product) | |- Product 2 | |- Product 3 | |- Product 4 | |- Product 5 | |- ... Page Products with template “products” is meant to show a gallery of product images. So we create a controller for the template (that otherwise would be auto-generated on the fly) in site/templates/controllers/ named products.controller.php. <?php /* site/templates/controllers/products.controller.php */ class ProductsController extends BaseController { // init() is executed on controller setup before action is called public function init() { // Just in case you defined general stuff in BaseController’s init() method parent::init(); // Set (for all actions of this controller) a script 'jquery/my.jquery.plugin.js' in group 'footer' with priority 5 // In layout and template you can then output the scripts group 'footer' using view helper <?=scripts('footer');?> // Assets defined via path are looked up in the corresponding folder within site/templates/assets/. You can alternatively // define assets using a URL. $this->script('jquery/my.jquery.plugin.js', 'footer', 5); } // index is the default action executed if no other route matches public function index() { // Add (for this action only) a stylesheet 'gallery.css' to group 'footer' with priority 10. // In layout and template you can then output the styles group using view helper <?=styles('footer');?> $this->style('gallery.css', 'footer', 10); // Set a template var 'products' that contains current page’s children as PageArray $this->set('products', $this->page->children('template=product, sort=title')); } } We’ll need an action template for products’ index action in site/templates/views/products/ named index.tmpl.php. <!-- site/templates/views/products/index.tmpl.php --> <h2><?=$title?></h2> <ul class="products"> <?php foreach($products as $product) { ?> <li class="products__item <?=gridClass($product->images->first(), 'products__image');?>"><a href="<?=$product->url?>"><img src="<?=$product->images->first()->url;?>" alt="<?=$product->title;?>"></a></li> <?php } ?> </ul> We’ll have a look at the used view helper gridClass() later. The first page in PW’s page stack (the one rendered through processPageView directly) is rendered and outputted in a layout’s outlet. Layouts are stored in site/templates/layouts. There is a default layout default.tmpl.php preinstalled. The rendered action templates are outputted within the document structure by using <?=$outlet?>. You can add as many layouts as you want and change the layout the action template will be rendered in by setting another template within your controller’s init() method like this: ... public function init() { parent::init(); // use layout site/templates/layouts/shop.tmpl.php for this template $this->set('layout', 'shop'); } ... Our product template of course also gets a controller: <?php /* site/templates/controllers/product.controller.php */ class ProductController extends BaseController { public function init() { parent::init(); // assign route pattern with dynamic segment to action 'reviewVote' $this->route('/reviews/:id/vote/', array('id' => '^[0-9]+$'), 'reviewsVote'); } public function index() { // set dynamic value to be calculated right before rendering the action template $this->set('similarProducts', function() { // your logic to get a PageArray of similar products goes here $tags = $this->page->get('tags'); // or $tags = $this->get('tags'); as it will pass the request through to page, if 'tags' isn’t set on controller itself $similarProducts = ...; return $similarProducts; }); } // action accessible via route /reviews/ public function reviews() { // we should set up this for pagination in template settings $this->set('reviews', $this->pages->find("template=reviews, product={$this->page->id}")); } // action accessible via route /reviews/new/ public function reviewsNew() { // Later versions will allow to handle actions depending on REQUEST_TYPE, but for now: if($_SERVER['REQUEST_METHOD'] == 'POST') { // create review logic goes here ... $this->session->redirect(...); } else { $this->set('form', $this->forms->get('review')); } } // action for action route /reviews/:id/vote/ public function reviewsVote() { if($id = $this->input->route->id) { // save vote for review ... } } } Template product’s action templates go into site/templates/views/product/ named index.tmpl.php, reviews.tmpl.php, etc. When we talk about routes in PVC, it means patterns of PW’s urlSegments. If you want to have multiple actions and routes, you have to enable urlSegments for the particular template. Index action is performed when a page is addressed directly via its path. If urlSegments are added to the request, PVC captures the urlSegments as a action route and provides it to the controller which determines the action to perform for the route. Until now all template specific view classes (like ProductsView, ProductView) are generated on the fly. Let’s use some view helpers to reduce logic in templates. For example we want pagination looking all the same all over the site. Therefor we define a general view helper for that in site/templates/views/base.view.php. <?php class BaseView extends PvcView { /** * Add custom view helpers that will be available as * global functions within your templates. * @method customViewHelpers * @param Array $scope contains an associative array of template scope * @returns Array An associative array with key/closure pairs */ public function customViewHelpers($scope) { return array( /** * Each helper is defined as a pair of key (name of the helper * function in template context) and closure (function body) * Via use() you can pass in $scope and custom values to be * available within your helper. * The helper below can be called like this: <?=sayHi('your name');?> */ 'pagination' => function(PageArray $pageArray) use($scope) { return $pageArray->renderPager(array( 'nextItemLabel' => "Next", 'previousItemLabel' => "Prev", 'separatorItemClass' => "pagination__item--separator", 'nextItemClass' => "pagination__item--next", 'previousItemClass' => "pagination__item--prev", 'currentItemClass' => "pagination__item--current", 'lastItemClass' => "pagination__item--last", 'listMarkup' => "<ul class='pagination pagination--{$scope['template']}'>{out}</ul>", 'itemMarkup' => "<li class='pagination__item {class}'>{out}</li>", 'linkMarkup' => "<a href='{url}'><span>{out}</span></a>" )); }) ); } } Now you can render your pagination in your action templates just by passing a PageArray value to your pagination view helper like <?=pagination($reviews);?>. You also can create template-specific view helpers (like gridClass() used in our products action template for index at the top) by creating a view class for the template in site/templates/views/ like this: <?php /* site/templates/views/products.view.php */ class ProductsView extends BaseView { public function customViewHelpers($scope) { $helpers = array( 'gridClass' => function(PageImage $img, $class=null) { $w = $img->width(); $h = $img->height(); $orientation = 'square'; if($w < $h) $orientation = 'portrait'; if($w > $h) $orientation = 'landscape'; return is_string($class) ? sprintf('%s--%s', $class, $orientation) : $orientation; } ); return array_merge($helpers, parent::customViewHelpers($scope)); } } Predefined view helpers are for example embed() to render other pages within your current action template, scripts() and styles() to output asset groups and snippet() to render reusable code chunks stored in site/templates/snippets/ within the current action template’s scope. Hopefully this gives you a vague idea how you can organize your code base using PVC.
    1 point
  34. You know Asm select plugin has this functionality just disabled?
    1 point
  35. A starting point module to use angularjs in our templates in an easy manner.
    1 point
  36. New methods: $page->getPage() $page->getPage(1015) $page->getChildren() $page->getChildren(2024) $page->getChildren('template=products')
    1 point
  37. Module updated 1.- Added methods $page->getChildren() $page->getPage() 2.- Now you can inject scripts trough module configuration
    1 point
  38. Hi All, I have spent a decent amount of time over the last two days (starting yesterday on American Thanksgiving) rebuilding my main personal business photo site with Processwire. For now this project is still being developed on a local install of MAMP. I did not wake up yesterday with the intension of starting this project - but I just went for it... Going back a few months: I discovered Processwire by accident. I was not really looking for a new CMS to replace my weapon of choice, namely MODx. Processwire seemed intriguing, but to be honest I had serious reservations in the beginning. After some initial tire kicking my conclusion was "this looks like a really interesting alternative, but this system is for advanced developer geeks with skills, it might never be the playground for you..." Initially my commitment to Processwire was an awkward stop and go experience. But I stuck with it. I asked some basic questions that just screamed "newbie alert" but the constructive and helpful responses were rewarding. I began to take notice and found that overall the Processwire Forum was simply first class. I know my way around markup HTML, CSS and pushing pixels around. But I can't write scripting code like PHP to save my life. I thought this was going to be a deal breaker - but I stuck with it. Fast forward to today: I am amazed at how much I got done! I am taking an existing MODx site and converting/improving all the dynamic elements from MODx to Processwire. Along the way I am streamlining the markup, the CSS, the logic, while adding more efficient Processwire building blocks than I thought possible, all without needing to fire off "help me" requests to the Processwire forum. I am also improving my CSS skills and I am even beginning to feel less intimated with working with PHP code. I guess you could call this the Processwire "aha" moment. It just feels good! I am really enjoying working with this system. There is so much in the Processwire arena that is still a mirage in the sand, but I think that with time I will add more and more knowledge. I guess that is it. I really appreciate the help and encouragement from you all... Cheers, Max
    1 point
  39. I am sure that many will recognize what you are writing there. You have a good writing style. It has to do that working with processwire has a side effect: it pushes you into learning code. You can ask yourself why processwire has this side effect. But if you think about it, it is because processwire has no shell, no front (rules). You can bring together your own (any) html and css and put it as a front on processwire. With processwire you can not avoid to see that paths, values, functionality, etc, between the html tags are replaceable by php and api. So naturally you are going to fiddle around to see what is all possible. This leads in a natural way to learn coding, the side effect of pw. Of course, not every pw user will go the road of coding, that is simply up to the user, but processwire puts a big temptation on you Having said this, everybody can already make nice websites with processwire with only a few php scripts that you don't need to learn but simply save as snippets and re-use them in your websites.
    1 point
  40. This is called the ProcessWire tractor beam. You've been pulled into its path! You wake up one day and know you won't be happy until your own site is completely rebuilt in PW. Even though you don't have time, you have real work to do and your current site and CMS have been perfectly "ok". Before you know it your life is full of echo statements, you're visiting the forums multiple times per day and you can't sleep at 5am because you're crazy excited about the great thing PW allowed you to do with your site that you never thought possible. Anyway, nice write up. Thanks for sharing
    1 point
  41. If you install this module you´ll be able to use angular and use it in your templates directly. Example of a list of all children of the actual page. <script> app.controller('myCtrl', function ($scope) { $scope.children = []; $scope.children = <?=$page->getChildren()?>; }); </script> <div ng-controller="myCtrl"> <ul> <li ng-repeat="child in children">{{child.title}}</li> </ul> </div>
    1 point
  42. Or even: <!-- Diogo says that I should tell you that this bit of code is to do with that very nice EMO module, okay? -->
    1 point
  43. Problem with different output (generated by PHP ) is that the default ProcessWire cache solutions (template cache & ProCache ) can't cache 2 versions for the same URL. When you want to support caching you need to create a workaround for this. (Could be done with AJAX and enabling urlsegments) Or you go for the other cache solutions ProcessWire has. For example MarkupCache. Keep in mind generating different output with PHP can be done easily without the need of caching, what is perfectly fine for smaller websites. If you need to build for a high traffic site then you need to make a good cache strategy. When you want to deliver different output purely in the browser, Javascript can easily detect the state and respond to this. Then there's no need for different source code. For example: Javascript could destroy a slider when moving from iPad to iphone, and rebuild the slider when moving back.
    1 point
  44. ok guys, there have been some major updates to the boilerplate. Check it out at https://github.com/fixate/pw-mvc-boilerplate, and take a look at my original post for a few details on the updates. Things are far neater
    1 point
  45. Hello, Since I last posted I've used processwire to create a simple content managed website and as an API data source for a Content-Publishing mobile application. I still intend on using it as a data source from within the Yii framework for the following reasons: Views I like that processwire gives you a raw template file and allows you to do what you like to output your HTML, but I found myself just trying to re-create the Themes/Layout/Partials structure provided by Yii. Folder/Class organisation With processwire I found myself just adding files to the modules folder, which is fine for a smaller project, but for a large project I would need to implement some sort of system that separated out the different types of modules and organise them accordingly, whereas with Yii I have the out of the box separation of Actions, Behaviors, Components, Extensions, Modules and Widgets. URL Management Processwire URL's were perfect for the small site I built, but I felt I had more out of the box control over URL's using Yii, with it's CBaseUrlRule class. Automated Testing Yii provides support for automated testing: http://www.yiiframework.com/doc/guide/1.1/en/test.overview In Summary - I really like processwire and I will definitely continue to use it stand alone, but I also still see how I could benefit from bootstrapping it into Yii, so I will be going ahead with that also.
    1 point
  46. Just wanted to chime in and mention what I've done. I've been working on a new version of this module to support language page names. (mainly speaking only if LanguageSupportPageNames is installed) - support Multilanguage - support for correct view Actions from admin - correct urls within admin - modified locaUrl() to work correctly, coming from LanguageSupportNames module I hope you guys don't mind. I forked the project and comited current version. As you can see there's not much left from the original, but the basic concept is the same. This work was supported and sponsored partly by http://dreikon.de/ with whom I've been doing some PW support work lately. Since it's already some time ago since I made it (meanwhile tons of other work in my head) I just tested again locally with and without LanguageSupportPageNames installed and corrected a little issue. I'd very appreciate if you guys help test this version. And any help or suggestions are welcome. It may not the best code ever written, especially since it's kinda complex I'd be very happy if more eyes take a look. Ideally it would replace the current multisite module and be backward compatible. Thanks You can grab the module here: https://github.com/somatonic/Multisite
    1 point
  47. Try this: (not tested) // check the correct url to use on the examples page of the module $.getJSON('/someweb.es/service-pages/?title=toby', function(data) { alert(data.matches[0].name); }); Or for iterating all the matches: (also not tested) $.getJSON('/someweb.es/service-pages/?title=toby', function(data) { $.each(data.matches, function(key,val) { console.log(key + ' -> ' + val.name); // check the console for this one }); }); I'm just adapting from here: http://api.jquery.com/jQuery.getJSON/ Edit: tested and corrected a couple of things
    1 point
  48. Greetings, This is a terrific discussion, which opens up a lot of ideas in my mind. Over the past couple of years, I have spent a lot of time using various PHP frameworks (especially like Yii). I would agree with Soma that -- for the most part -- ProcessWire allows you to accomplish the same goals as these frameworks. There is a lot to say here, but I'll try to summarize: ProcessWire's Huge Advantage: Querying and Syntax I find that the syntax of ProcessWire is far more concise and "expressive" (borrowing a favorite Laravel term) than these PHP frameworks. The ability to design very deep queries really quickly and easily is the greatest advantage of ProcessWire. "Framework" vs "CMS" I believe ProcessWire should be described as a framework with crucial pre-built CMS components. Currently, ProcessWire is described as a CMS with a framework behind it. The problem is that when it is described as a CMS, we naturally see comparisons with WordPress, Joomla, and Drupal, and anyone who spends time with ProcessWire immediately realizes it is not the same type of thing as these CMSs. If it were presented as a framework, it would attract a whole different set of people with (I believe) more accurate assumptions. Future Development and Framework Choices Nothing replaces ProcessWire, but I gain something using other frameworks that I often can come back and use in ProcessWire. My very rapid framework rundown... CodeIgniter is essentially dead. Laravel, which seemed great at first, has become overly convoluted. Yii has the best balance as a framework, but when I compared the time and effort to get an application up and running in ProcessWire vs Yii, ProcessWire wins. Lately, I have been experimenting with PHPixie (yes, I am always trying new things), and it is really nice. In fact, I see a lot of similarities between PHPixie and ProcessWire. What Do Frameworks Have Over ProcessWire? The only "advantage" of PHP frameworks over ProcessWire is that frameworks have no back end at all. ProcessWire's back end is extremely minimal, and really does serve the most necessary elements. But when building custom UIs, I often want to just go directly to the database with no assumed page concept at all. With that said, I have developed a set of methods that nicely takes care of this in ProcessWire. And ProcessWire has such an elegant query and syntax system, it saves massive time overall as compared with one of these frameworks. So there is a bit more time getting your custom UI CRUD going, but after that you save huge time using ProcessWire's data-handling system. Sorry if this got a bit far from the direct subject, but it seems that people reading this thread might be asking some of the same questions I have asked about PHP frameworks and ProcessWire. Thanks, Matthew
    1 point
  49. I recently had to setup front-end system to handle logins, password resets and changing passwords, so here's about how it was done. This should be functional code, but consider it pseudocode as you may need to make minor adjustments here and there. Please let me know if anything that doesn't compile and I'll correct it here. The template approach used here is the one I most often use, which is that the templates may generate output, but not echo it. Instead, they stuff any generated output into a variable ($page->body in this case). Then the main.php template is included at the end, and it handles sending the output. This 'main' template approach is preferable to separate head/foot includes when dealing with login stuff, because we can start sessions and do redirects before any output is actually sent. For a simple example of a main template, see the end of this post. 1. In Admin > Setup > Fields, create a new text field called 'tmp_pass' and add it to the 'user' template. This will enable us to keep track of a temporary, randomly generated password for the user, when they request a password reset. 2a. Create a new template file called reset-pass.php that has the following: /site/templates/reset-pass.php $showForm = true; $email = $sanitizer->email($input->post->email); if($email) { $u = $users->get("email=$email"); if($u->id) { // generate a random, temporary password $pass = ''; $chars = 'abcdefghjkmnopqrstuvwxyz23456789'; // add more as you see fit $length = mt_rand(9,12); // password between 9 and 12 characters for($n = 0; $n < $length; $n++) $pass .= $chars[mt_rand(0, strlen($chars)-1)]; $u->of(false); $u->tmp_pass = $pass; // populate a temporary pass to their profile $u->save(); $u->of(true); $message = "Your temporary password on our web site is: $pass\n"; $message .= "Please change it after you login."; mail($u->email, "Password reset", $message, "From: noreply@{$config->httpHost}"); $page->body = "<p>An email has been dispatched to you with further instructions.</p>"; $showForm = false; } else { $page->body = "<p>Sorry, account doesn't exist or doesn't have an email.</p>"; } } if($showForm) $page->body .= " <h2>Reset your password</h2> <form action='./' method='post'> <label>E-Mail <input type='email' name='email'></label> <input type='submit'> </form> "; // include the main HTML/markup template that outputs at least $page->body in an HTML document include('./main.php'); 2b. Create a page called /reset-pass/ that uses the above template. 3a. Create a login.php template. This is identical to other examples you may have seen, but with one major difference: it supports our password reset capability, where the user may login with a temporary password, when present. When successfully logging in with tmp_pass, the real password is changed to tmp_pass. Upon any successful authentication tmp_pass is cleared out for security. /site/templates/login.php if($user->isLoggedin()) $session->redirect('/profile/'); if($input->post->username && $input->post->pass) { $username = $sanitizer->username($input->post->username); $pass = $input->post->pass; $u = $users->get($username); if($u->id && $u->tmp_pass && $u->tmp_pass === $pass) { // user logging in with tmp_pass, so change it to be their real pass $u->of(false); $u->pass = $u->tmp_pass; $u->save(); $u->of(true); } $u = $session->login($username, $pass); if($u) { // user is logged in, get rid of tmp_pass $u->of(false); $u->tmp_pass = ''; $u->save(); // now redirect to the profile edit page $session->redirect('/profile/'); } } // present the login form $headline = $input->post->username ? "Login failed" : "Please login"; $page->body = " <h2>$headline</h2> <form action='./' method='post'> <p> <label>Username <input type='text' name='username'></label> <label>Password <input type='password' name='pass'></label> </p> <input type='submit'> </form> <p><a href='/reset-pass/'>Forgot your password?</a></p> "; include("./main.php"); // main markup template 3b. Create a /login/ page that uses the above template. 4a. Build a profile editing template that at least lets them change their password (but take it further if you want): /site/templates/profile.php // if user isn't logged in, then we pretend this page doesn't exist if(!$user->isLoggedin()) throw new Wire404Exception(); // check if they submitted a password change $pass = $input->post->pass; if($pass) { if(strlen($pass) < 6) { $page->body .= "<p>New password must be 6+ characters</p>"; } else if($pass !== $input->post->pass_confirm) { $page->body .= "<p>Passwords do not match</p>"; } else { $user->of(false); $user->pass = $pass; $user->save(); $user->of(true); $page->body .= "<p>Your password has been changed.</p>"; } } // display a password change form $page->body .= " <h2>Change password</h2> <form action='./' method='post'> <p> <label>New Password <input type='password' name='pass'></label><br> <label>New Password (confirm) <input type='password' name='pass_confirm'></label> </p> <input type='submit'> </form> <p><a href='/logout/'>Logout</a></p> "; include("./main.php"); 4b. Create a page called /profile/ that uses the template above. 5. Just to be complete, make a logout.php template and create a page called /logout/ that uses it. /site/templates/logout.php if($user->isLoggedin()) $session->logout(); $session->redirect('/'); 6. The above templates include main.php at the end. This should just be an HTML document that outputs your site's markup, like a separate head.inc or foot.inc would do, except that it's all in one file and called after the output is generated, and we leave the job of sending the output to main.php. An example of the simplest possible main.php would be: /site/templates/main.php <html> <head> <title><?=$page->title?></title> </head> <body> <?=$page->body?> </body> </html>
    1 point
×
×
  • Create New...