Leaderboard
Popular Content
Showing content with the highest reputation on 10/01/2016 in all areas
-
This is the first time that I'm going to post anything under the showcase forum, although I have a few ProcessWire powered websites under my belt. This one is special because I think the use case is somewhat unique. Caltex Loyalty Club - initial the situation Caltex Loyalty Club is a customer loyalty and rewards program of Caltex Palawan aimed to provide exciting promos and incentives their customers' continuous patronage. Caltex Palawan originally bought their system from a large software company that also provides card-based solutions. The previous system consist of the following: two high-end Dell servers that are located in two separate Caltex' offices traditional EFTPOS devices for reading loyalty cards MIfare RFID cards as loyalty cards Running within one of the Dell servers was a crude and barely usable loyalty/rewards manager application that runs the whole thing. Here's what I mean: You're free to imagine what the rest of the application looks like. The other dell server acts as a VPN server through which all the EFTPOS devices and the application server connect to. To cut the long story short, this setup was running smoothly for a total of 3 weeks before problems started popping up, mostly because VPN server did not have a static IP address and the EFTPOS devices could not connect. The developers refused to provide service to the system because Caltex Palawan does not want to shoulder the travel and boarding expenses of the developers (since it was just working 3 weeks). We were called in at this point (we being a local tech solutions provider in Puerto Princesa), and we made the VPN server work, but other problems soon surfaced. The whole system was barely working for about 3 years when they finally decided they were fed up with the customer complaints they keep getting everyday. Our Solution We studied the existing system for quite some time to examine where the problems we're coming from. The most obvious one we found was that because the servers were located inside Caltex Palawan's offices, the servers were prone to downtimes caused by power outages and internet connectivity problems. It was obvious that the better way would be a web-based solution that would always be online. We also wanted to replace the bulky and outdated EFTPOS devices with android based NFC device that are more portable, and easier to work with. We retained the cards that originally came with the system since there are thousands left unused, but eventually replaced them with NTAG stickers, and newer cards. To sum it up: A web-based application to manage the loyalty / rewards system Android based NFC device to read the loyalty cards NTAG stickers to act as loyalty cards ProcessWire to the Rescue Having used ProcessWire before, it was our best choice, after considering using Laravel, and other frameworks, because of ProcessWire's key strengths: all custom fields - no unnecessary bloat powerful api scalability Although this straight up looks like it's been lifted from processwire.com's front page, but this really is the case, and these are all we need from a web-application framework to do almost anything! All custom fields Since we are working with a unique dataset, it's impossible for us to find anything out there that would have anything even remotely close to what we need. In the beginning we were planning to use custom database tables that we would deploy alongside ProcessWire. I even posted one time in the forum, asking if there's any way to integrate an ORM library with ProcessWire, and the answer I got was that it would be redundant, and almost surely unnecessary. And this turned out exactly the case! When we designed our database (using ERDs), we we're delighted at how closely we were able to replicate our relational design using templates, fields, and pages. This is mainly due to FieldtypePage. We were able to create meaningful relationships within our templates. We ended up with ~60 templates and ~70 fields. Powerful API About 70% of our code are API calls. The rest are just control structures and simple computations. That's how powerful the ProcessWire API is. So powerful that we did not even need to write a single sql query to complete the whole project. We needed to handle user login, API has it. Session handling, API has it. Selecting and manipulating huge amount of interrelated data, the API has it! Scalability At the onset of the project, the existing CLC program already has some 20 thousand members with hundreds of thousands of transactions. Right now, our current system has around 500,000 pages and counting and were not experiencing any slowdown. How we used ProcessWire The first thing that we decided that our client would not be able to see the processwire admin page. We wanted to present them with a simplified UI that does not present them with anything they don't need. We created a whole frontend UI for the client to use. We had custom forms for all the pages that they can create, and all the actions that they can do. We, on the otherhand, use the admin backend thoroughly in continuously developing, and supporting the system. What the clients see vs what we see: Our setup ProcessWire 2.8 running on a LEMP stack DigitalOcean droplet AjentiV VPS manager Modules we used We used a very minimal amount of modules for the project: ImportPagesCSV - to import the data migrated from the old system FieldtypeDecimal - for all our decimal values Modified RestHelper - from clsource for all the communication between ProcessWire and our android POS app Modified PagesSum from esrch ProcessSelectorTest - for quickly checking some selections Things we had to do on our own Frontend user login Frontend password recovery Fine-grained permission handling for users Cron jobs for scheduled tasks. The rest are API calls, and business logic. The Result Our Caltex Loyalty Club web application is now running on its sixth month without so much as a hiccup! Compared to the previous system that was averaging 200 transactions per day, we are now getting 800 and it's growing. We are running 10 campaigns and promos simultaneously across 18 Caltex Stations all over Palawan, with 30 android NFC terminals communicating to a single ProcessWire installation. We are very happy with ProcessWire in terms of performance, ease of use, and most importantly it's simple and yet very powerful functionality as a web-application framework even though it doesn't primarily market itself as one. PS. Also one of the best things we experienced while doing this project is the awesome, unparalleled community support. Throughout the project, although we had a lot of moments when we just couldn't figure out what to do, never once did we have to ask a question in the forum. A quick search here and there, and someone already helped someone else that faced the same problem we were having. It's almost as if people are being paid to diligently answer all the questions! We most of the time just had to like an answer that was already there! Screenshots and photos Android POS terminals and CSR training17 points
-
Last week we called it a soft launch, but this week we'll say ProcessWire 3 is now released and considered our new master, version 3.0.35. This post is a changelog of sorts, where we will cover all that's new in ProcessWire 3! https://processwire.com/blog/posts/pw3-changelog/10 points
-
You'll probably need to log out - that module only checks for new PW versions when logging in: https://github.com/ryancramerdesign/ProcessWireUpgrade/issues/103 points
-
Finally figured it out (faceplam moment): a browser extension was messing with CKEditor inline mode and preventing it from saving. There were no errors because the browser extension was not passing it the content I was entering, it was just making it look like it. For the record, the browser extension is Grammarly. I should feel wiser for figuring this out, somehow I don't Thanks to everyone for your help with this!3 points
-
Just to confirm - you can use CKEditor in normal "Regular Editor" mode, and it's only if you change to "Inline Editor" mode that a problem occurs? I just tried CKEditor in inline mode in a fresh install of PW 3.0.35 and it worked normally so I think it must be something specific to your environment rather than a PW bug.3 points
-
True happiness!! And today Vue 2.0 was released too, Destiny are you trying to tell me something?! Thanks everyone for the amazing work, I keep enjoying developing with PW like in no other system.3 points
-
Redgate is giving out non commercial licenses for its MySQL Compare and MySQL Data Compare tool. I've used their SQL Server Compare tools and the ToolBelt extensively many years ago, and it saved my back side time and time again. I only happen to come across it because I was looking out for a MySQL Compare tool to work out the difference between my Test & Live Servers. The unfortunate caveat is that it only runs on Windows ...... perhaps it will still be of use to someone. I will try running it on Parallels and see if it can access a MySQL Instance running on the OS X Parent .... http://www.red-gate.com/products/mysql/mysql-comparison-bundle/2 points
-
Ah! Found the exclusions array! $config->fileCompilerOptions('exclusions', [ str_replace('\\', '/', __DIR__ . '/modules/ProcessJumplinks/vendor/illuminate/support/helpers.php'), ]);2 points
-
Thanks for the info! I will take a look. I'm also a Parallels user which I normally use for IE/Edge testing purposes only. For those interested, I succesfully use SquidMan to connect to my MAMP Pro's server on my Mac from the Parallels virtual machine and/or from other (mobile) devices on my network (actually, all requests will be routed through SquidMan): Set up a permanent local IP for your local dev computer, for instance 192.168.1.10 or take a note of the one assigned to it by DHCP. Open SquidMan and access the application preferences: - In the "General" tab under "HTTP port" enter "8080" - Next, in the "Clients" tab enter a range of allowed devices. - example: 192.168.1.0/24 and/or 192.168.0.0/24 etc... - In the "Template" tab, comment out "http_access deny to_localhost", like this: # protect web apps running on the proxy host from external users # http_access deny to_localhost - Save changes. Launch your web server and SquidMan.app. Your local web sites are now open to visitors. On a Mac you'll need to adjust your network settings to use this proxy for HTTP traffic: - Open the System Preferences panel, click the Network icon. - Create a new 'Location' that uses the Squid proxy. - Set the HTTP proxy to be "localhost", port "8080" and turn on "Web proxy (HTTP)" on the "Proxies" tab. - Next click on "Apply Now". On your Parallels virtual machine / remote (mobile) device connected to your local network you also need to use the proxy: - Go to your network settings. - Optionally, if it is possible to use profiles: create a new Profile that uses the Squid proxy. - Set the HTTP proxy to be your local dev machine's IP with port "8080". For the Parallels virtual machine set networking to "Bridged Network".2 points
-
It's a very important fix though - I wouldn't want to break anyone's non ML site if they upgraded to the latest version of this module, so very glad you reported this.2 points
-
This is resolved now. It was a problem with the underlying repeater, not the CroppableImage3 field in it. I had earlier used the API to migrate a new field into the template used by the repeater but forgot to reflect the change in the field data (specifically, the repeaterFields settings on the field.) Now I have the repeater and its template in sync, all works well.2 points
-
I have it in a site/ready.php (if you don't have this file just create one) function bot_detected() { if (isset($_SERVER['HTTP_USER_AGENT']) && preg_match('/bot|crawl|slurp|spider/i', $_SERVER['HTTP_USER_AGENT'])) { return TRUE; } else { return FALSE; } } if($session->get('visit_counter_flag') === 0 && !$user->isSuperuser()) { if (bot_detected()) return; /* if the user is NOT logged in and not counted */ /* turn of output formating so PW do not give an error when we change the value */ $page->of(false); /* save the visitor_counter field */ $page->set('visitCounter', ($page->visitCounter ?? 0) + 1); $page->save('visitCounter', array('quiet' => true, 'uncacheAll' => false, 'resetTrackChanges' => false)); /* turn on output formating so PW work as it should */ $page->of(true); /* set a visit counter flag to 1 so next load do not count */ $session->set('visit_counter_flag', 1); } As a extra bonus this script exludes bots from statistics.2 points
-
Superb work and so great many improvements. While I read all the blog posts I can't even remember them all, like the multi language improvements. Thanks Ryan (and the rest of the team) for the great work.2 points
-
I have a Page field with no restrictions on selection, set to use Page Autocomplete. Administrators need to be able to select the home page just like any other. When they type "Home" into the field, the home page appears as an option, but when it is selected, nothing happens. There aren't any javascript errors, and other pages can be added as expected. I do notice in the AJAX call to get the menu results there is a query param "id>0" but "Home" does appear in the list, it just can't be selected. Page Autocomplete is the only practical UI option due to the large (over 6k and growing) number of pages in the site. Has anyone else seen this behavior? Is this a bug or am I missing something in the configuration? This is on PW 2.7.3.1 point
-
Hi all... I would like to add some special javascripts files to a Inputfield if certain conditions are fullfilled. Thats working good with hook Inputfield::___render when the field is directly loaded on ProcessPageEdit. However I have problems adding these scripts when the Inputfield is not loaded directly on pageLoad. In my case a dynamically loaded repeaterItem. I found the Inputfield::renderReady method wich seems to be the best place, but it´s not hookable? ( https://github.com/processwire/processwire/blob/master/wire/core/Inputfield.php#L1030 ) ( the call in Repeater: https://github.com/processwire/processwire/blob/master/wire/modules/Fieldtype/FieldtypeRepeater/InputfieldRepeater.module#L204 ) Is there an "official" way of doing that? Of course I could hook in somewhere else, but that renderReady would be the place to go or am i wrong? Thanks for any information... Tom1 point
-
// This might work... $page->set('visitCounter', ((int) $page->visitCounter) + 1); // If not, try this... $page->set('visitCounter', (($page->visitCounter) ? ($page->visitCounter) :0) +1); // Personally, I don't like this style of code - I see too many smileys in there.1 point
-
@fbg13 Could you make it so that the edit page is only provided to superusers and maybe users with a certain role such as 'file-editor'? This would allow people like Sephiroth to use your module while keeping other users well away from the files.1 point
-
The ?? is new to php 7 http://lornajane.net/posts/2015/new-in-php-7-null-coalesce-operator1 point
-
Perhaps they handle this manually by a customer rep so you may need to wait until Monday / Tuesday. Mine was a guy by the name of Jordan Miller and gmail treated it like a promo e-mail so it was nowhere to be seen initially.1 point
-
Sorry Mike - looks like it was an issue with a recent change to the Tracy core. I have restored the core to an earlier commit and pushed a new version here which fixes the AJAX bar.1 point
-
I think they send you an e-mail with a registration Key. I too was waiting for the e-mail but I think a customer rep sends it sans Redgate labelling which is why you might not see notice it in your inbox.1 point
-
Have you had a look at this @szabesz? https://forum.parallels.com/threads/accessing-mysql-mac-from-windows.105647/ If I recall correctly, I think I had a similar situation with SQL Server where the version (32/64) of the client driver had to match the Server.1 point
-
Hi Adrian, I upgraded to 3.3.3 this morning, and noticed that the debug bar is no longer adding rows for AJAX requests, which I need to measure. Any idea what may have broken this? Using PW3. Thanks1 point
-
This looks awesome, well I don't think we should limited to 1 Module, different modules might have things that don't appeal to you, with that being said, This will benefit me because I am behind a Firewall at the office, so it's hard to FTP in my site.1 point
-
Thanks Adrien, "Undefined index: HTTP_MOD_REWRITE" is gone with even in "CGI mode". About CGI mode with MAMP Pro: in v3.3.2 I used to get: non CGI mode: mod_rewrite: 1, mod_security: CGI mode: "Undefined index: HTTP_MOD_REWRITE"... now in v3.3.3: non CGI mode: mod_rewrite: 1, mod_security: *confirmed off CGI mode: mod_rewrite: , mod_security So it does detect them properly when not in CGI mode, but just as you have noted they cannot be confirmed otherwise. It might be a good idea to use a short phrase, something like "probably not installed". What do you think? Also, the status of mod_rewrite seems to be uncertain too. BTW, is it possible to have the Inputfield Fieldsets be closed by default? I keep getting lost when all of them are open, and they are always open even after saving the settings.1 point
-
I think I know what I did here. I think 1 of the first modules I wrote was a standalone module that needed access to the API. Also happened to be the first module I wrote that accessed the API. So because it worked, I just assumed it was the correct way of calling the API without actually realising what I was doing. Should pay attention more to the documentation, but I guess it's sometimes hard when you're on super tight deadlines, reading/skimming so much material and working with new technologies you haven't got a clue about or lean on mentors for advice and validation.1 point
-
That's the issue. You cannot bootstrap pw, when it's already running. Also starting the pw instance again would be a waist of computation anyways. <?php namespace Site; $config = \ProcessWire\wire('config'); [your defines]1 point
-
No sorry needed After reading ' multi-language support', I had the feeling the problem was somewhere there, just wanted to notify you about this....1 point
-
1 point
-
That makes sense for sure with echo wire(config)->paths->templates; it should be: echo wire('config')->paths->templates; Not sure why you would get the undefined constant with the $config version though.1 point
-
Yeah I think that's the most clean approach currently, even though I'm still not sure about the consequences, like your concerns above. In the end it comes down to the fact, that people are more often supposed to work with composer, which might not be a bad thing, but still a barrier to entry.1 point
-
Yes, it works with pw3. Just updated module info and added textarea field.1 point
-
Hi, I got an error Error: Call to a member function get() on a non-object (line 346 of DIR_\site\assets\cache\FileCompiler\site\modules\ProcessCustomUploadNames\ProcessCustomUploadNames.module) After installing 'language support' it works... Grtz1 point
-
When you see all the new features listed together and consider the short amount of time this has happened in it's really impressive. Thank you Ryan, and thanks also to the other contributors to the PW core.1 point
-
@Fantomas, welcome to the PW forums! I found your post difficult to follow because of the page names you have used in your example. It would be easier to grasp what you're trying to do if you use demo names that can have some meaningful relation, e.g. "Cars", "Model", "Colour", etc. The thing you're asking about is not the basic inputfield dependency feature that this thread introduces, but is actually a feature of Page inputfields. The trouble is that the feature is not formally documented anywhere (grumble, grumble) - it just pops up in forum discussion - so it's difficult to know exactly what is and isn't possible in terms of this feature. As I understand it, the feature only works in the "Custom selector to find selectable pages" (not in "Custom PHP code to find selectable pages") and the reference can only be to another Page field that is in the page being edited. If you're wanting to reference the value of a Page field on a different page then you can do this with FieldtypeReference (and maybe RuntimeMarkup also, not sure).1 point
-
Thanks @szabesz - it should be fixed in the latest version. I also added a "*confirmed false" to the mod_security entry when we know it's definitely disabled. I am pretty sure this should be accurate, but would be keen to hear reports from you guys about this. If it doesn't have this "*confirmed false" text, and it is reported to be Off, we can't be certain because it's a sign that PHP is in PHP-FPM (CGI) mode and we may not be able to detect it. As far as I can tell if it reports it as On, then I think we can be certain of this no matter what mode PHP is in.1 point
-
I can confirm the behaviour in PW3. I think it's a bug - will you raise a GitHub issue for this?1 point
-
I was stunned because you had the answer in your question (literally) so I was expecting further trickeries1 point
-
1 point
-
First off, a big thanks to Jonathan Lahijani and Benjamin Milde for taking over the last two weeks of blog posts while I was traveling. They did an awesome job. If you haven't yet read Jonathan's CMS Critic case study or Benjamin's Migrations module introduction, be sure to check them out. This week we started using our new GitHub organization repository to soft launch version 3.0. ProcessWire 3.0 now appears on packagist as well (installable via Composer). We’ve got several other updates for you as well! https://processwire.com/blog/posts/hello-pw3/1 point
-
Speaking of bad bot blockers, I've had great success with Jeff Starr's robust "6G Firewall" for Apache: https://perishablepress.com/6g/1 point
-
1 point
-
As soon as one is using essentially any external php library you've to deal with namespaces and it's really not that complicated after some time using them. At least from my experience.1 point
-
Hi kongondo, Thanks for the quick reply and the welcome. I had actually already read the topic that you mention, and this is what prompted my need: I would like to save a "stock" field for each product, but this field would have to be calculated each time a stock movement is saved, and calculating this field is precisely what takes so much time. In the meantime, I continued looking into the problem, and I think that I came up with a solution with the following module: class PagesSum extends WireData implements Module { public static function getModuleInfo() { return array( 'title' => 'Pages Sum', 'version' => 1, 'summary' => 'Adds a $pages->sum($selectorString, $fieldName) function to sum the value of a specific field over a list of pages selected by a selector string.', 'singular' => true, 'autoload' => true ); } public function init() { $this->addHook('Pages::sum', $this, 'sum'); } public function sum($event) { $selectorString = $event->arguments(0); $fieldName = $event->arguments(1); // Find all the pages associated with the selector string $pageFinder = new PageFinder(); $idQuery = $pageFinder->findIDs(new Selectors($selectorString), array('returnQuery' => true)); $idQuery->set('orderby', array()); $idQuery->set('groupby', array()); $idQuery->set('limit', array()); $stmt = $idQuery->execute(); $idArray = $stmt->fetchAll(PDO::FETCH_COLUMN); // If no pages were found, return 0 if (count($idArray) == 0) { $event->return = 0; return; } $idString = implode(',', $idArray); // Get the table name for the given field name $field = $this->fields->get($fieldName); // If no field with this name is found, return 0; if (!$field) { $event->return = 0; return; } $tableName = $field->getTable(); // Run the SUM query $sumQuery = new DatabaseQuerySelect(); $sumQuery->select("SUM(data)"); $sumQuery->from($tableName); $sumQuery->where("pages_id IN ($idString)"); $stmt2 = $sumQuery->execute(); list($total) = $stmt2->fetch(PDO::FETCH_NUM); $event->return = $total; } } In my tests, it is about 60 times quicker to calculate the sum with the function $pages->sum($selectorString, $fieldName) than looping over the pages (for about 12000 pages). I would appreciate any feedback, in case there are any other optimizations to be achieved, or any errors I haven't thought about. And I hope that this might maybe be useful to others too!1 point
-
My brother has some Audio Technica ones and I like them. I haven't used them next to others, so don't have a good comparison, but I did find them very comfortable and with very nice sound. I personally use Grado SR-80s and Vmoda Crossfade LP. I'm mixed on the Grado headphones... they sound great, supposedly excellent, but I think for someone else's preferences. I love the sound of the Vmoda headphones though. They are heavy on the bass and soundstage for sure, but in a way that's real / you can feel, like you are in a movie theater... makes me forget I'm wearing headphones. Honestly though the best value I've seen for headphones is with these Panasonic earbuds. Both my wife and I use them to replace our mobile phone earbuds, and the incredible sound that comes out of those $8 earbuds is hard to believe.1 point
-
When I need a calculated field that will be used for sorting, I like to add a hidden (or regular, doesn't matter) field to the template to store the calculated value. The value gets automatically calculated on page save. A hook like this in your /site/templates/admin.php can do the work for you: $pages->addHook('saveReady', function($event) { $pages = $event->object; $page = $event->arguments(0); if($page->template == 'rider') { $miles = 0; foreach($page->rides as $ride) { $miles += $ride->miles; } $page->miles_ridden = $miles; } }); Then when it comes to sorting, you just sort on your calculated field: miles_ridden. If you are adding this to an existing PW installation, then you'd need to establish the initial values for each rider's miles_ridden. This could be done with a quick bootstrapped script: /setup-riders.php <pre><?php include("./index.php"); foreach(wire("pages")->find("template=rider") as $rider) { $rider->save(); echo "$rider->name: $rider->miles_ridden miles ridden\n"; } Then you'd just load domain.com/setup-riders.php in your web browser, and then delete the file when done.1 point