Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 12/13/2014 in Posts

  1. I assume you have a special template for /functions/ and you have set up your config.php to auto-append _main.php. You can exclude templates from auto-appending and auto-prepending in the “files” tab of the template settings. If auto-append is active, there will be a checkbox called “Disable automatic append of file: _main.php”. Regardless, it’s always a good idea to die() as soon as possible. In your case, I would advocate putting a die() at the end of each if ($command ...) block, unless there’s something you need to do afterwards. Probably a good idea to use a switch, too, then.
    5 points
  2. I recently created an ecommerce website, iBuildMacs, that I built with ProcessWire. Given that there's been quite a bit activity on combining ecommerce with ProcessWire, I feel many people would be interested in the approach I took. Feel free to visit it at: http://ibuildmacs.com/ The requirements for this site were: a computer configurator, much like the Apple website; example product page here cart checkout payment methods: paypal or check/cash shipping methods: the cost of shipping is based on a fixed cost that is related to the country being shipped. no live quotes The requirements did NOT include: tax rules inventory management coupons, gift certificates different product types: simple products, variable products, digital/downloadable products, etc. user accounts, address management a fancy ajax driven checkout So, I had a bit of flexibility for this site given the specific feature set. I then thought about how I wanted to develop the site. The options I considered included: WooCommerce: I've built several intricate websites with WooCommerce, the most recent being caviar.com. It was good fit that website, but for iBuildMacs, which has less requirements and a very unique product configurator, which WooCommerce could do but with a tremendous amount of overrides and working backward, I decided this wouldn't but the right fit. Plus, I'm trying to become as WordPress-free as possible. FoxyCart: A ProcessWire favorite, however I wanted to challenge myself a little bit with this site, and also keep things under one roof. Magento, Shopify, (insert some specific heavy or cloud-based ecommerce system you like): No. Overkill and making a product configurator would be a pain. After considering my options, I felt just rolling it entirely with ProcessWire and programming the catalog, payment methods, shipping methods and checkout tailored to the site's specific needs was the way to go. This would definitely reduce the time and headache needed in bending anyone of the above systems I mentioned to behave exactly the way I wanted it to. Products This was one of the complicated parts of the website, but ProcessWire, with its infintely flexible custom fields, made this a breeze. I have a product template (product.php). It has some general fields like Title, Body, Image and Base Price. It also has a PageTable field called Features. These features are child pages of the product and use feature template (feature.php), so the Features PageTable field just grabs its data from there. Then, the feature template has some general fields like Title, Body, Image and PageTable field called Feature Options. These feature options are child pages of the feature template using the feature option template (feature_option.php). So, what I ended up having is a 3 level deep structure, with two nested PageTable fields. Here's a video of what it looks like, which is quite slick is very easy to manage: https://vid.me/kjDW Cart When a user adds a configured product to their cart, it must be stored somehow and I thought of a variety of ways to do this. Ultimately, I decided that cart data is handled as a page (using the order.php template) undernearth /orders/. This order.php template has a page name that is based on the session id of the user, so it'll remain unique and not cause a conflict with other people's carts (as well as obscure from people trying to guess it's url, which is used for the order confirmation page). One of the fields in this order.php template is called "products_ordered", which utilizes the Table fieldtype (a Profields table). Video: https://vid.me/MIRl Checkout The checkout is a straight forward form with the basic questions. However, the shipping section is where it gets tricky. The requirements for this site were that each computer has a fixed shipping price depending on the method being used to ship. The shipping methods available to a customer are dependent on their country. I think WooCommerce could manage rules like that, but directly coding it wasn't that difficult. I create an array that stored the 2 payment methods, and another array that stored the 6 total shipping methods. I also have an array for all the countries. I then wrote some JavaScript that managed the relationships between the country chosen and the shipping methods available for the chosen country. When choosing a method, it will update the Shipping cost line item on the car to the right. Just basic JavaScript going on here. All nice and on one page. When the submit button is pressed, it will run through some logic and validate all the data and save it to the same page that stored the cart data. An order confirmation email is sent to the customer, and one is also sent to the admin (SwiftMailer). If Check/Cash was chosen, the user is then simply forwarded to the order confirmation page, which is at /orders/whatever-their-page-name-was-saved-as/. The email they are sent also has a link referencing this page. If PayPal was chosen, a URI is built and the user is taken to PayPal complete payment with PayPal Payments Standard using the Cart Upload command. Documentation here. After they complete Payment on PayPal, they are then taken to the order confirmation page as described previously. Video: https://vid.me/hwfB I will eventually be using ListerPro for a nicer admin orders list display and build a few custom actions to allow administrators to quickly send general emails from the system (like, when the order is shipped). Modules Used Admin Template Columns: http://modules.processwire.com/modules/admin-template-columns/ Markup Simple Navigation: http://modules.processwire.com/modules/markup-simple-navigation/ Maintenance Mode: http://modules.processwire.com/modules/maintenance-mode/ Batcher: http://modules.processwire.com/modules/process-batcher/ Form Builder (for the contact form only): https://processwire.com/talk/store/category/2-form-builder/ Swift Mailer: http://modules.processwire.com/modules/wire-mail-swift-mailer/ PageTable field type ProFields Table: https://processwire.com/talk/store/category/7-profields/ ListerPro (eventually): https://processwire.com/talk/store/category/9-listerpro/ Enjoy!
    4 points
  3. 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.
    3 points
  4. Inputfield And Fieldtype ImageFocusArea requires ProcessWire 2.5.6 or later This Inputfield makes it possible to select the important part of the image and use this area for different cropping options. This module is not a replacement for the existing Thumbnails module, though depending on your need it probably could replace it in many cases. I think a more flexible cropping approach than the existing Thumbnails module is useful especially when using the new html <picture> and you don't want the editor to define multiple thumbnails. Usage Create a new Inputfield ImageFocusArea and add it to the desired template. Edit a page with this template and add an image to the new field. You will see a link "Add Image Focusarea". Click the link and you will see a popup with a cropping tool similar to the Thumbnails module. Select the important part of the image, click "apply" and save the page. By default the Field hooks into Pageimage::size and automatically populates the cropping option with percentages of the center of the selected focusarea. You can always override this behaviour by calling $image->size with a different cropping option (e.g. $image->size(100,100,array('cropping'=>'center'))). The module introduces 3 new cropping options: align: This is the default if you do not override it with another cropping option. When resizing a image the module only adjusts the alignment of the crop. You will get the most zoomed-out result of these options. inside: Only parts inside of the selected area are used in the resulting image. You will get the most zoomed-in result of these options. outside: The resized image will contain the whole selected area. The surrounding imagearea will be used to reach the targetsize. This is also true for upscaling=false. Upscaling will only happen if the source image was smaller then the targetsize. API usage examples // here we force the old/usual 'center' mode: echo "<img src='{$page->image->size(200,200,array('cropping'=>'center'))}' />"; // by default if you did not define a cropping option, the cropping option gets automatically populated // Both calls will result in the same image: echo "<img src='{$page->image->size(200,200)}' />"; echo "<img src='{$page->image->size(200,200, array('cropping'=>'align'))}' />"; // the resulting image will be the center area of the selected focusarea echo "<img src='{$page->image->size(200,200, array('cropping'=>'inside'))}' />"; // to get an image with exactly the same ratio as the focusarea use width()/height() instead of a size() echo "<img src='{$page->image->width(200, array('cropping'=>'inside'))}' />"; echo "<img src='{$page->image->height(200, array('cropping'=>'inside'))}' />"; // the whole selected area will be part of the image, the surrounding imagearea will only be used to reach the targetsize echo "<img src='{$page->image->size(200,200, array('cropping'=>'outside'))}' />"; Flexible CSS Background Images Additionally you can access a new property cssBackgroundPosition, which could be useful for frontend responsive images. The visual result is similar to the cropping='align' mode, but depending on the size and postion of the focusArea and your images source and target size your mileage may vary. This property is intended to be used together with background-size: cover;. It is important that the background-image has the same ratio as the original image! <style> .cssimg{ background-size: cover; width:200px; height: 200px; } </style> <div class="cssimg" style="background-position: <?= $image->cssBackgroundPosition ?>; background-image: url(<?= $image->url ?>); "></div> Downloadhttps://github.com/phlppschrr/ImageFocusArea remember, this modules requires ProcessWire 2.5.6 or later There are still known bugs with upscaling=false, but I am not sure if it is a bug of this module or a ProcessWire bug. (fixed in ProcessWire 2.5.6) Thanks to Ryan and especially Horst for all the new great API additions for Pageimage und ImageSizer which made this module possible. This is my first module. If you notice any problems or unexpected behaviour post here or fill an issue on github. I am open to all suggestions. Do you think the cropping option names (align, inside, outside) are descriptive enough? Any better ideas? -- Edit: Renamed the Module to ImageFocusArea and updated the github link Edit 2: Reformatted this post and added some additional information.
    1 point
  5. Just another addition: Dell released a new IPS 27" (and also 24") UHD/4K (3840x2160) displays in the last week. While they're no reviews, the screens are shipping. Look for the Dell P2715Q or Dell P2415Q. The 27inch models costs about 700 Bucks.
    1 point
  6. As a guide or helper of features that would be needed for a module to comply with the EU vat law I found a Wordpress plugin for woocommerce that seems to tick all the boxes. https://wordpress.org/plugins/woocommerce-eu-vat-compliance/ Also found a European Vat number validation API http://isvat.appspot.com/
    1 point
  7. Small update on this: I will build support for tax classes, stock management and simple reports during Christmas holidays. After that hopefully ready for wider beta testing.
    1 point
  8. I have updated the module to Version 0.1.0 beta and it has a new addition to the weighten option that can be used together with contain. The initial code I have taken for weighten calculations is from Martijn. I have changed it to simplify its usage so that you only need to specify a bounding square and have to switch it on, or additionaly prioritize landscape oriented images in two favours: x1, x2 or do the same for portrait oriented images with: y1, y2. (read more in the posts above) But if you (@Martijn ) like to use more different options, like with the original ImageFitBoundaries.module, you can use it by specifying different values for width and height together with the new value "comp##". For ## you set the value for compression like comp20, comp30, comp40 or whatever you like.
    1 point
  9. 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
  10. @nico and mademyday (just in case you don't know already) you can delete pages by clicking on "move" and then on the right "trash" since 2.5 https://processwire.com/blog/posts/processwire-2.5-changelog/#admin-theme-and-ui
    1 point
  11. Hi Marty, assuming you want to build a grid upon an unknown collection of images and you want to have full control, you may start with this construct and change it to suite your needs: echo "<br /><hr /><pre style='font-family:monospace;'>"; // only a little test unit $yourImagesArray = array( 1,1,1,1,1,1, 1,2,1,1,1, 1,1,1,1,1,2, 1,1,1,2,1,1,1,2,1,2,1,1,1,2,1,1,1,1,2,1,1,1,2,1,1,1,2,1,2,1,1,1,2,1,1,1,1,2,1,1,1,2,1,1,1,2,1,2,1,1,1,2,1); // build the grid $images = $yourImagesArray; // containing lots of images, most with no tag or a "single" tag and some with a "twice" tag! You have to make sure it contains enough images for your grid, so. $i = 0; for ($row=1; $row<=7; $row++) { echo "\n$row:"; // only for the test for ($col=1; $col<=6; $col++) { // get the next image from the collection $img = $images[$i++]; // you would use $images->eq(++$i) with real images here! if (6 == $col) { // only special case is with the last $col while (2 == $img) { // last $col cannot take a "twice"-image. For the example I simply drop all "twices" while searching for a single-one. $img = $images[$i++]; } } // now we have a valid $img for our grid, so create output if (2 == $img) { $col++; // adjust the $col counter! echo 'oo'; } else { echo 'O'; } } } // ready with grid echo "</pre><br /><hr />"; // only for the little test unit test output is: 1:OOOOOO 2:OooOOO 3:OOOOOO 4:OOooOO 5:OooOoo 6:OOOooO 7:OOOooO
    1 point
  12. Okay, I will address the Pages issue - I am somewhat famous for it! To start: https://processwire.com/talk/topic/2296-confused-by-pages/ And once you have that out of your system, here is the real info. Basically, a page in Processwire is just a container for content - nothing more. So, it could be a: Web Page News Bullitin Block of info Some strange widget An option for a dropdown selector A gallery item A review Something that gets stuffed into something else! A parent of some other group of pages, A child of something Basically, it is just an item that is created using the criteria of a template. It does not need to have a template file associated with it - if you are using it as a simple option in a drop down, what would be the point? Fields from a particular page can be called into another template or page or anything else, either singularly or rendered as a group. The contents of a page need a template file to be displayed on the site as they are, but not if they are being displayed by something else. Confused? The bottom line is don't think of a page as a "page" that you would get in Wordpress - just think of it as a container for data that can be used for anything at all. This is why Processwire is a TRUE content management system - because all the elements are simply tools to help you manage content, they do not force you to make your content any particular shape.
    1 point
  13. The symlink options works fine. You just have to understand and configure your permissions accordingly. This is how lightning.pw works (We have a /wire/ folder for every PW version and a /site/ folder for every customer install). You can put modules in there too.
    1 point
×
×
  • Create New...