Leaderboard
Popular Content
Showing content with the highest reputation on 12/05/2014 in all areas
-
Hey all, I launched this website a few weeks ago: http://www.archsf.com/ It was deceptively simple looking at a first glance of the mockups, however this project turned out to be very challenging and ProcessWire really shined, as it always does. The main template being used on the site is the Project Category template. Here's the "Residental" page, which is powered by that template: http://www.archsf.com/project-categories/residential/ As you can see, if you're on a large screen, there are 5 blocks across (1 callout + 4 projects). I'm using Zurb Foundation (the Grunt/Libsass version, which rocks), however like most CSS frameworks, there isn't an even 5 column structure, so I had to take care of that manually. Then, add in the fact that the website is full browser width, which presents a whole host of width/height manipulation that must be done. All the project thumbnails are the same size, but that first callout is text-based so it's height must calculated based of the height of one of the project thumbnails. But of course, the thumbnails themselves are dynamic in height depending on the browser width. And, you can only get the height of the images once they are loaded in (which is easy thanks to the imagesLoaded plugin). Now, if you look at the next row, it's not 5 easy blocks across, but rather 2 blocks, then a big block that takes up 2 block spaces, then another regular size block. I went through some different approaches to handle that situation, and what I ended up doing is hardcoding a the layout so that specific blocks would appear in specific places. It's not a masonry / nicely floated structure! Then, let's not forget this is a responsive site. So, for the phone-sized breakpoint, there's actually another repeated layout of all the project thumbnails, but it's set to hidden unless viewing that breakpoint (which will hide the other breakpoints). That breakpoint has 2 blocks across, with the occasional 1 block featured project. There is also the tablet-sized breakpoint, which has 4 blocks across. This approach, from a code point of view, is a bit ugly in that content is being repeated on a page, however this was a necessary decision I had to make in order for the complicated layout structure to work. It didn't seem to affect the search engine indexing of the site however. Also, each project thumbnail also has different image sizes based on the breakpoint being viewed. ProcessWire makes creating thumbnails on the fly so easy, which is a huge plus (especially compared to WordPress). Oh, while administrators have the ability to create projects, they sometimes wanted the ability to have a project assigned 2+ times for a page. Now, having them create a repeat project would be inefficient, so I created another template type called 'duplicate_project' which allows a custom title and thumbnail, but then has a dropdown field that makes the duplicate project act as the main project. As for the lightbox that appears when clicking on a project thumbnail. An ajax request is made to the project template file, which returns a JSON object containing the lightbox image data for Blueimp Gallery, which is the lightbox being used (not Foundation's Clearing Lightbox, which I find very annoying!). It works well, except aligning the bottom-left caption (and bottom-right "Project Information" toggle) was an huge exercise in manipulating the absolute positioning of that element, relative to the image itself, because Blueimp by default doesn't align captions relative to the image. I considered using other lightboxes, but Bluimp turned out to be the best one for my needs, and it's responsive out of the box. The projects themselves have their own individual pages/URLs, but not in the classic sense. If you go to a direct URL of the project, I wrote some code so that it will show the FIRST category it's been assigned to, and then automatically bring up the lightbox containing the projects images. It does this by detecting the the page being hit is either project-category.php or project.php and running the necessary code, which involves the same AJAX request to bring up the lightbox. Example: http://www.archsf.com/projects/aptos-street/ The firm page is whole other beast, but I won't get into that. Screenshots demonstrating some internals: Editing a Project Category: http://goo.gl/T30AEh Editing a Project: http://goo.gl/fekgqQ Editing a Duplicate Project: http://goo.gl/ppKfo5 Editing a Callout: http://goo.gl/gfEbPO Editing the Home Page: http://goo.gl/rbHlRQ Overall Page Structure: http://goo.gl/gfEbPO Enjoy. Jonathan12 points
-
http://assessment.ifas.ufl.edu I've been working on this one a good while now. What's there now is essentially a phase one MVP (Minimum Viable Product). We start the next phase of the project soon, which migrates a lot more data, and takes all the paper processes and turns them into web forms and/or calculation tools. More on that another time. For those of you familiar with the pitfalls of infinite scroll — I'm still working out the kinks with history.js, but I wanted to go ahead and post the site here as it's now officially live. Some of the more crucial modules used: ListerPro AIOM ProFields: PageTable FormBuilder (not live yet, coming in phase 2) Homepage Search Page Filters Species Page8 points
-
Maybe this helps someone. Nerd alert! Currently building a shop module for a project, where I was looking for a easy way to handle/store form data in session and later repopulate it easily using form API. It can be very tedious to do that manually grab the fields, store in session repopulate form. So I found a way to do it "automatically" by serializing form object and build a name => value array that I store in session, then retrieve the array later and convert it to WireInputData as it is required for form object to process. Further I needed to turn of CSRF temporarely to get around error when populating the form object. Here a example code for those interested. // generate $form // when sent if($input->post->send) { // process form $form->processInput($input->post); // if no errors if(!count($form->getErrors())){ // serialize form values and store in "shop" session namespace $formfields = $form->getAll(); $formdataKeys = $formfields->explode(function($item, $key){ return $item->name; }); $formdataValues = $formfields->explode(function($item, $key){ return $item->value; }); $formdata = array_combine($formdataKeys, $formdataValues); $session->setFor("shop", "userformdata", $formdata ); $session->redirect("nextpageurl"); } } else { // if session formdata found repopulate form object if($formdata = $session->getFor("shop", "userformdata")){ $formdataInput = new WireInputData($formdata); $form->protectCSRF = false; // to not get a CSRF validation error $form->processInput($formdataInput); // fills in form and validates it $form->protectCSRF = true; } } return $form->render();7 points
-
So, let's launch this finally! › https://processwire-recipes.com/ ‹ As you can see, it's a work in progress. The design is going to change, Nico at the helm, and once we got a "critical mass" of recipes, another way of structuring recipes (the "table of contents") will also go online. To contribute, you can post your recipes either in this thread and we'll pick it up, or - codey - via Pull Request on GitHub of this repo here. Frankly, that's the favoured way, simple and a good start dive in to GitHub and this form of Open Source contribution. As always, feedback (and of course, contribution) is really welcome. We're always eager to learn - and helping to learn new stuff and create a place to spread some PW knowledge, that's what PWR was about in the first place Big big thanks to my partner in crime owzim who, among other things, contributed the - imho - heart of this tiny project: a textfile-to-page-importer. Finding an elegant way to contribute was one of the reasons this took so long, and during Beyond Tellerrand conference, it finally clicked into place.5 points
-
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.5 points
-
It struck me today, as I was working on a large site, that it would be really nice if the Setup -> Fields fly-out menu would implement the "Tags" feature to group fields into sub-menus. I use Tags (defined under the 'Advanced' tab when editing a field) to neatly organize fields on the actual Setup->Fields page. It would be great if the menu was also organized the same way. A single fly-out menu of 50+ un-grouped fields isn't so useful... What do you think?4 points
-
All the taxonomy is handled by page fields. Some are just basic fields like Origin and Growth habit, and others like Conclusion Type and Zones are part of a PageTable. (Screenshots at the end of the post). There is a lot of JS involved in the filters — more than I have time to explain at the moment. The short version: Filter selections build a URL containing the page IDs for any selected filters via JS. We needed the URIs to be as short as possible, since they will be frequently emailed, and eventually cited in publications. They end up looking something like: /?zones=1030,1028&types=1082,1080&growth_habit=19040,1022 A selector is then built from those GET variables in the template. // default selector, used for assessment page $selector = "template=species, limit=16, sort=name,"; // zones GET variables if ($input->get->zones){ $zones = explode(",", $input->get->zones); $q = implode("|", $zones); $selector .= "@conclusions.conclusion_zones={$q}, check_access=0,"; } It gets a little more complicated, because of the infinite scroll. A maximum of 16 results are initially shown for any query, additional items are pulled in via AJAX on scroll. So if there are GET variables involved, the AJAX call needs to pass them along. In the JS function getUrlVars() { var vars = {}; var parts = window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m,key,value) { vars[key] = value; }); return vars; } var GET_zones = getUrlVars()["zones"]; There is a GET_* for each possible filter. All of which are passed via the data param in the $.ajax() call. data: { start:start, query:query, zones:GET_zones, types:GET_types, origin:GET_origin, growth_habit:GET_growth_habit, tool_used:GET_tool_used }, Screenshots This is a bit of a disjointed explanation, but should give you some idea.3 points
-
Why store the domain twice, if you already have the full source URL? Just ouput the part from the source URL field you want to display like horst mentioned: <? echo parse_url($page->source_url,PHP_URL_HOST);?> If you want to store it additionally, look at the HelloWorld.module demo and try to hook after each page save and write the field.3 points
-
For the fun of it, I have another solution for you. Firstly, install Migrator via the zip Then extract the contents of the attached file into the assets folder. You should end up with a structure that looks like: assets/migratorbackups/blank-profile Then go to Setup > Migrator > Restore and choose the blank-profile option from the select - it will be the only option available. That should be it. Let me know if that works out for you.3 points
-
2 points
-
This might be the finest big, data-heavy PW site (aside from some of Ryan's sites obvs ), I've seen. Great work, and please keep us up to date on future developments.2 points
-
Page fields are about as core as anything in PW. PW without free Page fields would be unspeakable2 points
-
You're welcome. Also Batcher and Lister Pro are really great for fast bulk editing and workflow improvements.2 points
-
Phone Number Fieldtype A new fieldtype to enter phone numbers with 4 integer values for country, area code, number and extension and format the output based on predefined or custom options. StyledOutput The most common usage option will be: echo $page->fieldname //eg. +1 (123) 456-7890 x123 This provides a fully formatted phone number, based on the output format chosen from module's configuration page, or with the format override option (if enabled), when entering a phone number on a page. This is a shortcut that produces the same output as: echo $page->fieldname->formattedNumber //eg. +1 (123) 456-7890 x123 Alternate styled options are: echo $page->fieldname->formattedNumberNoExt: //eg. +1 (123) 456-7890 echo $page->fieldname->formattedNumberNoCtry: //eg. (123) 456-7890 x123 echo $page->fieldname->formattedNumberNoCtryNoExt: //eg. (123) 456-7890 echo $page->fieldname->unformattedNumber: //eg. 11234567890123 echo $page->fieldname->unformattedNumberNoExt: //eg. 11234567890 echo $page->fieldname->unformattedNumberNoCtry: //eg. 1234567890123 echo $page->fieldname->unformattedNumberNoCtryNoExt: //eg. 1234567890 Of course the actual output is determined by the selected format output Raw Output You can output the values for the component parts of the phone number like this: echo $page->fieldname->country; echo $page->fieldname->area_code; echo $page->fieldname->number; echo $page->fieldname->extension; Output for mobile compatibility To get iOS and other mobile platforms to recognize numbers and be able to automatically dial them, use something like this: echo '<a href="tel:+'.$page->fieldname->unformattedNumberNoExt.'">'.$page->fieldname->formattedNumber.'</a>'; Selectors for searching The component parts can be used in selectors like this: $pages->find("phone.area_code=123"); Field Settings There is a field settings for the width of the inputs in pixels. There is a field settings for the width of the inputs in pixels. You can also choose whether to display the country and extension fields for input. Off by default. There is an additional checkbox that determines whether there is an option to override the default format option on a per entry basis, which will be useful when styling phone numbers from different countries on the one website. Off by default. Custom formatting options On the module's configuration page you can choose from predefined formats, or create custom formats using syntax like this: {+[phoneCountry] }{([phoneAreaCode]) }{[phoneNumber,0,3]-}{[phoneNumber,3,4]}{ x[phoneExtension]} which generates: +1 (123) 456-7890 x123 Each component is surrounded by { } The names of the component parts are surrounded by [ ] Two comma separated numbers after the component name are used to get certain parts of the number using php's substr function, allowing for complete flexibility. Anything outside the [ ] is used directly: +,-,(,),x, spaces, etc - whatever every you want to use. There are lots of complicated rules around numbers changing when dialed from different locations. A simple example is for Australia. When dialing from within Australia, area codes start with a 0, but when dialing from another country, the 0 must be omitted. You can write a simple format to handle this. The following truncates the first number from an Australian two digit area code: {+[phoneCountry] }{([phoneAreaCode,1,1]) }{[phoneNumber,0,4] }{ [phoneNumber,4,4]}{ x[phoneExtension]} which generates: +1 (7) 1234 5678 x123 even though the full "07" is stored in the area code field. Where to get Available from github: https://github.com/adrianbj/FieldtypePhone And the modules directory: http://modules.processwire.com/modules/fieldtype-phone/ To Do Need to increase the number of pre-defined formats. There seem to be so many options and no real standards, so I thought rather than create a huge list of options that no-one will use, I thought I'd wait and get you guys to contribute them as you need them. Either post your formats here, or send me a PR on github and I'll add them. How to install Download and place the module folder named "FieldtypePhone" in: /site/modules/ In the admin control panel, go to Modules. At the bottom of the screen, click the "Check for New Modules" button. Now scroll to the FieldtypePhone module and click "Install". The required InputfieldPhone will get installed automatically. Create a new Field with the new "Phone" Fieldtype. Choose a Phone Output Format from the details tab. Acknowledgments This module uses code from Soma's DimensionFieldtype and the core FieldtypeDatetime module - thanks guys for making it so easy.1 point
-
Many members of the community create modules that are very helpful for me and others and offer great support for these modules. We can offer our appreciation with a thanks in a forum post etc.. which is great and gives a feel good factor.. but to create and support modules can take a great deal of time and energy and with this in mind I was thinking how it would be nice if we could show our appreciation by having the opportunity donate beer money to authors of modules that we use. How about if a donate button is displayed on each module page so that donations could be made to the author of the module?1 point
-
Pia - Pageimage Assistant Hello, today I can tell you that Pia Ballerina want to assist you with Pageimages and that can become really helpful! . . . Pia, in its current state, version 1.0.0, provides: a GUI (the module config screen) for quick and easy changes to the sitewide Pageimage default options an alternative way for calling the Pageimage resizing methods with PW selector strings three new methods as shortcuts to the resizing functions a new method called retinafy and its alias hiDPI, (introduced in version 0.2.0) . . . 2) Instead of ->width(), ->height(), ->size() you can call ->pia() now. With a PW selector string you tell Pia what image variation you want to have : . $image->pia("width=100, quality=80, sharpening=medium")->url; . If you want process ->width() just define width. If you want process ->height() only define height. If you want process ->size() just define width and height. If you want process ->size() with equal values for width and height, just define only size, or use the alias square: . $image->pia("width=480")->url; $image->pia("height=320")->url; $image->pia("width=400, height=300")->url; $image->pia("size=350")->url; $image->pia("square=350")->url; . So, yes, - I see. Now you may think: "Ok, nice looking girl, - and she can dance very well, - but for what should it be good that she is involved here? My very old buddies width, height and size - and me, - we don't need any Ballerinas between us!" . Yeah, I see what you mean. But this above is not what Pia is good for, this is just a little warming up for you. . In some cases one need to specify more than just width and / or height. If it comes to that you need explicitly populated options with the individual pageimages, Pia will become faster and more comfortable at some point. Also the code is looking more readable with Pia, at least to me: . // regular style #1: $image->width(800, array("upscaling" => false, "cropping" => true, "quality" => 80, "sharpening" => "strong")); // or regular style #2: $options = array("upscaling" => false, "cropping" => true, "quality" => 80, "sharpening" => "strong"); $image->width(800, $options); // now lets Pia dance: $image->pia('width=800, upscaling=0, cropping=1, quality=80, sharpening=strong'); $image->pia('width=800, upscaling=off, cropping=on, quality=80, sharpening=strong'); . For me it is that not only Pia begin to dance, my fingers do so too when writing selector strings instead of the regular array code. . Ok, last thing before we can go to stage: "You already may have noticed that Pia accepts few different values for boolean expression, yes?" for TRUE you can write these strings: "1, on, ON, true, TRUE, -1" for FALSE you may use one out of "0, off, OFF, false, FALSE" Ready? Ok, lets go to stage. . . . 3) Pia provide three new methods as shortcuts. This means that when using one of the shortcuts you have pre-populated options, regardless of the sitewide default settings: crop :: does what the name says contain :: is equal to the regular method: ->size($width, $height, array("cropping" => false)) cover :: this, Pias third child, is a new kid on the block . Let's have a closer look and compare it. We use Pias image from above as source for this example. (It's dimensions are 289 x 400 px) . . * crop $image->crop('square=100'); . it is 100 x 100 px and the name is: pia-ballerina_titel.100x100-piacrop.jpg . . . * contain $image->contain('square=100'); . it is 73 x 100 px and the name is: pia-ballerina_titel.100x100-piacontain.jpg . . . * cover $image->cover('square=100'); . it is 100 x 139 px and the name is: pia-ballerina_titel.100x139-piacover.jpg . . . Ok, you got it? . "Crop" crop out the area, "Contain" fits the image into the area, and "Cover" calculates the needed dimensions for the image so that the area is completly covered by it. . Following is a link with lots of those crop-, contain-, cover- variations. I have stress-tested it a bit: much variations . ---------- . . Later Additions: . * contain with option weighten Since version 0.0.6 contain can take an additional param called "weighten". (read more here) . . . * retinafy Since version 0.2.0 retinafy is added. It returns a markup string, e.g. a HTML img tag, where placeholders are populated with property values from the pageimage. Default properties are: URL, WIDTH, HEIGHT, DESCRIPTION. The method also can take an optional array with CustomPropertyNames. You also can use the alias HiDPI if you like. (read more here) . . ---------- . . You can get the module from the modules directory or from the repo on Github: . git clone https://github.com/horst-n/PageimageAssistant.git your/path/site/modules/PageimageAssistant . . Bye! . Classical ballet performance at the Aalto Theatre in Essen, in the context of the Red Dot Award ceremony 26 June 2007, Act III, Sleeping Beauty, the wedding reception Photos: Horst Nogajski - www.nogajski.de1 point
-
Introducing PVC PvcCore: https://github.com/oliverwehn/PvcCore/ PvcRendererTwig: https://github.com/oliverwehn/PvcRendererTwig/ (coming soon) PvcGenerator: https://github.com/oliverwehn/PvcGenerator/ (coming soon) Each time I’ve built a ProcessWire page I’ve struggled with organizing (and separating) code, markup and stuff. Playing around with frameworks (backend as well as frontend) like Rails, Ember and stuff I really liked having a given structure, knowing where to put what piece of code. Therefor I started working on a MVCish way to deal with templates in PW that considers the $page object kind of the data/model layer and adds View and Controller upon it. First by just catching everything via a small processor file added to all PW templates as altFilename. I’ve digged a bit deeper since then and hooked into the native rendering process, have been refactoring my code base more than a dozen times. Now I got a first version that seem to work and I’d love some of you guys to try it out! PVC (instead of MVC) stands for Page-View-Controller, as it considers PW’s $page var the model/data layer. I’m still working on the README.md on GitHub to document the basics. So have a look for more detailed infos there. I’ll give you a short overview here: Code separation: PVC introduces views and controllers to your PW templates as well as multiple action templates. Controllers, as most of you already know, keep all the business logic. Controllers execute actions wired to routes (urlSegment patterns). Even routes with dynamic segements (e.g. /edit/:id/) can be defined and assigned to an action, providing input through $this->input->route. Values can be set on the controller to be accessable in your templates later on. It’s also possible to set dynamic values as closures to be calculated (e.g. using field values of the current page) on render. Also controllers allow you to set layouts, styles and scripts to be available in your layout or template. Logic can be shared through inheritance between controllers. Views introduce view helpers. Helpers are functions that are made available to you (only) within your template context. There are predefined ones like embed(), snippet(), styles() or scripts(). But you can implement your own helpers easily and share them among your view classes through inheritance. Action templates contain the actual markup. Every action defined in a controller uses its own template. So the same page can display content accordingly to the action that was addressed via urlSegments/route. Within templates you can access all field values and values set on your controller like globals (e.g. <?=$title?>). Modular renderers: PVC implements rendering through separate renderer modules. PvcCore comes with PvcRendererNative that gives you template syntax the good ol’ PW/PHP way. A Twig renderer is in the making. And maybe you want to build your own renderer for the template syntax of your choice? I consider the module an early Beta version. So make sure to try it within a save environment! Would love to get some feedback (and error reports). I’m no professional developer, so code quality may suck here and there. So I’m glad for inputs on that, too. Also there is some old stuff in there yet, I still have to get rid of.1 point
-
I am starting an initiative for Slovak translation of ProcessWire. Any participants are welcome. https://github.com/rzelnik/ProcessWire-Slovak-Language-Pack1 point
-
I think it must be something in your sizeCloud method, because my quick testing with the ProcessPageEditImageSelect::executeResize hook seems to be working fine. Sorry about pointing you to the wrong function by the way. It is to do with your: $resizedImage = $image->size($width, $height, $options); Which means that $image is not the object you are looking for. Let me go on my way - to investigate a little more1 point
-
Sorry, I thought it would be more appropriate here. Will go back to the first post1 point
-
benbyf, see from here: https://processwire.com/talk/topic/148-release-redirects/?p=787981 point
-
You could use an autocomplete pageField for the tags. That way existing tags are available across all pages using the field. Check the "allow new pages to be created from this field" option. The end result, is that your tags are now page references that you can search against by the sanitized name field.1 point
-
A majority of the photos are from wikimedia commons. There are other sources too, but that seems to be the majority. The UF/IFAS Assessment Coordinator was tasked with gathering all the photos (previous incarnations of the assessment were just text). I gave her a few pointers about resolution, etc... but she really did an amazing job. There are some low-res photos or poorly composed shots here and there. They will all eventually be replaced with higher quality versions.1 point
-
You miss the ->url. You don't have to get the page like Adrian example as you already got the page.1 point
-
You need to get the URL from the field: $slide->slide_link_url->url; But to make things a little less confusing, I would rename your field from slide_link_url to slide_page or something like that By the way - I am not sure why this is in the Profields board - do you mind if I move it to general support or API? PS Soma - I edited my mistake before your reply came through - wasn't trying to hide my initial mess1 point
-
I would say you need two fields, one for internal PW pages - use a Page field with Deref in API set to: Single page (Page) or empty page (NullPage) when none selected and Inputfieldtype set to PageListSelect+ You can set the Parent of Selectable Pages to Home or any subbranch. For the external URL option, use the URL fieldtype so your editors can manually enter a URL. Then in your template code, check which one has a value and use that for the link. You may want to add a showif dependency so that as soon as one field has been populated, the other one is hidden.1 point
-
Dzień dobry girlz n boize! One thing just came to my mind, when reading Marcrura's new Module post: https://processwire.com/talk/topic/8477-processpageselectlinks/ There are many little helper modules out there that enhance the admin in neat little ways. Perhaps there should be ONE Module (say ProcessWireAdminHelpers.module), which provides hookable methods, so that helper modules can hook into them to be shown on the ProcessWireAdminHelpers.module settings page. There you could enable/disable or apply settings for each. Then there would be a single entry point for stuff like this. I don't want to manage the settings for 20 different modules on 20 different module setting pages. One person should take charge and design such a module, and module devs should then use it's hooks when creating little helpers schmelpers. Any thought's on that?1 point
-
I think there was a discussion about this some time ago in a thread here. While I quite like the ideas, I see some challenges that comes with this approach Who is handling the payment? What about taxes? How to "book" this income? How exactly should they work? Flattr? Paypal Donate? Why not just leave it up to the Developer, to include a Donate Link in his/her description? And I'm not sure if that many people would donate after all. If we/Ryan spent about 20-30 hours building the donate function and we only collect 200-300 Dollards in Donation after all..... - better build another great module1 point
-
1 point
-
Actually, I take that back - having "None" selected is a valid option as you can choose to output the components manually. For now, all you need to do is save the module config settings page once and the errors will go away, but I will fix the module so this is not necessary - should have it done pretty quickly. EDIT: Updated version of module just committed now saves default config settings during installation.1 point
-
The problem is that you haven't selected a "Phone Output Format" in the module config settings. The module needs this to know how you want it formatted. Do that and the errors will go away ! That said, I should probably handle this better1 point
-
BittorrentSync could be a rather simple solution for distributing the filesystem to different machines.1 point
-
Sorry, just trying to get an idea of what's going on here. So far it sounds like your domains are configured correctly, or at least they work (mostly) as expected. The fact that hortonsshortuns.com is identical in content to www.hortonsshortuns.com and both versions work is a problem (for this module and from SEO point of view) but as long as you use the version that you've configured this module to use, it's not really the issue right now. Anyway, this makes me think that there could be something wrong with the Multisite module config or the page it's trying to point the user to. If you're using Soma's variation of Multisite, I don't really know anything about that (never used it), but: It might be helpful if you could post here literally how you've configured the module (every config setting and value exactly as they are on your site, either as text or screenshots)? Also, just to rule out any inconsistencies, please double-check (or triple-check, or whatever) that the related page branch is correctly named (name field, not title) and placed in the page tree below the root page, something like this: - Home - whatever - whatever - hortonsshortuns.com - whatever - whatever - ... and so on Looks like this has been way more difficult than it should've been, but hopefully we'll get this sorted1 point
-
Hi Cerulean and welcome to PW! I honestly think the easiest way would be to delete any installed pages, templates and fields via the admin panel. Then remove the un-needed files from the templates directory. The only other way I can think of would be to replace the contents of the site folder with those from site-blank and then dropping the entire database and using the install.sql from site-blank/install to repopulate it. Then delete the install folder when you are done. Honestly though, this sounds like it could be fraught with danger1 point
-
What a fantastic and well-suited design! And thanks for sharing your challenges with the design and positioning - it certainly wasn't easy to achieve going from your description, but the end result looks brilliant. Well done1 point
-
A project like this isn't really funded in a big chunk. It comes from different sources, so we had to make some concessions out of the gate to build what we could with the first round of funding. The next phase has funding now, so we can start work again. Might take 3-4 phases to get everything done.1 point
-
Thanks Adrian, That's part of the minimum viability. There is a proper contact form already built (as well as several other forms via FormBuilder), but the contact form has other options that we weren't ready to introduce, so we decided to go with the simplest option for now.1 point
-
This module has intentionally been kept very simple, hence the login box appears on it's own. I actually prefer this for sites in development so that users can't see anything about the site until the protection has been disabled. However, what you are looking for is available in the Page Protector module. Just use the Login Template option in the module config settings. If you have any questions about it, please continue this discussion over in that thread.1 point
-
1 point
-
Ok, I have committed a new version that supports protection via the API. You can now do: // all optional, except "page_protected", which must be set to true/false // if setting it to false, the other options are not relevant $options = array( "page_protected" => true, "children_protected" => true, "allowed_roles" => array("role1", "role2"), "message_override" => "My custom login message", "prohibited_message" => "My custom prohibited access message" ); $page->protect($options); Let me know if you have any problems. EDIT: I am wondering if in your case dedicated code might be a better solution. This module stores the protection info in the module's data DB field. While this works great because there is no need for special fields to be added to the templates of a pages to be protected, I am worried you might come across some scaling issues if you have thousands or potentially millions of users, all wanting to protect various pages. I have no idea on the scale of your social network, but this is definitely something to consider.1 point
-
Managed to do this $pages->get(1)->get("image")->get("name=myotherlogo.png")->url and even $pages->get(1)->image->get("name=myotherlogo.png")->url I guess it's the shortest version...1 point
-
1 point
-
The most recent update to this module seems to have resolved this issue - working great again!1 point
-
Ryan, The new @ option in selectors saved me today. Just wanted to say thanks.1 point
-
1 point
-
Ok. We just launched our new website today, of course now running on ProcessWire. A long journey with many iterations and somewhat experimental. Still a work in progress, as much as never finished. There's a lot of inter-linkage going on between content news, projects and competence pages. Modules worth mentioning: TextformatterAutoLinks Markup RSS Feed http://update.ch (IE < 9 not supported, sorry. Old Androids may experience strange things)1 point
-
When searching pages with images field, there's no subfield "name" for images, but you can use images.data. And you won't get the image but a page(s) $p = $wire->pages->get("images.data%=mode"); // get return the first match echo $p->images->get("filename%=mode")->url; Or $p = $wire->pages->find("images.data=modelifestyle.jpg")->first(); // returns a pagearray and we access first echo $p->images->get("filename%=mode")->url; Or echo $p->images->get("name%=mode")->url; Or echo $p->images->find("filename%=mode")->first()->url; Or echo $p->images->get("modelifestyle.jpg")->url; Or echo $p->images->get("modelifestyle.jpg")->name; // image name or echo $p->images->get("modelifestyle.jpg")->filename; // full path1 point
-
Hi this was discussed a little in another thread: http://processwire.c...age__hl__mailer I actually use templates and Mandrill to send some of my transactional emails such as welcome emails and confirmations. It's relatively easy to do this using SMTP. Here's an example: <?php require_once "Mail.php"; require_once "Mail/mime.php"; $email = new Page(); $email->template = $templates->get("email-template"); $email->somePageVariable = "example"; $email->setOutputFormatting(true); $body = $email->render(); // Header info $from = "<info@yoursite.com>"; $to = "<user@name.com>"; $subject = "Thank you for registering!"; // Send via Mandrill $host = "ssl://smtp.mandrillapp.com"; $port = "465"; $username = "info@yoursite.com"; // Your mandrill user name $password = "secretKey"; // Your mandrill API key $headers = array ( 'From' => $from, 'To' => $to, 'Subject' => $subject, ); $smtp = Mail::factory('smtp', array ( 'host' => $host, 'port' => $port, 'auth' => true, 'username' => $username, 'password' => $password )); $message = new Mail_mime(); $message->setHTMLBody($body); $mail = $smtp->send($to, $message->headers($headers), $message->get()); if (PEAR::isError($mail)) { echo($mail->getMessage() . "\n"); } else { echo("Message successfully sent!\n"); } Because the template can pull in content anywhere from your site, you can easily make templates for upcoming events, latest news, etc. For inlining CSS, premailer now offers an API. I think it's best to use netcarver's tag parser for user-specific details when bulk mailing. You could render these in the template and pass in the user ID to that, but then you'd have to inline the CSS after rendering each and every email. It should be possible to avoid this by rendering the template, sending to premailer, and then looping through the recipients replacing the first_name, surname etc. I've not tried this out yet though. Stephen1 point