Leaderboard
Popular Content
Showing content with the highest reputation on 06/05/2019 in all areas
-
We recently rebuilt the Architekturführer Köln (architectural guide Cologne) as a mobile-first JavaScript web app, powered by VueJS in the frontend and ProcessWire in the backend. Concept, design and implementation by schwarzdesign! The Architekturführer Köln is a guidebook and now a web application about architectural highlights in Cologne, Germany. It contains detailled information about around 100 objects (architectural landmarks) in Cologne. The web app offers multiple ways to search through all available objects, including: An interactive live map A list of object near the user's location Filtering based on architect, district and category Favourites saved by the user The frontend is written entirely in JavaScript, with the data coming from a ProcessWire-powered API-first backend. Frontend The app is built with the Vue framework and compiled with Webpack 4. As a learning exercise and for greater customizability we opted to not use Vue CLI, and instead wrote our own Webpack config with individually defined dependencies. The site is a SPA (Single Page Application), which means all internal links are intercepted by the Vue app and the corresponding routes (pages) are generated by the framework directly in the browser, using data retrieved from the API. It's also a PWA (Progressive Web App), the main feature of which is that you can install it to your home screen on your phone and launch it from there like a regular app. It also includes a service worker which catches requests to the API and returns cached responses when the network is not available. The Architekturführer is supposed to be taken with you on a walk through the city, and will keep working even if you are completely offline. Notable mentions from the tech stack: Vue Vue Router for the SPA functionality VueX for state management and storage / caching of the data returned through the API Leaflet (with Mapbox tiles) for the interactive maps Webpack 4 for compilation of the app into a single distributable Babel for transpilation of ES6+ SASS & PostCSS with Autoprefixer as a convenience for SASS in SFCs Google Workbox to generate the service worker instead of writing lots of boilerplate code Bootstrap 4 is barely used here, but we still included it's reboot and grid system Backend The ProcessWire backend is API-only, there are no server-side rendered templates, which means the only PHP template is the one used for the API. For this API, we used a single content type (template) with a couple of pre-defined endpoints (url segments); most importantly we built entdpoints to get a list of all objects (either including the full data, or only the data necessary to show teaser tiles), as well as individual objects and taxonomies. The API template which acts as a controller contains all the necessary switches and selectors to serve the correct response in <100 lines of code. Since we wanted some flexibility regarding the format in which different fields were transmitted over the api, we wrote a function to extract arbitrary page fields from ProcessWire pages and return them as serializable standard objects. There's also a function that takes a Pageimage object, creates multiple variants in different sizes and returns an object containing their base path and an array of variants (identified by their basename and width). We use that one to generate responsive images in the frontend. Check out the code for both functions in this gist. We used native ProcessWire data wherever possible, so as to not duplicate that work in the frontend app. For example: Page names from the backend translate to URLs in the frontend in the form of route parameters for the Vue Router Page IDs from ProcessWire are included in the API responses, we use those to identify objects across the app, for example to store the user's favourites, and as render keys for object lists Taxonomies have their own API endpoints, and objects contain their taxonomies only as IDs (in the same way ProcessWire uses Page References) Finally, the raw JSON data is cached using the cache API and this handy trick by @LostKobrakai to store raw JSON strings over the cache API. Screenshots19 points
-
I'm not really sure why we would actually need a new permission here at all. We already have a permission to view a page and one to edit a page. It's just that ProcessWire is build with custom frontends in mind and "viewing" a page is generally considered to be done by viewing the page on the frontend. That's why we have ProcessPageEdit and not ProcessPage. I can see that repurposing ProcessPageEdit one could make it basically behave as though any field would be set to "not editable" when a user only has permission to view a page, but not edit it. I just expect that the implicit notion of "you look at a page on the frontend" is build into many places. Like everywhere you currently have a link to edit a page the permission checks need to be changed, it probably cannot be named "edit" anymore or at least must dynamically be switched between "edit" and "show". The latter might still cause some confusion.2 points
-
Feeling like Apple has finally addressed the 'Pro' market here but their definition or Pro is limited to video editors. What about Pro Web Designers and Pro Developers? What about Pro photographers etc There's many Pro industries out there that don't need those high specs and prices but would benefit from a modular and upgradeable machine. Re their monitor, IMHO there's a big market for a display that it simply an upgrade to their old cinema display. Something max 4K and 27" with thunderbolt and a stand included would be ideal.2 points
-
For the last couple months, I've been working on a module that does exactly this. It's not a site profile, it's not a theme. I don't know what term would accurately describe it, but its a ProcessWire module that's an opinionated, update-able starting point, oriented towards developers, and brings in a bunch of boilerplate like: an installer that will create fields, templates, pages, hannacodes; it runs through a thorough check before doing anything that may result in an error (module installation errors are aggravating; i'm testing it very thoroughly) the installer will rename your 'templates' dir to something temporary, and then copy a starting 'templates' folder that's prepped for the module (you should only do this on dev) if you try to add it to an existing site with a bunch of data, it will work as long as there are not collisions in some fields and templates; if there are, the module won't install and tell you what you need to change around to allow it to install establishes some new $config variables ('env', 'disableTemplateCache', a few others) built with UIkit 3 in mind, but not hardcoded to it a menu builder based on Repeaters with its own Process Module has its own seo+og+twitter+sitemap metadata fields and uses Profields FieldGroup since that is the best module for handling such a grouping has it's own templates inside the module which can be used, or overridden in /site/templates/; this includes blog sitemap.xml maintenance search in addition to template files being able to be overridden, partial files can be overridden too! some module configuration fields (site_name, maintenance, etc.) the module has documentation and other statistics built into it for easy reference takes full advantage of setting() and markup regions; applies attributes like UIkit 'uk-grid' and other data attributes without "touching" the html; keeps the module flexible and easily allows you to rip out UIkit and swap it for another CSS framework (Bootstrap 4); you'll never need to touch edit the _main.php file because of how regions has been set up has it's on RepeaterMatrix fields with boilerplate matrix-types (headline, text, slideshow, etc. etc.); if the user makes new custom matrix types and a later version of my module brings in a new matrix-type, it will update the RepeaterMatrix field and merge it correctly (tricky to do!); the matrix types use many of the same base fields, thereby allowing you to switch from one matrix type to another without data being destroyed (this was only possible as of 2 weeks ago with the new matrix update) to avoid creating a bunch of 1-off fields for the matrix field for block configuration, it uses the new and quite amazing Mystique fieldtype in a unique way (this was tricky to do); this module is critical to establishing a page-builder that is clean (this was only possible as of April 2019 since the module is brand new) brings in PW's debugger to the frontend (brings in jQuery UI); can be disabled all field and template names don't use any prefixes; this would allow you to dump the module one day in the future if you don't like it, without having a bunch of field and template names that sound too specific to the module Laravel Mix based asset compiler pre-configured with UIkit works with FormBuilder and other modules I often use; works and may require certain Pro modules; eliminates the need for any modules that do blogging, menu building, sitemap, maintenance or seo since this module does it using native ProcessWire login/logout/account/register templates it may include a 'collection' generator for common things like events, products, people, properties, along with some templates for those. don't like the templates my module provides? then just create your own template file in /site/templates/the-template-file.php which will override /site/modules/my-module-name/templates/the-template-file.php Right now I just started building a few sites with it (spent the last 2 months developing it) which will hammer it out further. I will release it late summer, early fall.2 points
-
FieldtypeColor is on github Fieldtype stores a 32bit integer value reflecting a RGBA value. Input 5 types of Inputfields provided Html5 Inputfield of type='color' (if supported by browser) Inputfield type='text' expecting a 24bit hexcode string (RGB). Input format: '#4496dd'. The background color of the input field shows selected color Inputfield of type='text' expecting 32bit hexcode strings (RGB + alpha channel) Input format: '#fa4496dd' Inputfield with Spectrum Color Picker (Options modifiable) Inputfield type='text' with custom JavaScript and/or CSS (since version 1.0.3) Output Define output format under 'Details' tab in field settings. Select from the following 9 options string 6-digit hex color. Example: '#4496dd' string 8-digit hex color (limited browser support). Example: '#fa4496dd' string CSS color value RGB. Example: 'rgb(68, 100, 221)' string CSS color value RGB. Example: 'rgba(68, 100, 221, 0.98)' string CSS color value RGB. Example: 'hsl(227, 69.2%, 56.7%)' string CSS color value RGB. Example: 'hsla(227, 69.2%, 56.7%, 0.98)' string 32bit raw hex value. Example: 'fa4496dd'(unformatted output value) int 32bit. Example: '4198799069' (storage value) array() array( [0] => 0-255, // opacity [1],['r'] => 0-255, [2],['g'] => 0-255, [3],['b'] => 0-255, ['rx'] => 00-ff, ['gx'] => 00-ff, ['bx'] => 00-ff, ['ox'] => 00-ff, // opacity ['o'] => 0-1 // opacity ) The Fieldtype includes Spectrum Color Picker by Brian Grinstead SCREENSHOTS Input type=text with changing background and font color (for better contrast) Input type=color (in Firefox) Javascript based input (Spectrum Color Picker) Settings Output Settings Input1 point
-
WireCache is a really nice way to quickly cache data to the database, but when working with json data there are some quirks. Imagine the following examples: $data = $cache->get('my-key', WireCache::expireHourly); if(!$data){ $data = […] $cache->save('my-key', $data, WireCache::expireHourly); } // API response $response = json_decode($data); $image = $response->data[0]->image; // or $html = "<div data-json='$data'></div>"; Both should work from the quick look. Both will fail as soon as the cache kicks in. This is because the implementation of WireCache tries to be smart and does automatically decode data, which is detected to be json. But it doesn't just decode it like in my example, but rather uses json_decode()'s second parameter to decode the json as associative array(s) instead of stdobject(s). If you prefer the object syntay to traverse your json data or you really want to store raw json, then I've got two hooks for you, which do prevent the automatic json detection of WireCache, so you can work with the stringified json as you need to. Just replace the get() and save() calls in the example with getRaw() and saveRaw(). $wire->addHook('WireCache::saveRaw', function(HookEvent $event){ $args = $event->arguments(); $args[1] = '::RAW::' . $args[1]; return $event->return = call_user_func_array([$event->object, 'save'], $args); }); $wire->addHook('WireCache::getRaw', function(HookEvent $event){ $args = $event->arguments(); return $event->return = str_replace('::RAW::', '', call_user_func_array([$event->object, 'get'], $args)); });1 point
-
Hi there, I have a simple Fieldset layout in a process module based on the code below: /** @var InputfieldWrapper $wrapper */ $wrapper = new InputfieldWrapper(); /** @var InputfieldFieldset $fsTop */ $fsTop = $modules->get('InputfieldFieldset'); $fsTop->icon = 'bar-chart'; $fsTop->label = $this->_('Top Store Actions'); $fsTop->wrapClass = 'bottomSpace'; /** @var InputfieldMarkup $f */ $f = $modules->get('InputfieldMarkup'); $f->label = $this->_('Top Customers'); $f->value = $this->_renderTableCustomers($dashboard[SnipRest::resourcePathCustomers]); $f->columnWidth = 50; $f->collapsed = Inputfield::collapsedNever; $fsTop->add($f); /** @var InputfieldMarkup $f */ $f = $modules->get('InputfieldMarkup'); $f->label = $this->_('Top Products'); $f->value = $this->_renderTableProducts($dashboard[SnipRest::resourcePathProducts]); $f->columnWidth = 50; $f->collapsed = Inputfield::collapsedNever; $fsTop->add($f); $wrapper->add($fsTop); $out .= $wrapper->render(); In UIKit admin theme it renders correctly like this: In Default and Reno theme like this (which is wrong): If I change the InputfieldWrapper to InputfieldForm it works as expected. But I don't like to use a form wrapper because the fields don't represent a form and they don't have any input. What am I doing wrong? Greetings, Martin1 point
-
Beautiful color contrasts and switching between them Responsive made with proportional resizing Pictures going out of focus into the background The first not irritating popups I have ever seen -- Einfach WoW --1 point
-
This looks absolutely brilliant! Congratulations for this great work and thanks for sharing it with us! I've also tried it on my phone and everything just worked ? One thing that was counter intuitive for me was the left arrow icon on the top left corner of the frontpage. On all other pages this icon means "back", on the frontpage there is no "back" of course, but I didn't realize that I was on the frontpage, so it might make sense to remove the icon there? Another thing: I wanted to share the app with a friend, but the share icon is only available on sub-pages.1 point
-
@Mikie, thanks for the report, fixed now in next version. In the meantime if you want this fixes, change line 31 in InputfieldSelectize.js from what it is now to this: $(".AdminThemeUikit .InputfieldSelectize select").removeClass('uk-select uk-form-small uk-form-large');1 point
-
1 point
-
Depends: you could provide such option, but don't really have to. FormBuilder, for an example, simply makes use of the wireMail() function, so you're automatically using an installed ("third party") WireMail module instead of the default one (if one can be found – and if multiple are installed then the first one found). When the WireMail module type was introduced all examples used this function, either directly sending messages using it, or instantiating a new WireMail object by calling it without arguments ("$mail = wireMail()"). Basically you should only ever use "new [WireMail class name]()" if you want to select a specific WireMail module instead of letting ProcessWire make that choice for you.1 point
-
You can upgrade every component in this new Mac Pro... it's basically a normal tower. Also, you could upgrade the CPU in the trashcan... it was just difficult (my friend runs a Mac business and has upgraded them hundreds of times).1 point
-
"Modular" is just a fancy word Apple used to say it's a normal tower design whereby the components can be upgraded and are not soldered in.1 point
-
I made a quick test to try the different options to get an instance of WireMail. Like https://processwire.com/api/ref/wire-mail/ tells us, there are three options: $m = $mail->new(); // option A $m = wireMail(); // option B $m = new WireMail(); // option C With WireMailMailGun installed, option A and B are going out with WireMailMailGun. Option C uses the native WireMail. So for anyone using WireMailMailGun and wanting to send mails outside of MailGun, new WireMail() is the way to go.1 point
-
1 point
-
If I'm being completely honest, I've never really had this need, and I don't think that I'd have much use for this feature. Then again It's clear that you've built much bigger – and much more complex – admin side features than I've ever even thought of, so it's no surprise that your needs are also somewhat different from mine. For me the admin is mostly for managing content, and when that content needs to be viewed by non-content-editors, I generally prefer to create my own views for it ? While I do understand your reasoning here, at the same time I think that what should be in the core are features that are commonly needed. Like Ryan, I'm not really sure that this as a very common need, and as such I think that it might be better to solve it with a module (at least for the time being). Personally I'd be slightly worried about the security of this feature if it was in the core: sure, Ryan has been great at covering all the bases when it comes to security, but making notable tweaks to the permission system is still a potential risk. I get that it's even more of a risk when you add it yourself, but when it's a third party module there's zero chance of it affecting anyone who doesn't specifically install it. I was actually going to suggest this – but then I re-read your post, and realised that you had already ruled it out ? In my opinion this doesn't don't seem like a very hacky thing. Hooking before page and fields can be saved and preventing seems like a proper solution to me. If you do that and also hide the "save" buttons (and prevent submitting ProcessPageEdit form in other ways), you'll be really close to what you're suggesting here.1 point
-
v0.2.1 released. This is a fairly major update in that there has been quite a bit of refactoring. Please be alert for and report any issues. ProcessWire >= v3.0.0 is now required. This release adds a new hookable HannaCodeDialog::buildForm() method that lets you build the dialog form in the hook rather than setting inputfield options as pseudo-attributes in the Hanna Code tag settings. From the readme... Build entire dialog form in a hook You can hook after HannaCodeDialog::buildForm to add inputfields to the dialog form. You can define options for the inputfields when you add them. Using a hook like this can be useful if you prefer to configure inputfield type/options/descriptions/notes in your IDE rather than as extra attributes in the Hanna tag settings. It's also useful if you want to use inputfield settings such as showIf. When you add the inputfields you must set both the name and the id of the inputfield to match the attribute name. You only need to set an inputfield value in the hook if you want to force the value - otherwise the current values from the tag are automatically applied. To use this hook you only have to define the essential attributes (the "fields" for the tag) in the Hanna Code settings and then all the other inputfield settings can be set in the hook. Example buildForm() hook The Hanna Code attributes defined for tag "meal" (a default value is defined for "vegetables"): vegetables=Carrot meat cooking_style comments The hook code in /site/ready.php: $wire->addHookAfter('HannaCodeDialog::buildForm', function(HookEvent $event) { // The Hanna tag that is being opened in the dialog $tag_name = $event->arguments(0); // Other arguments if you need them /* @var Page $edited_page */ $edited_page = $event->arguments(1); // The page open in Page Edit $current_attributes = $event->arguments(2); // The current attribute values $default_attributes = $event->arguments(3); // The default attribute values // The form rendered in the dialog /* @var InputfieldForm $form */ $form = $event->return; if($tag_name === 'meal') { $modules = $event->wire('modules'); /* @var InputfieldCheckboxes $f */ $f = $modules->InputfieldCheckboxes; $f->name = 'vegetables'; // Set name to match attribute $f->id = 'vegetables'; // Set id to match attribute $f->label = 'Vegetables'; $f->description = 'Please select some vegetables.'; $f->notes = "If you don't eat your vegetables you can't have any pudding."; $f->addOptions(['Carrot', 'Cabbage', 'Celery'], false); $form->add($f); /* @var InputfieldRadios $f */ $f = $modules->InputfieldRadios; $f->name = 'meat'; $f->id = 'meat'; $f->label = 'Meat'; $f->addOptions(['Pork', 'Beef', 'Chicken', 'Lamb'], false); $form->add($f); /* @var InputfieldSelect $f */ $f = $modules->InputfieldSelect; $f->name = 'cooking_style'; $f->id = 'cooking_style'; $f->label = 'How would you like it cooked?'; $f->addOptions(['Fried', 'Boiled', 'Baked'], false); $form->add($f); /* @var InputfieldText $f */ $f = $modules->InputfieldText; $f->name = 'comments'; $f->id = 'comments'; $f->label = 'Comments for the chef'; $f->showIf = 'cooking_style=Fried'; $form->add($f); } });1 point
-
You could just ask the template to give you all fields it does posses: $selector = "..." . $template->fields->implode("|", "name") . "*=$string"; If you can specify all field beforehand you could use FieldtypeCache and add all necessary fields to it. After that you can just search the cache field instead of all other fields.1 point
-
Yeah, I know. I guess the title of post isn't really accurate as at the time I didn't realize that removing it completely provides different behavior to having it unchecked. I guess I think the page-edit should not be affected by page-publish. Maybe there needs to be a page-edit-published as well to provide the scenario I am talking about. So you could check page-edit, page-edit-published and uncheck page-publish. Might be a better way to achieve this, but you get the idea.1 point