Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 06/08/2019 in all areas

  1. Short answer: ProcessWire differs from many other systems in that it doesn't really generate any markup, and as such there are not that many easy ways to tell that a site is running ProcessWire. This is intentional. Letting everyone know what system you're running is usually fine (and it's a nice hat tip towards that system), but potentially you might also be tipping malicious visitors off on how to best attack your site. With ProcessWire it's easy to go into "stealth mode", so that potential attackers have absolutely no idea what system they're currently targeting. As for builtwith.com, my initial guess would be that their algorithm primarily looks for the "generator" meta tag (or similar headers), or the text "Powered by ProcessWire". At least those seemed to be present on all the sites listed on their site under ProcessWire that I quickly browsed through. They may be looking for other indicators as well, but anything more than that can get a bit tedious. The site mentioned above, isit.pw, gathers a number of clues and then estimates the likelihood of a site being powered by ProcessWire. A lot of times (probably most) it gets its estimate right, but then again it is relatively easy to fool ?
    3 points
  2. With ProcessWire you don't generally want to perform your own SQL queries. It's possible, but generally I'd consider that a bad practice. If your content is stored as ProcessWire objects (basically Pages), you should always use the Selector engine for that sort of stuff. Not only does this provide the benefits of a great API (such as $pages->find('template=mailbox, owner=[some_user_field=whatever_value]') or $pages->get('parent=some-parent, name=page-name')->setAndSave('field', 'value')), there's also zero chance of accidentally running into nasty SQL injection vulnerabilities. Of course you can always create custom database tables and perform queries on them using the $database API variable (which is essentially a wrapper for PHP's own PDO class), but in such cases the content won't be editable within ProcessWire's admin, so you're missing a pretty important benefit there. Another alternative would be using RockFinder, which kind of provides the best of both worlds: easy to use syntax for queries combined with the performance of raw SQL and lightweight PHP arrays/objects. So, long story short: if you want a nice GUI and an easy-to-use API for managing your content, ProcessWire is a great choice. If you ultimately just want to use your custom database tables, write a few SQL clauses to update a few rows here and there, and there's no need for a web based interface for managing said items – then perhaps you should just build it from scratch (or use something like Laravel instead).
    3 points
  3. I've just commented on that old closed issue: https://github.com/ryancramerdesign/ProcessWire/issues/1868#issuecomment-500081534 Note that the change needs to happen in ListerPro, rather than the core (I think).
    2 points
  4. We had this discussion a few weeks/months back... could be interesting as well:
    2 points
  5. 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. Screenshots
    1 point
  6. Hello There Guys. I am in the process of getting into making my first modules for PW and i had a question for you PHP and PW gurus in here. I was wondering how i could use an external library, lets say TwitterOAuth in my PW module. Link to library https://twitteroauth.com/ Would the code below be correct or how would i go about this: <?PHP namespace ProcessWire; /* load the TwitterOAuth library from my Module folder */ require "twitteroauth/autoload.php"; use Abraham\TwitterOAuth\TwitterOAuth; class EyeTwitter extends WireData,TwitterOAuth implements Module { /* vars */ protected $twConnection; /* extend parent TwitterOAuth contructor $connection = new TwitterOAuth(CONSUMER_KEY, CONSUMER_SECRET, $access_token, $access_token_secret); */ public function myTwitterConnection ($consumer_key, $consumer_secret, $access_token, $access_token_secret) { /* save the connection for use later */ $this->twConnection = TwitterOAuth::__construct($consumer_key, $consumer_secret, $access_token, $access_token_secret); } } ?> Am i on the right trail here or i am barking up the wrong tree? I don´t need a complete solution, i just wonder if i am including the external library the right way. If not, then give me a few hint´s and i will figure it out. Thanks a bunch. /EyeDentify
    1 point
  7. I've now came up with this setup which works really well for me: /site/config.php (can safely be committed to GIT) <?php if(!defined("PROCESSWIRE")) die(); /*** SITE CONFIG *************************************************************************/ $config->debug = false; $config->prependTemplateFile = '_init.php'; $config->appendTemplateFile = '_main.php'; /*** INSTALLER CONFIG ********************************************************************/ $config->dbHost = 'localhost'; $config->dbPort = '3306'; $config->chmodDir = '0755'; // permission for directories created by ProcessWire $config->chmodFile = '0644'; // permission for files created by ProcessWire $config->timezone = 'Europe/Vienna'; // include config file from outside of the repo include('../config.php'); ../config.php DEV (one file for all laragon hosted sites on my local machine) <?php $config->dbUser = 'root'; $config->dbPass = ''; $config->httpHosts = [$_SERVER['HTTP_HOST']]; $config->debug = true; switch($_SERVER['SERVER_NAME']) { case 'www.XXX.test': $config->dbName = 'XXX'; $config->userAuthSalt = 'XXX'; $config->installed = 123456789; break; [...] } ../config.php LIVE (one file for each vhost) <?php $config->dbName = 'XXX'; $config->dbUser = 'XXX'; $config->dbPass = 'XXX'; $config->httpHosts = ['www.XXX.com']; $config->userAuthSalt = 'XXX'; $config->installed = 123456789; setlocale(LC_ALL,'en_US.UTF-8'); Thx for that ideas @arjen and @jens.martsch!
    1 point
  8. ... except if you're already checking with class_exists(), in which case it's just a tiny but unnecessary overhead ?
    1 point
  9. The only thing what may occure in very rare cases is, that another module in the same PW installation also uses the TwitterOAuth lib, stored in a different place. To avoid conflicts, one can add a conditional check before including it, using the PHP function class_exists(). <?PHP namespace ProcessWire; if(!class_exists("Abraham\TwitterOAuth\TwitterOAuth") { /* load the TwitterOAuth library from my Module folder */ require_once("./twitteroauth/autoload.php"); } use Abraham\TwitterOAuth\TwitterOAuth; Also one may prefer require_once() over require(), if there is a chance that the class / class file is loaded twice.
    1 point
  10. yep, took me about three hours from tracing to solution.. i thought an IDE like phpstorm would be at least sophisticated enough to inform me about these little suckers.. ? Lesson learned anyways. Nice weekend to everyone!
    1 point
  11. Your method seems fine to me. Something like Composer would be another option, but then you'd have to explain to your module's intended users how to use it, and expect them to have it installed, before they can get started with your module. Depending on the use case that may or may not be worth the hassle. In RedBeanPHP I've bundled the RedBean ORM into a module, and pretty much the only difference is that I'm loading the file and instantiating the class in the init() method – but even then I'm mainly doing it that way because I wanted to provide a config setting for selecting which version of the library to include.
    1 point
  12. It was closed on 10 Jun 2016, but it's still (or again) an issue (PW 3.0.132).
    1 point
  13. Have you made projects before with processwire api and sql queries ? Did you prototype your new project with processwire ? I don't know of any other cms that has a better api, so please give us some more details what your new project is about.
    1 point
  14. Hi all users of the croppable image 3 fieldtype. I'm currently working on the module, or better I'm reworking the module to support webp copys like the core image field does. Unfortunately this will break backwards compatibility! ? My questions are, how should we handle this? Until now the crop variation has this sort of names: basename.ext becomes basename.-suffix.ext But with the new version, it looks like regular image variation files with a -suffix: basename.ext becomes basename.100x200-suffix.ext My current thoughts are along that lines: I create a new named module: CroppableImage4, that supports the same API as the CAI3 version plus an alternative method like getCrop4("suffix"), and I add some checking, when the CAI3 is installed / active, it only hooks the plus method, not the regular one. What do you think? Any suggestions, ideas, wishes? And how can we savely update from CAI3 to CAI4, for example with existing websites containing tons of images ❓ PS: Besides that, the new module now supports individual $options as array or selector strings. It generates 0x48 thumbs and webp copies by auto generation and by manually creating a crop. It removes all variations on every changes: changing a single image, changing or removing settings. It has input fields in modules config for webpAdd and webpQuality, so you can handle it different from the $config->imageSizerSettings, and you now can add individual options with every API call, like with the core image field: $pageimage->getCrop("suffix", $options)->url, or $pageimage->getCrop("suffix", $options)->webp->url. And some more minor tweaks.
    1 point
  15. Just an idea... but there might be an event() in your .js that watches if someone clicks or touches outside the opened navigation container and therefore closes it. It's not that uncommon to take care of opened elements and to close them if there is an click/touch event somewhere else. As you use fancybox I looked for this feature and found this: // Clicked on the background (backdrop) element; // if you have not changed the layout, then most likely you need to use `clickSlide` option clickOutside: "close", There are more similar options, maybe someone can look into it and test it.
    1 point
  16. Ah, @ryan has added support for PNG8 to the Imagick engine, what wasn't before. He also asked me why this wasn't added and I was unsure if I simply forgot to add it. But now when I see this, I think I had tested it and removed it from the Imagick supported filetypes / subtypes, so that this images always were rendered by GD! until before the last Update. https://github.com/processwire/processwire/pull/141#issuecomment-495983196 So it seems it should be rolled back again, at least for PNG8. EDIT: I couldn't remember as it is (how many?) years ago as the Image Engine System was introduced. And yep, it would have been better to add some comments. ;-)
    1 point
  17. I ran into issues with a slow server using this method, where wireHttp would already resolve a result while RestApi was still running. So with help from my co-worker @harmvandeven we came up with a more stable version, with some more redundancy: <?php /* api.php, a simple PW template to fill the gap between the RestApi and ProCache modules v2 @author: @eelkenet, with help from @harmvandeven & @ryan 1. Create a template called 'api' and set it up using the following settings: - Allow URL segments - Allow guests to view the page - Set the Content-Type to application/json - Make sure to NOT Prepend or Append any files 2. Add a page using this template and allow ProCache to run its magic */ $timeout = 600; $maxAttempts = 10; // Pre-check for unwanted symbols if (strpos($input->urlSegmentStr(), '.') !== false) { throw new Wire404Exception(); } // Build request URL $endpoint = $modules->get("RestApi")->endpoint; $url = $input->scheme() . "://" . $config->httpHost . "/" . $endpoint ."/" . $input->urlSegmentStr(); $http = new WireHttp(); // Set a high timeout, to deal with a slow server $http->setTimeout($timeout); // Get the HTTP status of the page, to make sure it exists in the first place $status = $http->status($url); // If the page exists, or possibly redirects to valid content if ($status >= 200 && $status < 400) { $result = false; $attempt = 0; // If the result isn't a string, something went wrong while(gettype($result) !== "string" && $attempt++ < $maxAttempts) { $result = $http->get($url); if ($attempt > 1) wire()->log->message("Loading content at $url, attempt $attempt: " . gettype($result)); } // Double check if the data is a string.. if (gettype($result) === "string"){ // .. And check if it can be decoded, if so: return the data and thus cache it if (json_decode($result) !== NULL) return $result; // If it cannot be decoded: throw exception (don't cache it) throw new WireException("Found the data at $url, but it could not be decoded. Please check your API output!"); } // Throw exception if data could not be loaded in time (don't cache it) throw new WireException("Found the data at $url, but could not load it in time, after $attempt attempts. Result has type: " . gettype($result)); } // Throw generic exception if the requested page was not found or there was another error throw new WireException("Failed to load the content at: $url, with HTTP status: " . $status);
    1 point
  18. Maybe OT: I have been thinking of using Dart or TypeScript to write my JS for me ?. Vanilla JS can be a pain at times. Using Dart or TypeScript, I can write in familiar OOP style (yes, I know about ES6, but that's another story) and have them transpile the code into JS. For small projects it's probably not worth the hassle, but the strongly typed nature of Dart or TypeScript alone is compelling reason enough to steer away from vanilla JS if I can. OK, I'll now crawl back under my rock...?
    1 point
  19. Imho the much more compelling reasoning against using jQuery is going up the abstraction ladder and using some library, which handles e.g. DOM manipulation for you and not going down the ladder to do everything in vanilla js. jQuery for one part is a great library if you really want to manually handle changing the DOM, but I much rather deal with templates and data then with the low level "making the DOM behave". What I never really liked is how ajax was bundled with jquery, as it really has nothing to do with the DOM at all. At the time it might have been about "we make things simply work cross-browser", but it could've been packaged more separately.
    1 point
  20. Why I'm still using jQuery in 2019
    1 point
  21. Nice site, the only issue I came across is scrolling over the map is impossible with the mouse (the map gets zoomed instead).
    1 point
  22. ANOTHER UPDATE SnipWires Taxes (VAT) configurator is ready! I added a new custom Fieldtype FieldtypeSnipWireTaxSelector based on an idea of @BitPoet - thanks for that! Also I created a full featured repeater for module config editor including drag&drop handling. Have a look at the animated GIF below. The taxes you configure here will be available as select option list in product page editor. The first tax in the configured list will be used a s the default tax in the custom field.
    1 point
  23. It's possible, but not as simple as it should be because it seems that the option() method of Datepicker (and Timepicker) is not working for the stepMinute option. Instead it seems you have to destroy and re-init the datepicker if you change stepMinute. In some custom admin JS, for a field named "date"... // For a Datetime field named "date" with time enabled $('#Inputfield_date').on('focus', function() { // Get the existing options for the Datetimepicker var options = $(this).datetimepicker('option', 'all'); // If the picker has the default stepMinute setting... if(options.stepMinute === 1) { // Set custom stepMinute setting options.stepMinute = 15; // Destroy picker $(this).datetimepicker('destroy'); // Re-initialise picker $(this).datetimepicker(options); } });
    1 point
  24. See how PW determines $config->ajax here. So you may need to set the X-Requested-With header:
    1 point
  25. if($config->ajax) { header('Content-Type: application/json'); echo $json; $this->halt(); // like die(); } else throw new Wire404Exception();
    1 point
  26. Well, well, well. I don't even know where to start. Speed is a big factor, and you should always strive to optimize for it. People on spotty, slow mobile networks might beg to differ with your opinion. And Google too. In case of a typical single page website, you could at least implement some sort of lazy loading technique, which would at least optimize the perceived loading time. Also, run Google Chrome's Lighthouse speed audit, and you'll spot some strange problems there related to the site's images.
    1 point
  27. One image is actually indexed... ? There are a few things you might want to change or at least take a closer look at. use only https:// and redirect to it choose prefered domain (see below) reduce page size drastically (~13MB is too large) and speed it up remove the preloader as it stays for hours fix your sitemap (as mentioned by @dragan) set up Google Search Console to figure out problems with your site add robots.txt (as mentioned above) and reference your sitemap and maybe add a nice favicon.ico Your site is available through 4 different addresses: http://lobo-taberna.de/ http://www.lobo-taberna.de/ https://lobo-taberna.de/ https://www.lobo-taberna.de/ Choose one. ? Reduce page size to ... way less than that.
    1 point
  28. There are two possible options to fit / contain images into a predefined rectangle / square: With the bare core options, you need to pass your width / height and an additonal setting for cropping = false. (the distribution default is true!) $containedImage = $page->original_uploaded_image->size(500, 500, array("cropping" => false)); If you find this to abstract or clumpsy, you may use the beautyful Pia, which reduces this to $containedImage = $page->original_uploaded_image->contain("square=500"); Optionally / additionally interesting in this regard maybe the weighten option of Pia here. ------ But both options only help in rendering images that fit into your defined boundaries. They will work with appropriate markup and css styles applied to them, but they do not apply a canvas to the image files. If you really want to increase the images filesizes for that, by adding pixels and not use css styles, you can use the ImageManipulators canvas method. It does exactly that. When using the Imagemanipulator with a recent PW version, please pay attention to use $image->pim2load()->...! the API examples all show the method for PW version prior to 2.6 ------ Examples with Pia and IM: $square = $page->original_uploaded_image->contain("square=500, quality=100")->pim2load("squarecanvas")->canvas(500, 500, array(255,255,255))->pimSave(); // or $bgColor = array(255,255,255); $suffix = "squarecanvas"; $innerSize = 480; $outersize = 500; $square = $page->original_uploaded_image->contain("square=$innerSize, quality=100")->pim2load($suffix)->canvas($outersize, $outersize, $bgColor)->pimSave(); // or $bgColor = array(255,255,255); $suffix = "squarecanvas"; $oneSizeFitsAll = 500; $square = $page->original_uploaded_image->contain("square=$oneSizeFitsAll, weighten=1, quality=100")->pim2load($suffix)->canvas($oneSizeFitsAll, $oneSizeFitsAll, $bgColor)->pimSave();
    1 point
  29. Thanks @monchu and @Robin S - I have checked here and also see the problem based on deleting the default Find Lister. I have posted a Github issue: https://github.com/ryancramerdesign/ProcessWire/issues/1868
    1 point
  30. I had this problem, and I believe it's caused by deleting the default lister (aka "Find"), which is something that becomes possible when Lister Pro is installed. If you have done this the solution is to create a new lister called "Lister". Because the default lister is used by the core it would be better if Lister Pro did not allow you to delete it, but instead made it simple to disable it for non-superuser roles. If you have other Lister Pro instances and you don't want certain roles to see the default lister you have to set up a special permission for the default lister and then not apply it to a role. There's definitely scope to make this process a bit clearer and easier for Lister Pro users.
    1 point
  31. 404 pages serve an important purpose from an SEO standpoint. So if this is a public facing site, I'd recommend maintaining a proper 404 page rather than just redirecting to or displaying the homepage. You could always have your 404 page link to your homepage or even meta redirect to it after a few seconds.
    1 point
×
×
  • Create New...