Jump to content

larrybotha

Members
  • Posts

    38
  • Joined

  • Last visited

  • Days Won

    1

Posts posted by larrybotha

  1. Hi there,

    My company, Fixate, has been building and supporting ProcessWire sites for a number of years now.

    I've recently accepted an offer for a position at another company, and as the last dev on the team (the team is now primarily UI/UX), we need to find someone who can assist with client requests.

    We have clients in Canada, Zambia, and South Africa, so we're comfortable with any timezone you may be in.

    The projects predominantly have this setup:

    • Dockerised services for quick setup
    • Gulp to automate:
      • builds and file revisioning
      • SSH deployments
      • backups / restorations

    Some of our client's sites:

    We're looking for someone to work directly with our clients when they need assistance.

    Feel free to contact me at larry U+0040 fixate.it

    Thanks!
    Larry

    • Like 3
  2. @onjegolders ye that's a bit of a pain. At Fixate we generally use placeholders until real content is added. Once real content is added, if someone needs the content for anything specific (usually the devs don't need all assets to work on the site) we'll Slack each other the assets.

    Once a site is on a staging environment it gets easier to manage, as final content is usually added there. We use rsync to sync remote assets to local folders, and sync site files to the remote using Gulp:

    https://github.com/fixate/generator-fixate-pw/blob/master/app/templates/gulp/tasks/rsync.js

    I'd be interested to hear how others handle it, but yup - don't commit assets or generated files (*.css, *.js, minified images, etc) to your repo - your repo should contain only dev and working files; a build process should be responsible for generating production files. Clean repos, and clean commit histories :)

    • Like 1
  3. Perhaps working solo and on only one machine would be ok for not committing database versions, but working with multiple devs would make db updates a nightmare if they weren't committed to a repo. Working from a single remote database is painfully slow, and as soon as you have no internet, your work stops there and then. At Fixate we've always versioned our db's for ProcessWire sites. Adding db exports to a repo is not ideal, but in terms of pragmatic workflow it's the fastest way to keep a project moving efficiently.

    The alternative would require a manifest or generator that would check if the correct fields are present on a database, and programmatically insert them (like Rails migrations). This would be the best way to go, as you're versioning your schema, as opposed to your data, but in terms of flexibility of what your admin looks like, you're going to have to manage enormous schemas for each template and field if you're to ensure the best UX in the admin for your clients.

    We've automated MySQL exports and imports with Gulp: https://github.com/fixate/generator-fixate-pw/blob/master/app/templates/gulp/tasks/mysql.js

    • Like 1
  4. @Nico Smit I took a look last night at 3.x with the MVC framework - I ran into a few issues where previously global ProcessWire functions weren't available, such as `wire` and `wireEncodeJSON` in `traits/search.php` and `controllers/javascript.php` (there'll be a couple other files, such as `traits/forms.php`, but I haven't yet scoured all the files), but the issue was remedied by adding the ProcessWire namespace to those files, and using the namespace to access the functions:

    <?php
    # traits/search.php
    use ProcessWire as PW;
    
    ...
      
    # changed from wire(...) to:
    PW\wire(...);

    I didn't have any issues with `Error: Class 'Environment' not found`. I did an install using our generator.

    UPDATE 06/11/2016: Just released 0.5.9 which adds fixes for the global `wire` calls in the boilerplate: https://github.com/fixate/pw-mvc-boilerplate/releases/tag/0.5.9

    • Like 2
  5. @Nico Smit our last PW project was released when 3.x was not yet stable, so we haven't yet toyed with the latest stable branch of PW. We'll be starting one or two new PW sites in the coming months, but with our current backlog I'm not sure we'll be getting there any time soon!

    In my spare time I'm building a project for our company on PW which will be starting in the next couple weeks, so I'll have to ascertain how quickly I can resolve those issues. If it's not too much trouble (I think it may come down to refactoring how our classes are instantiated / namespaced) I'll update the boilerplate then, but with our deadlines I may be forced to carry on with 2.x until I do get the time.

     

    @Nico Smit if you can open an issue, or even make a pull request it would be much appreciated!

    • Like 1
  6. To supplement @John the Painter's answer:

    1. Update InputfieldMapMarker.module to get your API key however you're managing it:

    public function init() {
    	$apikey = // get my api key
    	$script_path = ($this->config->https ? 'https' : 'http') . "://maps.googleapis.com/maps/api/js?key={$apikey}";
    	$this->config->scripts->add($script_path); 
    	return parent::init();
    }

    2. Enable 'Google Maps Geocoding API' in your Google API Console for your site's API key: https://console.developers.google.com/apis/api/geocoding_backend/overview

    You may need to enable whichever other individual APIs (places, geolocation, etc.) from Google's API library for the client side if you use the same API key: https://console.developers.google.com/apis/library

     

    Updating the MapMarker module will remove these changes if this file is affected by the update.

    • Like 2
  7. We've made a lot of progress on our generator. We're now using Gulp to automate everything, but still, it ties in strongly with our PW Boilerplate. You'll likely find a lot of useful things in our generator that you can take over.

    Some useful things:

    • automatically downloads the latest PW
    • automatically gets a few PW Modules we use in all projects
      • MarkupSimpleNavigation
      • ProcessRedirects
      • MarkupSitemapXML
    • install npm and all the dependencies in the Gulpfile
    • initialises bower

    The generated Gulpfile has a bunch of useful utilities:

    • browsersync
    • sass and coffee compilation
    • asset revisioning for production cache busting (like fingerprinting in Rails apps)
    • rsync utilities

    Instead of bash scripts being run, we've opted for a small Node app for better cross OS support.

    Feel free to fork it, and add and remove as you see fit.

    • Like 8
  8. thanks @WinnieB :)

    Yeoman's great for automating the dirty work and getting right to business.

    @boundaryfunctions great to hear it may be of use to you! It's very much based on Rails, and our new manifest feature is reminiscent of Sprockets / Asset Pipeline (but way faster thanks to Node and Gulp). Make sure to check out the wiki on the repo on Github - it's a little rough around the edges, but it should get you going a bit faster.

    • Like 1
  9. We've now added cache busting for all assets in our boileplate.

    This means that in production, if an asset has been added to a manifest in the assets/ folder, your site will now serve an MD5'd version of the file.

    i.e. style.css -> style-18925h5bsdfsdfn.css

    No worries about appending query strings or force refreshing to get the latest asset, it's all done for you.

    Use of the manifest is optional. If an asset is not being rev'd in the manifest, it will be served with the filename you provide.

    e.g.:

    <!-- if this asset is not in the manifest, it will be served as assets/img/logo.svg -->
    <link rel="logo" type="image/svg" href="http://<?= $config->httpHost . $this->assets('img/logo.svg') ?>"/>
    
    <!-- if this asset IS in the manifest, in production it will be served as assets/css/style-9n183he.css -->
    <link rel="stylesheet" type="text/css" href="<?= $this->assets('css/style.css') ?>" >
    

    For an asset to be eligible for rev'ing, it must be accessed through the assets helper in views / templates:

    $this->assets('path/to/my/asset.ext')
    

    This is used best in conjunction with some sort of task automation, for which we have a Yeoman generator which generates a project with a Gulpfile that handles all the rev'ing of assets without any additional work for you:

    https://github.com/fixate/generator-fixate-pw (and more specifically, the gulpfile: https://github.com/fixate/generator-fixate-pw/blob/master/app/templates/_gulpfile.coffee)

    To create the manifest, you can run the following from the command line:

    $ gulp build
    

    You're now ready to deploy with your cache busted assets.

    Assets that are being rev'd by Gulp are css, js, images, and fonts (even handles rewriting paths in your css).

    Happy cache busting!

    • Like 4
  10. A quick update: we've added a manifest for cache busting of assets via our generator and boilerplate. Assets in development are served as is, production assets are all MD5'd with references stored in a manfiest in /assets/rev-manifest.json

    If the manifest doesn't store a reference to an asset obtained via $this->assets('path/to/asset.ext') then it will simply serve the asset as specified in that helper.

    This means the manifest is completely optional.

    The manifest is generated via gulp tasks generated via our generator. The default gulp task will watch assets relevant to being revisioned, and keep the manifest updated as you work.

    ProcessWire Boilerplate: https://github.com/fixate/pw-mvc-boilerplate

    ProcessWire Generator: https://github.com/fixate/generator-fixate-pw

  11. Hi Mackski!

    The page-specific method is being called by the MVC framework, not by PW itself!

    Let's say you have a page with a name of /i-really-enjoy-carpeting using a template called 'carpeting'.

    Inside carpeting_controller.php you could then have the following:

    # carpeting_controller.php.php
    
    class CarpetingController extends ApplicationController {
      function page_i_really_enjoy_carpeting() {
        return $this->render();
      }
    
      function index() {
        ...
      }
    }
    

    What happens before a page is rendered is the call() method inside core/controller.php checks to see if there exists a method matching the snake-cased version of the current page name, prepended by 'page_'. If so, it will use that method instead of index() in the controller, allowing you to set variables and use templates for that page only.

    i.e. if the current page's name is i-really-enjoy-carpeting, and a page_i_really_enjoy_carpeting() method exists in the controller, use that method to process logic for that page.

  12. You can render templates from wherever you like - by default render() will look inside views/, but you can set a relative path from there:

    // MyController.php
    
    class MyController extends ApplicationController {
      ...
    
      function index() {
        ...
      
        // use views/dialogs/my_template.html.php
        return $this->render('dialogs/my_template', array(...));
      }
    }
    

    will look inside views/dialogs/

    Did I understand your question correctly?

    ----------------------------------------------

    WRT api_controller.php, my knowledge of ajax is pretty slim (I didn't write any of the API stuff, so I may be wrong here), but what appears to happen is when a request comes in from your JS, the boilerplate will look at controllers/api/my_controller.php instead of controllers/my_controller.php.

    Inside controllers/api/my_controller.php you will extend ApiController, instead of Controller. The call() method in the ApiController class, in contrast to the Controller class', looks for a method that matches an HTTP verb you would need to define in your controller (PUT, PATCH, DELETE, and UPDATE don't seem to be supported - perhaps because ProcessWire only supports GET and POST), and handles it accordingly.

    The ApiController class has its own partial() method to generate markup inside controllers. The return value of your method is then handed back to your JS.

    So, in a nutshell, you should be able to create a new controller as follows:

    <?php
    /**
     * MyController - API Controller
     */
    
    class MyController extends ApiController {
      ...
      
      // GET verb specified in AJAX request
      function get() {
        ...
    
        $html = '';
    
        // use views/partials/dialogs/my_dialog.html.php
        $html .= $this->partial("dialogs/my_dialog", array(...));
    
        // return results of request to js
        return array(
          'html' => $html
        );
      }
    }
    

    Additionally, there's a function, render_js_data(), in javascript.php which will retrieve the page's path and template as a window object in a script tag for easy access in your javascript. You can simply add it to scripts.html.php:

    // scripts.html.php
    
    ...
    
    <?= $this->render_js_data() ?>
    <?= $this->render_scripts() ?>
    
    

    and in your js then use:

    // main.js
    
    if (this.processWire.template === 'my_template') {
      // do something
    }
    

    I hope I've made sense!

  13. Hi Nico,

    UrlSegments are something we haven't yet really considered for the framework - purely because we haven't had to use them yet!

    You were on the right track, but the name of the function wasn't outputting correctly with your modification - call() allows you to define a function based on a particular path. You'd have to loop through all urlSegments, until you get to an empty one, and then append a string of all the segments to the name of the page in call().

    In your controller you would then have:

    // tasks_controller.php
    
    ...
    
    // handle requests to tasks/action/update
    function page_tasks_action_update() {
      return $this->render('some-template', array( 'some_var' => 'some_value' ));
    }
    
    ...
    

    I've made an update to core/controller.php: https://github.com/fixate/pw-mvc-boilerplate/blob/master/core/controller.php#L80-L97 to handle urlSegments :)

    • Like 1
  14. Hi @gebeer

    Ye, I must outline some of the features of the generator - it can definitely improve workflow!

    It's a little opinionated - it generates projects using our SCSS framework, our KSS Styleguide Boilerplate, an extensive Gruntfile for much awesome automation, and of course the MVC Boilerplate, all of which are fundamental to our ProcessWire projects.

    As a quick overview, you can expect the following structure from a newly generated project :

    ├── database              // location for automated db dumps
    ├── src                   // PW install location
    ├── styleguide            // KSS Boilerplate, and SCSS (style.css built to templates)
    ├── .bowerrc              // tell Bower where to install libraries
    ├── .editorconfig         // normalise line endings, tabs, etc for all team members
    ├── .gitattributes        // have git normalise line endings cross platforms
    ├── .gitignore            // default ignores
    ├── Gruntfile.coffee      // automated deliciousness
    ├── package.json          // Grunt dependencies
    ├── private.json          // .gitignored - put sensitive data here (SSH keys, db creds etc)
    └── private-sample.json   // a template private.json for other devs to add non-committed sensitive data
    

    I'd like to put together a post covering some finer details in the next 2 weeks or so - things are a bit crazy here at the moment!

    I'll update here to let everyone know!

    • Like 2
  15. The advantage of having it in a separate file is that you are separating your concerns. Logic is kept with logic, markup is dedicated to displaying and layout of the data. This makes it easy to understand where things are, how they got to be there, and where to add what as you extend a site. Have a read through just the views in the boilerplate - there is no repetition, everything is well organised and brief, and it is easy to understand where markup is being obtained.

    Many functions will be specific to just one template, but other logic is likely to be shared across a number of templates. Abstracting logic away from markup ensures that you can quickly find where to add logic, or where logic is being defined. You can see how we have achieved this with the controllers/traits files - SEO, Search, Opengraph, etc.

    A nice result of this methodology is that your files are often shorter, and easier to manage.

    In the Ruby realm it's considered good practise to keep functions down to approximately 5 lines, so that they are brief, and achieve only one goal. Keeping files to an approximate maximum length of 100 lines is another good practise - try reading through WordPress core files; it won't be long before you find a monster 1000+ line file (possibly even a single function of that length). That's insane, a nightmare to navigate and manage, and is plain horrible for devs when debugging WordPress' innumerable quirks. When your files and functions start exceeding these numbers, there's often room to neaten things up, make things more concise, and abstract functionality elsewhere. It helps you, helps future devs, and makes unicorns poop rainbows!

    You can, of course, write all of your logic into the template, but then may you lose reusability of the code, and will undoubtedly lose brevity, or have to add logic in places which may not make sense. MVC removes this issue entirely - you always know what goes where. ProcessWire allows you to use _init.php and other mechanisms to handle this, but that can quickly become unwieldy, so abstracting concepts to separate files can then become beneficial.

    I'm sure the boilerplate can also be achieved using modules, but it made sense for us to keep the controllers right with the views (as in Rails), since controllers are created as we add templates in the admin. Perhaps in the future it would be beneficial to move the logic out to modules, but we'll only look at that should we see a benefit over how we're doing it right now. It's awesome that we have the flexibility to make such decisions with ProcessWire.

    Another cool thing is that when you don't want to use the MVC approach, such as when you want a template to redirect - then you don't use MVC! Point the template directly to its file, and put the redirect straight in there, bypassing all the boilerplate logic. You get the best of both worlds.

    • Like 5
  16. Rails uses MD5's for asset filenames, which is awesome, but requires some sort of build process so that the process isn't run on every page load when using PHP. We're looking to eventually build this into our MVC Boilerplate, as cache busting is a bit of an irritant.

    • Like 1
  17. You're correct, I didn't check the response header for the page without the file, so it is a 404 - baffling!

    It definitely isn't working with ProcessRedirect - as soon as I remove the percent encoding I get the 404 page I expect, and that URL can be used as the from address.

  18. @OrganizedFellow MVC's not too bad, really. I was always intimidated by it, but all it really is is this:

    • Models -> object definitions, and communication with the database (not really applicable in PW because the API speaks with the DB).
      Models are an interface between the database, and controllers
    • Views -> Logicless (mostly) templates which are responsible for markup, and display of data.
      Views communicate only with controllers
    • Controllers -> functional and logical aspects regarding instances of an object (in our case, instances of page templates).
      Controllers are an interface between Models, and Views

    As a side note, we have a yeoman generator which will quickly help getting an entire PW project set up: https://github.com/fixate/generator-fixate-pw

    I'll eventually cover this in a separate post.

    • Like 3
  19. This is an edge case, and a nasty side effect of IIS servers allowing spaces in paths. I'm going to document so as to allow people to perhaps gain some knowledge on it, but also to see if it's something applicable to this module, or ProcessWire (although I'm thinking this comes down to Apache more than anything else).

    We've just launched a new site, and our client's SEO guys are adding redirects from the old site.

    The old site was on IIS servers, whereas it's now on a Unix host running Apache. One of the redirects is a pdf, residing in a folder that contains a space.

    This is what I've attempted:

    • visit the pdf directly (bare in mind, this pdf no longer exists)
      • expected:
        404 on request
      • result:
        home page shown
        pdf 404's
        URL is displayed as example.com/full/path%20with%20spaces/somepdf.pdf
    • visit example.com/full/path%20with%20spaces/
      • expected:
        404 on request
      • result:
        display home page
        full URL is retained

    So this leaves me with the problem that ProcessRedirect first checks if a URL returns a 404, and doesn't get one, and thus does not perform a redirect.

    I doubt this is ProcessWire's doing, in which case the issue must be with how Apache is handling the request.

    Solution: add urls containing spaces directly to .htaccess with a Rewrite rule (blergh!).

    I hope this helps someone who may think it's the module's fault (and I hope I'm wrong, and that someone may have a better solution for me!).

  20. hey xweb,

    Sorry about only replying now!

    You can add vars to views either on a per view basis, or to all views, by doing the following:

    Make a variable available everywhere:

    ...
    // controllers/application_controller.php
    
    class ApplicationController extends Controller {
      ...
    
      function initialize() {
        ...
        
        // look in core/controller.php to see how add_view_vars() works
        $this->add_view_vars('my_var', 'my var value');
    
        ...
      }
    }
    
    // basic_page.html.php
    <?= $my_var ?>
    

    Make a variable available to a particular view:

    ...
    // controllers/basic_page_controller.php
    
    class BasicPageController extends Controller {
      ...
    
      function index() {
        /**
         * use the implicit template name (basic_page in this case), 
         * and make $my_var available to the view
         *
         * look in core/controller.php to see how render() works
         */
        return $this->render(null, array('my_var' => 'my var value'));
      }
    }
    
    // basic_page.html.php
    <?= $my_var ?>
    

    Make a variable available to a partial:

    Variables can be passed through to partials in a similar fashion to how the render() function is used within controllers.

    // basic_page.html.php
    <?= $this->partial('my_partial', array('my_var_in_partial' => $my_var) ?>
    
    // my_partial.html.php
    <?= $my_var_in_partial ?>
    
×
×
  • Create New...