Search the Community
Showing results for 'runtime'.
-
Building your very own custom Fieldtypes in ProcessWire seems to be hard, but it actually is not, once you get the concept. In this post I'll share a simple and as minimalistic module as it can get that everybody can use as a boilerplate for his own Fieldtypes. A Fieldtype that does not store any information in the database A Fieldtype that stores information in the database (to be done) Make your Fieldtype configurable 1. A Fieldtype that does not store any information in the database Some of you might know the excellent RuntimeMarkup module by @kongondo. I've used it a lot in the past, but I get more and more into developing custom fieldtypes rather than hacking the runtime module to my needs. That has several advantages, but it has also one major drawback: It is always a pain to setup a new Fieldtype, because there are lots of methods (see the base class /wire/core/Fieldtype.php) and you have to know which methods you need, which ones you have to remove and adopt etc.; Not any more! Ryan has developed a showcase module (the Events Fieldtype) to learn from, but when I first peaked into it, it felt quite complex and I thought it would be a lot of effort to learn Fieldtype development). There are also some easy and small Fieldtypes to learn from, like the FieldtypeCheckbox. But all of them require a good understanding of what is going on, you need to modify existing config inputfields that might have been added to that fieldtype and afterall it's not as easy as it could be. With my new approach I plan to use a boilerplate fieldtype to start from (in OOP terms to "extend" from) and only change the parts i need... More on that later. Here is the boilerplate module with some debugging info to illustrate the internal flow on the tracy console: See the module in action in the tracy console ( @adrian has done such an amazing job with that module!!!): The code should be self-explaining. What is interesting, though, is that after the ### getUnformatted ### dump there is only one call to "___formatValue". All the other calls (loadPageField, wakeupValue and sanitizeValue) are not executed because the value is already stored in memory. Only the formatting part was not done at that point. With that concept it is very easy to create your very own custom Fieldtypes: <?php namespace ProcessWire; /** * Demo Fieldtype Extending the Boilerplate Runtime Fieldtype * * @author Bernhard Baumrock, 03.10.2018 * @license Licensed under MIT * @link https://www.baumrock.com */ class FieldtypeDemo extends FieldtypeMarkup { public static function getModuleInfo() { return [ 'title' => 'Demo', 'version' => '0.0.1', 'summary' => 'Demo Fieldtype', 'icon' => 'code', ]; } /** * convert the wakeupValue to the given format * eg: convert a page object to a string */ public function ___formatValue(Page $page, Field $field, $value) { $value = parent::___formatValue($page, $field, $value) . " - but even better!"; d($value, '___formatValue --> convert to whatever format you need'); return $value; } } Notice the change "but even better" in the last two dumps. I think it can't get any easier, can it?! ? I'll continue testing and improving this module, so any comments are welcome! 2. A Fieldtype that stores information in the database See this module for an easy example of how to extend FieldtypeText:
- 17 replies
-
- 19
-
-
I also brought this up before as a wishlist request UX improvements · Issue #392 · processwire/processwire-requests (github.com), because I use these features of AoS in EVERY PW instance. But there are also always voices against integrating useful things into the core, to keep it "lean". For example integrating migrations into the core, which I see as crucial, but others say that migrations are not needed for everyone, and so they should stay out of the core. One feature might be useful for one person, but not for the others, so I am always in favor of "providing options" (turning features on or off). I'm also at a point where I find the admin or UIkit theme stale and not really functional. There are a lot of things missing for me. Reactivity like vue.js or alpinejs or react offer. Better usability of dropdowns in the main menu and other things, but I digress. Several times I started to develop a new admin theme based on vuejs, but also noticed how complicated for example the pagetree is built and moreover I lacked the time. Furthermore, with such a big undertaking, it's also always a question of how many people would really use it, or if I (or WE) are just developing it for fun. Because I don't want to develop anything for &>/dev/null. Back to AdminOnSteroids: Right now it's not modular and uses jQuery under the hood. It's not a bad thing because the PW core also relies on jQuery, but would rather suggest a rewrite here where every feature is a javascript module. These modules could be loaded on demand (conditionally based if a specific DOM element exists or not) at runtime. This keeps the core lean, and also the javascript load and execution time and memory consumption low. Maybe such an update (or the integration into the core) could be developed by crowdfunding. I am also in favor of ditching support for Default or Reno theme, because I think that most people would use AdminThemeUikit, but I might be wrong? Upgrading the PHP part, would not be that difficult, if we drop support for PHP versions < 8.
-
@Ivan Gretskygreat news. I contributed to the module many years ago with leaflet providers and marker cluster integration. It definitely needs some attention and love. Upgrading assets etc. I think that leaflet.js in general is still a viable solution for open source maps in general. Mapbox have changed their subscription model few years ago that is why I still prefer Leaflet over Mapbox. As for geocoding addresses this is still an issue with the open source provider that sits behind InputfieldLeafletMapMarker (Nominatim). They have improved a lot over time. But still failing on more exotic addresses where the Google Maps geocoder is doing a better job. There's quite a few open source geocoding services out there, but most of them use data from OSM's Nominatim. So you can't expect better results than you get with Nominatim. If looking for closed source geocoding APIs, one that might be worth looking into is https://positionstack.com/ . They have a free tier and seem to have a huge address pool. And I'd rather trust my data with an Austrian Company then sending it to Google. Just sayin... It could be used a s a fallback in case Nominatim returns garbage or nothing. It is not. At least with v3.0.3 of InputfieldLeafletMapMarker. You can make seperate inputfields that hold address data work together with the InputfieldLeafletMapMarker. I once wrote a module for a specific use case where I have 3 inputfields, address, postcode, city. The module loads some JS that first hides the default InputfieldLeafletMapMarker inputs, adds a button which takes the values from those fields, geocodes them through Nominatim, adjusts the marker on the map in the InputfieldLeafletMapMarker and fills the (now hidden) fields with the lat lng and name. Although I have done this about 4 years ago or so, it is still working. Here's the module code for reference in case anyone wants to go a similar route. Not a very clean and portable integration but it is doing the job and is here mainly to serve as an example how you could tackle this scenario. EDIT: short screencast to show UI AddressToMap.module.php (just loads the necessary JS) <?php use ProcessWire\HookEvent; class AddressToMap extends WireData implements Module { /** * getModuleInfo is a module required by all modules to tell ProcessWire about them * * @return array * */ public static function getModuleInfo() { return array( // The module'ss title, typically a little more descriptive than the class name 'title' => 'AddressToMap', // version number 'version' => 001, // summary is brief description of what this module is 'summary' => 'Geocode an Address and put a Pin on the Leaflet Map', // singular=true: indicates that only one instance of the module is allowed. // This is usually what you want for modules that attach hooks. 'singular' => true, // autoload=true: indicates the module should be started with ProcessWire. // This is necessary for any modules that attach runtime hooks, otherwise those // hooks won't get attached unless some other code calls the module on it's own. // Note that autoload modules are almost always also 'singular' (seen above). 'autoload' => "template=admin", // Optional font-awesome icon name, minus the 'fa-' part 'icon' => 'map', ); } public function init() { $this->wire->addHookAfter('ProcessPageEdit::loadPage', $this, 'loadAssets'); } public function loadAssets(Hookevent $event) { $id = $event->arguments(0); $page = $this->pages->get($id); if($page->template == 'member') { $this->config->scripts->add($this->config->urls->siteModules . $this->className . "/{$this->className}.js"); } } } AddressToMap.js var AddressToMap = { init: function () { // $(window).on('map:init', function (e) { // map = e.originalEvent.detail.map; // console.log(map); // }); var coder = window.L.Control.Geocoder.nominatim(); // console.log(AddressToMap.geocoder); var address = $('p.InputfieldLeafletMapMarkerAddress').css({ 'display': 'none' }); var setAddress = $('<p></p>').addClass('InputfieldLeafletMapMarkerSetAddress'); var button = $($.parseHTML("<button class='btn btn-primary btn-block' id='setAddress'><i class='fa fa-arrow-down fa-fw'></i>" + ProcessWire.config.strings.addresstomap + "<i class='fa fa-arrow-down fa-fw'></i></button>")); setAddress.append(button); setAddress.insertAfter(address); var inputfieldName = $('.Inputfield.InputfieldLeafletMapMarker').attr('id').replace('wrap_', ''); button.on('click', function (event) { event.preventDefault(); var combAddress = $('#Inputfield_address').val() + ', ' + $('#Inputfield_postcode').val() + ', ' + $('#Inputfield_city').val(); coder.geocode(combAddress, function (results) { if(results[0] !== undefined) { var map = window.leafletmap; map.eachLayer(function(layer){ if(layer.options.draggable === true) { var latlng = L.latLng(results[0].center.lat, results[0].center.lng); layer.setLatLng(latlng); $('#_' + inputfieldName + '_lat').val(results[0].center.lat); $('#_' + inputfieldName + '_lng').val(results[0].center.lng); $('input#' + inputfieldName).val(results[0].name); map.fitBounds(results[0].bbox); } }); } else { alert('Could not geocode this address'); } }); }); } } $(document).ready(function () { AddressToMap.init(); });
-
@thetuningspoon magicpages are super cool ? the only drawback is that they come with a small performance penalty as I need to load all available templates once on init and then attach the hooks or magic methods on applicable templates: https://github.com/baumrock/RockMigrations/blob/87541c899901f773bf62068a639f070f48a85453/MagicPages.module.php#L43-L51 The init() and ready() method (and the magic methods) are only called once for every template because I create one runtime page for each template on ProcessWire::init The magic methods on the other hand only trigger for the correct pageclass because I have an early exit in the hook if the pageclass does not match: https://github.com/baumrock/RockMigrations/blob/87541c899901f773bf62068a639f070f48a85453/MagicPages.module.php#L113-L119 You might also like this:
-
https://blog.gskinner.com/archives/2020/07/introducing-flokk-a-desktop-app-built-with-flutter.html https://blog.gskinner.com/archives/2020/09/flokk---how-we-built-a-desktop-app-using-flutter.html "Rive takes advantage of cutting-edge technologies such as Flutter and WebAssembly to create native desktop and web apps." https://rive.app "Bring Your Apps and Games to Life with Real-Time Animation" https://blog.rive.app/rives-web-runtime/ "Learn how Rive's web runtime works under the hood and how to embed a Rive animation in a web page."
- 35 replies
-
- 2
-
-
Hi, I'm not sure what has gone wrong but after adding a few lines for webp to my .htaccess my site no longer works properly. I reversed it but there may have been another version of .htacess on the site which I've now overwritten. Note: After some checking: It doesn't seem to be rendering the templates. Eg: / = (should use template home.php) /about/ = (uses template page.php) For example putting "die;" in the home.php does nothing on the live server. Basically, it doesn't render the content block and spits out "default content" It is working perfectly on my local server with the same .htaccess file. $config->useMarkupRegions = true; I do not know what to do and I'd be grateful for help. This is my site: https://greglumley.com I've changed "default content" to a more friendly message. And here is my .htaccess ################################################################################################# # START PROCESSWIRE HTACCESS DIRECTIVES # @version 3.0 # @htaccessVersion 301 ################################################################################################# # # Upgrading htaccess (or index) version 300 to 301 # ----------------------------------------------------------------------------------------------- # If you never modified your previous .htaccess file, then you can simply replace it with this # one. If you have modified your .htaccess file, then you will want to copy/paste some updates # to the old one instead: # If your htaccess/index version is 300, upgrade to this version by replacing all of sections #5 # and #15 (Access Restrictions). Also take a look at section #9, which you might also consider # replacing if using HTTPS, though it is not required. (For instance, HSTS might be worthwhile) # # Following that, optionally review the rest of the file to see if there are any other changes # you also want to apply. Sections tagged "(v301)" are new or have significant changes. # # When finished, add a line at the top identical to the "htaccessVersion 301" that you see at # the top of this file. This tells ProcessWire your .htaccess file is up-to-date. # # Resolving 500 errors # ----------------------------------------------------------------------------------------------- # Depending on your server, some htaccess rules may not be compatible and result in a 500 error. # If you experience this, find all instances of the term "(500)" in this file for suggestions on # things you can change to resolve 500 errors. # # Optional features # ----------------------------------------------------------------------------------------------- # Many of the rules in this .htaccess file are optional and commented out by default. While the # defaults are okay for many, you may want to review each section in this .htaccess file for # optional rules that you can enable to increase security, speed or best practices. To quickly # locate all optional rules, search this file for all instances of "(O)". # # If using a load balancer # ----------------------------------------------------------------------------------------------- # If using a load balancer (like those available from AWS) some htaccess rules will need to # change. Search this file for instances of "(L)" for details. # # ----------------------------------------------------------------------------------------------- # 1. Apache Options # # Note: If you experience a (500) error, it may indicate your host does not allow setting one or # more of these options. First try replacing the +FollowSymLinks with +SymLinksifOwnerMatch. # If that does not work, try commenting them all out, then uncommenting one at a time to # determine which one is the source of the 500 error. # ----------------------------------------------------------------------------------------------- # Do not show directory indexes (strongly recommended) Options -Indexes # Do not use multiviews (v301) Options -MultiViews # Do follow symbolic links Options +FollowSymLinks # Options +SymLinksifOwnerMatch # Character encoding: Serve text/html or text/plain as UTF-8 AddDefaultCharset UTF-8 # ----------------------------------------------------------------------------------------------- # 2. ErrorDocument settings: Have ProcessWire handle 404s # # For options and optimizations (O) see: # https://processwire.com/blog/posts/optimizing-404s-in-processwire/ # ----------------------------------------------------------------------------------------------- ErrorDocument 404 /index.php # ----------------------------------------------------------------------------------------------- # 3. Handle request for missing favicon.ico/robots.txt files (no ending quote for Apache 1.3) # ----------------------------------------------------------------------------------------------- <Files favicon.ico> ErrorDocument 404 "The requested file favicon.ico was not found. </Files> <Files robots.txt> ErrorDocument 404 "The requested file robots.txt was not found. </Files> # ----------------------------------------------------------------------------------------------- # 4. Protect from XSS with Apache headers # ----------------------------------------------------------------------------------------------- <IfModule mod_headers.c> # prevent site from being loaded in an iframe on another site # you will need to remove this one if you want to allow external iframes Header always append X-Frame-Options SAMEORIGIN # To prevent cross site scripting (IE8+ proprietary) Header set X-XSS-Protection "1; mode=block" # Optionally (O) prevent mime-based attacks via content sniffing (IE+Chrome) # Header set X-Content-Type-Options "nosniff" </IfModule> # ----------------------------------------------------------------------------------------------- # 5. Prevent access to various types of files (v301) # # Note that some of these rules are duplicated by RewriteRules or other .htaccess files, as we # try to maintain two layers of protection when/where possible. # ----------------------------------------------------------------------------------------------- # 5A. Block access to inc, info, info.json/php, module/php, sh, sql and composer files # ----------------------------------------------------------------------------------------------- <FilesMatch "\.(inc|info|info\.(json|php)|module|module\.php|sh|sql)$|^\..*$|composer\.(json|lock)$"> <IfModule mod_authz_core.c> Require all denied </IfModule> <IfModule !mod_authz_core.c> Order allow,deny </IfModule> </FilesMatch> # 5B. Block bak, conf, dist, ini, log, orig, sh, sql, swo, swp, ~, and more # ----------------------------------------------------------------------------------------------- <FilesMatch "(^#.*#|\.(bak|conf|dist|in[ci]|log|orig|sh|sql|sw[op])|~)$"> <IfModule mod_authz_core.c> Require all denied </IfModule> <IfModule !mod_authz_core.c> Order allow,deny </IfModule> </FilesMatch> # ----------------------------------------------------------------------------------------------- # 6. Override a few PHP settings that can't be changed at runtime (not required) # Note: try commenting out this entire section below if getting Apache (500) errors. # ----------------------------------------------------------------------------------------------- <IfModule mod_php5.c> php_flag magic_quotes_gpc off php_flag magic_quotes_sybase off php_flag register_globals off </IfModule> # ----------------------------------------------------------------------------------------------- # 7. Set default directory index files # ----------------------------------------------------------------------------------------------- DirectoryIndex index.php index.html index.htm # ----------------------------------------------------------------------------------------------- # 8. Enable Apache mod_rewrite (required) # ----------------------------------------------------------------------------------------------- <IfModule mod_rewrite.c> RewriteEngine On # Send WEBP images for JPG or PNG when supported and available. # This means that a request for a JPG or PNG file will instead deliver # WEBP data, but only when the browser supports and understands it. # RewriteCond %{HTTP_ACCEPT} image/webp # RewriteCond %{REQUEST_FILENAME} -f # RewriteCond %{DOCUMENT_ROOT}/$1$2$3/$4.webp -f # RewriteCond expr "! %{QUERY_STRING} -strmatch 'nc=*'" # RewriteRule ^(.*?)(site/assets/files/)([0-9]+)/(.*)\.(jpe?g|png)(.*)$ /$1$2$3/$4.webp [L] # 8A. Optionally (O) set a rewrite base if rewrites are not working properly on your server. # ----------------------------------------------------------------------------------------------- # In addition, if your site directory starts with a "~" you will most likely have to use this. # https://httpd.apache.org/docs/current/mod/mod_rewrite.html#rewritebase # Examples of RewriteBase (root and subdirectories): # RewriteBase / # RewriteBase /pw/ # RewriteBase /~user/ # 8B. Set an environment variable so the installer can detect that mod_rewrite is active. # ----------------------------------------------------------------------------------------------- # Note that some web hosts don't support this. If you get a (500) error, try commenting out this # SetEnv line below. <IfModule mod_env.c> SetEnv HTTP_MOD_REWRITE On </IfModule> # ----------------------------------------------------------------------------------------------- # 9. Optionally Force HTTPS (O) # ----------------------------------------------------------------------------------------------- # Note that on some web hosts you may need to replace %{HTTPS} with %{ENV:HTTPS} in order # for it to work (in sections 9A and 9D below). If on a load balancer or proxy setup, you will # likely need to use 9B rather than 9A, and 9E rather than 9D. # ----------------------------------------------------------------------------------------------- # 9A. To redirect HTTP requests to HTTPS, uncomment the lines below (also see note above): # ----------------------------------------------------------------------------------------------- # RewriteCond %{HTTPS} !=on # RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301] # 9B. If using load balancer/AWS or behind proxy, use the following rather than 9A above: (L) # ----------------------------------------------------------------------------------------------- # RewriteCond %{HTTP:X-Forwarded-Proto} =http # RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301] # 9C. If using cPanel AutoSSL or Let's Encrypt webroot you may need to MOVE one of the below # lines after the first RewriteCond in 9A or 9B to allow certificate validation: # ----------------------------------------------------------------------------------------------- # RewriteCond %{REQUEST_URI} !^/\.well-known/acme-challenge/ # RewriteCond %{REQUEST_URI} !^/\.well-known/cpanel-dcv/[\w-]+$ # RewriteCond %{REQUEST_URI} !^/\.well-known/pki-validation/[A-F0-9]{32}\.txt(?:\ Comodo\ DCV)?$ # 9D. Store current scheme in a 'proto' environment variable for later use # ----------------------------------------------------------------------------------------------- RewriteCond %{HTTPS} =on RewriteRule ^ - [env=proto:https] RewriteCond %{HTTPS} !=on RewriteRule ^ - [env=proto:http] # 9E. If using load balancer/AWS or behind proxy, use lines below rather than 9D: (L) # ----------------------------------------------------------------------------------------------- # RewriteCond %{HTTP:X-Forwarded-Proto} =https # RewriteRule ^ - [env=proto:https] # RewriteCond %{HTTP:X-Forwarded-Proto} =http # RewriteRule ^ - [env=proto:http] # 9F. Tell web browsers to only allow access via HSTS: Strict-Transport-Security (O) (v301) # ----------------------------------------------------------------------------------------------- # This forces client-side SSL redirection. Before enabling be absolutely certain you can # always serve via HTTPS because it becomes non-revokable for the duration of your max-age. # See link below for details and options (note 'max-age=31536000' is 1-year): # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security <IfModule mod_headers.c> # Uncomment one (1) line below & adjust as needed to enable Strict-Transport-Security (HSTS): # Header always set Strict-Transport-Security "max-age=31536000;" # Header always set Strict-Transport-Security "max-age=31536000; includeSubdomains" # Header always set Strict-Transport-Security "max-age=31536000; preload" # Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" </IfModule> # Section 10 intentionally omitted for future use # ----------------------------------------------------------------------------------------------- # 11. Nuisance blocking/firewall # ----------------------------------------------------------------------------------------------- # None of these are enabled by default, but are here for convenience when the need arises. # Review and uncomment as needed. For more complete firewall (and more overhead), the 7G firewall # (or latest version) is worth considering, see: https://perishablepress.com/7g-firewall/ # ----------------------------------------------------------------------------------------------- # 11A. Block via IP addresses # ----------------------------------------------------------------------------------------------- # Note that IP addresses here are examples only and should be replaced with actual IPs. # Block single IP address # Deny from 111.222.333.444 # Block multiple IP addresses # Deny from 111.222.333.444 44.33.22.11 # Block IP address ranges (999.88.*, 99.88.77.*, 1.2.3.*) # Deny from 999.888 99.88.77 1.2.3 # 11B. Block via request URI (matches strings anywhere in request URL) # ----------------------------------------------------------------------------------------------- # RewriteCond %{REQUEST_URI} (bad-word|wp-admin|wp-content) [NC] # RewriteRule .* - [F,L] # 11B. Block via user agent strings (matches strings anywhere in user-agent) # ----------------------------------------------------------------------------------------------- # RewriteCond %{HTTP_USER_AGENT} (bad-bot|mean-bot) [NC] # RewriteRule .* - [F,L] # 11C. Block via remote hosts # ----------------------------------------------------------------------------------------------- # RewriteCond %{REMOTE_HOST} (bad-host|annoying-host) [NC] # RewriteRule .* - [F,L] # 11D. Block via HTTP referrer (matches anywhere in referrer URL) # ----------------------------------------------------------------------------------------------- # RewriteCond %{HTTP_REFERER} (bad-referrer|gross-referrer) [NC] # RewriteRule .* - [F,L] # 11E. Block unneeded request methods (only if you do not need them) # ----------------------------------------------------------------------------------------------- # RewriteCond %{REQUEST_METHOD} ^(connect|debug|delete|move|put|trace|track) [NC] # RewriteRule .* - [F,L] # 11F. Limit file upload size from Apache (i.e. 10240000=10 MB, adjust as needed) # ----------------------------------------------------------------------------------------------- # LimitRequestBody 10240000 # ----------------------------------------------------------------------------------------------- # 12. Access Restrictions: Keep web users out of dirs or files that begin with a period, # but let services like Lets Encrypt use the webroot authentication method. # ----------------------------------------------------------------------------------------------- RewriteRule "(^|/)\.(?!well-known)" - [F] # ----------------------------------------------------------------------------------------------- # 13. Optional domain redirects (O) # # Redirect domain.com to www.domain.com redirect (or www to domain.com redirect). # To use, uncomment either 13A, 13B or 13C. Do not use more than one of them. 13A and 13B # redirect non-www hosts to www.domain.com, 13C redirects www.domain.com host to domain.com. # ----------------------------------------------------------------------------------------------- # 13A. Redirect domain.com and *.domain.com to www.domain.com (see also 13B as alternate): # ----------------------------------------------------------------------------------------------- # RewriteCond %{HTTP_HOST} !^www\. [NC] # RewriteCond %{SERVER_ADDR} !=127.0.0.1 # RewriteCond %{SERVER_ADDR} !=::1 # RewriteRule ^ %{ENV:PROTO}://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301] # 13B. Alternate www redirect if 13A does not work for your server: # ----------------------------------------------------------------------------------------------- # RewriteCond %{HTTP_HOST} !^www\. [NC] # RewriteRule ^ %{ENV:PROTO}://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301] # 13C. Redirect www.domain.com to domain.com (do not combine with 13A or 13B): # ----------------------------------------------------------------------------------------------- # RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC] # RewriteRule ^ %{ENV:PROTO}://%1%{REQUEST_URI} [R=301,L] # ----------------------------------------------------------------------------------------------- # 14. Optionally send URLs with non-ASCII name-format characters to 404 page (optimization). # # This ensures that ProcessWire does not spend time processing URLs that we know ahead of time # are going to result in 404s. Uncomment lines below to enable. (O) # ----------------------------------------------------------------------------------------------- # RewriteCond %{REQUEST_URI} "[^-_.a-zA-Z0-9/~]" # RewriteCond %{REQUEST_FILENAME} !-f # RewriteCond %{REQUEST_FILENAME} !-d # RewriteRule ^(.*)$ index.php?it=/http404/ [L,QSA] # ----------------------------------------------------------------------------------------------- # 15. Access Restrictions (v301) # ----------------------------------------------------------------------------------------------- # 15A. Keep http requests out of specific files and directories # ----------------------------------------------------------------------------------------------- # Prevent all the following rules from blocking images in site install directories RewriteCond %{REQUEST_URI} !(^|/)site-[^/]+/install/[^/]+\.(jpg|jpeg|png|gif|webp|svg)$ # Block access to any htaccess files RewriteCond %{REQUEST_URI} (^|/)(\.htaccess|htaccess\..*)$ [NC,OR] # Block access to various assets directories RewriteCond %{REQUEST_URI} (^|/)(site|site-[^/]+)/assets/(cache|logs|backups|sessions|config|install|tmp)($|/.*$) [NC,OR] # Block access to the /site/install/ directories RewriteCond %{REQUEST_URI} (^|/)(site|site-[^/]+)/install($|/.*$) [NC,OR] # Block dirs in /site/assets/dirs that start with a hyphen (see config.pagefileSecure) RewriteCond %{REQUEST_URI} (^|/)(site|site-[^/]+)/assets.*/-.+/.* [NC,OR] # Block access to /wire/config.php, /site/config.php, /site/config-dev.php, /wire/index.config.php, etc. RewriteCond %{REQUEST_URI} (^|/)(wire|site|site-[^/]+)/(config|index\.config|config-dev)\.php($|/) [NC,OR] # Block access to any PHP-based files in /site/templates-admin/ or /wire/templates-admin/ RewriteCond %{REQUEST_URI} (^|/)(wire|site|site-[^/]+)/templates-admin($|/|/.*\.(php|html?|tpl|inc))($|/) [NC,OR] # Block access to any PHP or markup files in /site/templates/ or /site-*/templates/ RewriteCond %{REQUEST_URI} (^|/)(site|site-[^/]+)/templates($|/|/.*\.(php|html?|tpl|inc))($|/) [NC,OR] # Block access to any files in /site/classes/ or /site-*/classes/ RewriteCond %{REQUEST_URI} (^|/)(site|site-[^/]+)/classes($|/.*) [NC,OR] # Block access to any PHP files within /site/assets/ and further RewriteCond %{REQUEST_URI} (^|/)(site|site-[^/]+)/assets($|/|/.*\.ph(p|ps|tml|p[0-9]))($|/) [NC,OR] # Block access to any PHP, module, inc or info files in core or core modules directories RewriteCond %{REQUEST_URI} (^|/)wire/(core|modules)/.*\.(php|inc|tpl|module|info\.json)($|/) [NC,OR] # Block access to any PHP, tpl or info.json files in /site/modules/ or /site-*/modules/ RewriteCond %{REQUEST_URI} (^|/)(site|site-[^/]+)/modules/.*\.(php|inc|tpl|module|info\.json)$ [NC,OR] # Block access to any software identifying txt, markdown or textile files RewriteCond %{REQUEST_URI} (^|/)(COPYRIGHT|INSTALL|README|htaccess)\.(txt|md|textile)$ [NC,OR] # Block potential arbitrary backup files within site directories for things like config RewriteCond %{REQUEST_URI} (^|/)(site|site-[^/]+)/(config[^/]*/?|[^/]+\.php.*)$ [NC,OR] # Block access throughout to temporary files ending with tilde created by certain editors RewriteCond %{REQUEST_URI} \.(html?|inc|json|lock|module|php|py|rb|sh|sql|tpl|tmpl|twig)~$ [NC,OR] # Block access to names of potential backup file extensions within wire or site directories RewriteCond %{REQUEST_URI} (^|/)(wire/|site[-/]).+\.(bak|old|sql|sw[op]|(bak|php|sql)[./]+.*)[\d.]*$ [NC,OR] # Block all http access to the default/uninstalled site-default directory RewriteCond %{REQUEST_URI} (^|/)site-default/ # If any conditions above match, issue a 403 forbidden RewriteRule ^.*$ - [F,L] # 15B. Block archive file types commonly used for backup purposes (O) # ----------------------------------------------------------------------------------------------- # This blocks requests for zip, rar, tar, gz, and tgz files that are sometimes left on servers # as backup files, and thus can be problematic for security. This rule blocks those files # unless they are located within the /site/assets/files/ directory. This is not enabled by # default since there are many legitimate use cases for these files, so uncomment the lines # below if you want to enable this. # RewriteCond %{REQUEST_URI} \.(zip|rar|tar|gz|tgz)$ [NC] # RewriteCond %{REQUEST_URI} !(^|/)(site|site-[^/]+)/assets/files/\d+/ [NC] # RewriteRule ^.*$ - [F,L] # PW-PAGENAME # ----------------------------------------------------------------------------------------------- # 16A. Ensure that the URL follows the name-format specification required by PW # See also directive 16b below, you should choose and use either 16a or 16b. # ----------------------------------------------------------------------------------------------- RewriteCond %{REQUEST_URI} "^/~?[-_.a-zA-Z0-9/]*$" # ----------------------------------------------------------------------------------------------- # 16B. Alternative name-format specification for UTF8 page name support. (O) # If used, comment out section 16a above and uncomment the directive below. If you have updated # your $config->pageNameWhitelist make the characters below consistent with that. # ----------------------------------------------------------------------------------------------- # RewriteCond %{REQUEST_URI} "^/~?[-_./a-zA-Z0-9æåäßöüđжхцчшщюяàáâèéëêěìíïîõòóôøùúûůñçčćďĺľńňŕřšťýžабвгдеёзийклмнопрстуфыэęąśłżź]*$" # END-PW-PAGENAME # ----------------------------------------------------------------------------------------------- # 17. If the request is for a file or directory that physically exists on the server, # then don't give control to ProcessWire, and instead load the file # ----------------------------------------------------------------------------------------------- RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !(favicon\.ico|robots\.txt) # ----------------------------------------------------------------------------------------------- # 18. Optionally (O) prevent PW from attempting to serve images or anything in /site/assets/. # Both of these lines are optional, but can help to reduce server load. However, they # are not compatible with the $config->pagefileSecure option (if enabled) and they # may produce an Apache 404 rather than your regular 404. You may uncomment the two lines # below if you don't need to use the $config->pagefileSecure option. After uncommenting, test # a URL like domain.com/site/assets/files/test.jpg to make sure you are getting a 404 and not # your homepage. If getting your homepage, then either: do not use this option, or comment out # section #2 above that makes ProcessWire the 404 handler. # ----------------------------------------------------------------------------------------------- # RewriteCond %{REQUEST_URI} !\.(jpg|jpeg|gif|png|ico|webp|svg)$ [NC] # RewriteCond %{REQUEST_FILENAME} !(^|/)site/assets/ # ----------------------------------------------------------------------------------------------- # 19. Pass control to ProcessWire if all the above directives allow us to this point. # For regular VirtualHosts (most installs) # ----------------------------------------------------------------------------------------------- RewriteRule ^(.*)$ index.php?it=$1 [L,QSA] # ----------------------------------------------------------------------------------------------- # 20. If using VirtualDocumentRoot (500): comment out the one above and use this one instead # ----------------------------------------------------------------------------------------------- # RewriteRule ^(.*)$ /index.php?it=$1 [L,QSA] </IfModule> ################################################################################################# # END PROCESSWIRE HTACCESS DIRECTIVES #################################################################################################
-
I couldn't find much about the pagefileSecure option. Is this just a runtime setting I can switch on or off anytime? Or is it only for files uploaded later? Is there anything changing in the files/assets folder?
-
ProcessWire 3.0.198 contains a mixture of new features and issue resolutions. Below are details on a few of the new features: Support was added for runtime page cache groups. This enables pages to be cached as a group—and just as importantly—uncached as a group. While it can be used by anybody, it was added primarily to add efficiency to $pages->findMany(), so that it can cache supporting pages (like parents and page references). Previously, it would have to load a fresh copy of each supporting page used by findMany() results (for every returned page) since findMany() used no in-memory caching. If it did cache in memory, then you could potentially run out of memory on large result sets, so that strategy was avoided. Consider the case of iterating over all pages returned by findMany() and outputting their URLs... that triggers load of all parent pages for each page in the result set. And without a memory cache, it meant it would have to do it for each page in the results. Following this week's updates, now it can cache these supporting pages for each chunk of 250 pages, offering potentially significant performance improvement in many cases, without creating excess memory usage or memory leaks. When the chunk of 250 result pages is released from memory (to make room for the next chunk), all the supporting pages (parents, page references, etc.) are also released from memory, but not before. Now findMany() can offer both memory efficiency and great performance. For as long as I can remember, ProcessWire has had an apparently undocumented feature for dependent select fields that enables you to have two page reference fields using selects (single, multiple or AsmSelect) where the selected value in one select changes the selectable options in the other select (Ajax powered). Think of "categories" and "subcategories" selects, for example, where your selection for "categories" changes what options are selectable in "subcategories". Part of the reason it's undocumented is that it is one of those features that is a little bit fragile, and didn't work in some instances, such as within Repeater items. That changed this week, as the feature has been updated so that it can also work in Repeater items too. The $pages->findRaw() method was updated with a new "nulls" option (per Adrian's request in #1553). If you enable this new "nulls" option, it will add placeholders in the return value with null values for any fields you requested that were not present on each matching page. This reflects how PW's database works, in that if a field has no value, PW removes it from the database entirely. Without the nulls option (the existing behavior), it retains the more compact return values, which omit non present values completely. For example, consider the following: $items = $pages->findRaw("template=user, fields=email|first_name|last_name"); If a row in the result set had no "first_name" or "last_name" populated, then it would not appear in the that row of the return value at all... [ "email": "ryan@processwire.com" ] By specifying the "nulls" option, it will still include placeholders for field values not present in the database, and these will have a value of null: $items = $pages->findRaw("template=user, nulls=1, fields=email|first_name|last_name"); [ "email": "ryan@processwire.com", "first_name": null, "last_name": null ] By the way, if you don't specify which fields you want to get (which is the same as saying "get all") then adding the nulls option makes it provide placeholders for all fields used by the page's template. As you might expect, without the nulls option, it includes only populated fields. Also included in 3.0.198 are 7 issue fixes, most of which are visible in the dev branch commits log. That's all for this week. Thanks for reading this update and have a great weekend!
- 5 replies
-
- 18
-
-
-
Thx, it has already been running all the time ? Just tried without it and same issue. What about adding a $config->noTracy = true config setting that makes sure that tracy is not loaded if the flag is true? I could maybe set that on runtime and it could also be nice to have on production servers maybe?
-
When you do a $pages->find($selector) operation your selector is translated by PW into an SQL query. It's a bit of a simplification (because there some exceptions for things like "count"), but essentially this means that you can only sort by values that correspond to columns in the database. So for example you can sort by "title" because that corresponds to a column in the database. But you can't use some logic at runtime to conditionally build up a custom value based on various properties of each page and then sort by that because there is no corresponding column for that custom value. So your options are... 1. If the only way to work out the sort is to iterate over all the pages in a PageArray and you then want to paginate that sorted PageArray, you can do something like this: // $results is a PageArray that you have applied some custom sorting to at runtime $total = $results->count(); $limit = 10; // Convert page number to be zero-based $page_num = $input->pageNum - 1; $start = $page_num * $limit; // Get the slice of results for the current pagination $results = $results->slice($start, $limit); $results->setStart($start)->setLimit($limit)->setTotal($total); foreach($results as $result) { // Output result } echo $results->renderPager(); But because you have to load all the results into memory in order to sort them, this strategy is not going to scale well with large numbers of results. 2. If the sorting doesn't actually depend on dynamic input you can think about using an integer field in the template to store a weighting that you can sort by in a $pages->find() selector. You would use a saveReady hook to populate this sort_weighting field according to other field values in the page. You can use the API to loop over all your book pages to set a sort_weighting value initially. The sorting in your code didn't quite make sense to me so you'll probably need to adapt this to suit, but the general idea is this: // In /site/ready.php $pages->addHookAfter('saveReady', function(HookEvent $event) { $page = $event->arguments(0); if($page->template == 'book') { $sort_weighting = 0; if(!$page->subject) $sort_weighting = -1; if(!$page->subject && !$page->author) $sort_weighting = -2; $page->sort_weighting = $sort_weighting; } }); // In your template code $results = $pages->find("template=book, sort=sort_weighting, sort=subject, sort=cleanauthor, sort=cleantitle, limit=50");
-
Thank you very much for your inspiring, and detailed answer @monollonom I am going to make some tests very soon, also I didn’t know the existence of inputfield-runtime-only it solves a blurry area in my view of the process!
-
I don't know if anyone pm'd you already but it can be quite simple if you only need to generate a static svg from a text input. I found this library https://github.com/kartsims/easysvg which would allow you to do it all server-wise if you have .svg font files at hand. My approach would be to have a file input for the font file, a text input for the text you want to generate the svg from, a textarea (closed by default and non-editable) to hold the svg code, and something like https://processwire.com/modules/inputfield-runtime-only/ to echo the textarea's content (the svg) as a preview. Basically a hook in `ready.php`: require "/path/to/easySVG.php"; wire()->addHookBefore("Pages::saveReady", function(HookEvent $event) { /** @var Page $page */ $page = $event->arguments(0); if($page->template->name !== "font") return; // or whatever if(!$page->fontfile && !$page->text) return; // file and text inputs // copy/pasting from easySVG example $svg = new EasySVG(); $svg->setFontSVG($page->fontfile->url); $svg->setFontSize(100); $svg->setFontColor('#000000'); $svg->setLineHeight(1.2); $svg->setLetterSpacing(.1); $svg->setUseKerning(true); $svg->addText($page->text); list($textWidth, $textHeight) = $svg->textDimensions($page->text); $svg->addAttribute("width", $textWidth."px"); $svg->addAttribute("height", $textHeight."px"); $page->svgcode = $svg->asXML(); // textarea input $event->arguments(0, $page); }); And in your `svgpreview` field/file (check RuntimeOnly doc) or template file: echo $page->getUnformatted("svgcode"); (I used getUnformatted in case there are textformatters but it would best if there's none in the field's settings) It's not tested and made on top of my head but I think this might work. (nice to see Velvetyne here btw, I like your work and a good friend of mine made La Savate ?)
-
Suggestions on implementing a Pinterest like save button
flydev replied to Liam88's topic in Getting Started
Get rid of writing the $action = $input->post->option('bookmark', [ 'save', 'remove'] ); block in a loop, you do not need that. If you look at my example (made some corrections for consistency), you are capturing the action made by the user in the `$input->bookmark->action` and the id in `$input->bookmark->id` (form data built in the $.post() ajax jquery code): (I don't know what is the `$input->post->option('a', ['b', 'c'])`) thing, but we dont care) bd($input->post); // debug with tracy /** contain: * action: 'save' * bookmark: '1024' */ Then just handle the request : <?php /** threat ajax (pw) => https://processwire.com/api/ref/config/#pwapi-methods-runtime * Better to write a dedicated template which will receive the request. * That is a good candidate and exercise to try the module AppApi ? */ if($config->ajax && $input->post->bookmark) { // bd($input->post->bookmark); // debug with tracy, uncomment if you have it /** contain: * action: 'save' or 'remove' * bookmark: '1024' */ $bookmarkid = $sanitizer->int($input->post->bookmark); $action = $sanitizer->name($input->post->action); switch($action) { // which action ? case 'save': // save logic $message = 'Borat saved bookmark "'. $bookmarkid .'" ?'; $success = true; break; case 'remove': // remove logic $message = 'Borat removed bookmark "'. $bookmarkid .'" ❌'; $success = true; break; default: $message = 'error'; $success = false; } // build the response data array that will be returned in `data` from `.done(function(data) {` $json = array( 'id' => $bookmarkid, 'action' => $action, 'message' => $message, 'success' => $success ); // convert data and send as JSON header('Content-Type: text/json; charset=utf-8'); // forgot this line echo json_encode($json); return; } ?> <!-- the only one loop --> <!-- you dont really need a form --> <!-- <form action='<?=$page->url?>' method='post'> --> <?php // dummy bookmarks loop logic for the show $bookmarks = $pages->find("template=dummypage, limit=5, sort=sort"); foreach ($bookmarks as $bookmark): ?> <?php if($user->isLoggedin()): ?> <!-- show button to save and remove this page to bookmarks --> <!-- of course, make your own logic to show one or other button --> <!-- add a data attribut to each button --> <button class="button bookmark" name='bookmark' value='save' data-id='<?= $bookmark->id ?>'>Save <?= $bookmark->id ?></button> <button class="button bookmark" name='bookmark' value='remove' data-id='<?= $bookmark->id ?>'>Remove <?= $bookmark->id ?></button> <?php endif; ?> <?php endforeach; ?> <!-- </form> --> <script> jQuery(document).ready(function($) { // when clicked, send ajax request to server $('button.bookmark').on('click', function(e /* add event arg */) { var btn = $(this).hasClass('clicked') ? false : $(this).addClass('clicked'); if (!btn) { console.warn(`⚠️ Bookmark already saved to profil`); return false; } $.post('<?= $page->url /* send to the page which have the logic and return json answer */ ?>', { action: $(this).val(), bookmark: btn.data('id') }) .done(function(data) { console.log(data, "? response from ajax req"); // $(this).removeClass('clicked'); // remove `clicked` class, can be added on the foreach loop if the bookmark is already saved and then locked, or whatever.. console.info(`✅ Bookmark id => ${data.id} ${data.action} `); }); //e.preventDefault(); // you didn't need a <form>, and if you really want it, add this line to prevent default behavior and stop the redirection }); }); </script> I will make you an example to save the page, but if I were you, I would just save a "page (ID)" in a page-reference field in the profile. -
Suggestions on implementing a Pinterest like save button
flydev replied to Liam88's topic in Getting Started
I don't really get what is your issue, the click that still redirect ? If yes, just add `e.preventDefault()` to your js script to prevent default behavior as your are submiting a form. <?php /** threat ajax (pw) => https://processwire.com/api/ref/config/#pwapi-methods-runtime * Better to write a dedicated template which will receive the request. * That is a good candidate and exercise to try the module AppApi ? */ if($config->ajax && $input->post) { bd($input->post->bookmark); // debug with tracy /** contain: * action: 'add' * bookmark: '1024' */ /** * you can write some logic here, eg., to grab the post data sent by the ajax request */ $bookmarkid = $sanitizer->int($input->post->bookmark); // eg. you can get a page from that $bookmarkedPage = $pages->get($bookmarkid); // send response data back $message = 'Borat added bookmark "'. $bookmarkedPage->title .'" ?'; $success = true; // build the response data array $json = array( 'message' => $message, 'success' => $success ); // convert data and send as JSON header('Content-Type: text/json; charset=utf-8'); // forgot this line echo json_encode($json); return; } ?> <?php // dummy bookmarks loop logic for the show // foreach($bookmarks as $bookmark) : $bookmark = $pages->get(1024); // forgot this line ?> <!-- you dont really need a form --> <!-- <form action='<?=$page->url?>' method='post'> --> <?php if($user->isLoggedin()): ?> <!-- show button to add this page to bookmarks --> <!-- add a data attribut to each button --> <button class="button bookmark" name='bookmark' value='add' data-id='<?= $bookmark->id ?>'>Save bm #1</button> <?php endif; ?> <?php //endforeach; ?> <!-- </form> --> <script> jQuery(document).ready(function($) { // when clicked, send ajax request to server $('button.bookmark').on('click', function(e /* add event arg */) { var btn = $(this).hasClass('clicked') ? false : $(this).addClass('clicked'); if (!btn) { console.warn(`⚠️ Bookmark already saved to profil`); return false; } $.post('<?= $page->url /* send to the page which have the logic and return json answer */ ?>', { action: $(this).val(), bookmark: btn.data('id') }) .done(function(data) { console.log(data, "? response from ajax req"); // $(this).removeClass('clicked'); // remove `clicked` class, can be added on the foreach loop if the bookmark is already saved and then locked, or whatever.. console.info(`✅ Bookmark id => ${btn.data('id')} saved to user profil`); }); //e.preventDefault(); // you didn't need a <form>, and if you really want it, uncomment this line to prevent default behavior and stop the redirection }); }); </script> -
Thanks for the answer @szabesz! I've read the RuntimeMarkup module thread, and @kongondo also recommends to put the actual code in a file and just wireRenderFile() it. So that must be the main difference. I also thought about the easy inclusion of js and css in Runtime only as a substantial difference. By the way, I do not read any real sarcasm in @bernhard's post. I guess it is just a his style) He is always asking himself questions and answers them. Sort of inner dialog)
-
Background I'm creating a module to integrate https://pushalert.co/ into ProcessWire. You actually don't even need a module. You could just use the "Other Websites" javascript provided by PushAlert for basic functionality, ie send a broadcast notification to all subscribers. This is essentially what all the other integrations, including WordPress, do. The WP integration installs a widget with a form enabling the admin to enter details such as title, message, etc from a blog post. It does not: collect any statistics within the CMS about the notification enable audience fine tuning to eg a particular subscriber or subscriber segment within WP. The admin needs to use the PA dashboard for that functionality PushAlert has a javascript and REST API. It's intended that this module will use both. https://pushalert.co/documentation What my module does so far: associate a subscription with a user. FE user clicks a button on the website front end to subscribe and/or agrees to the browser popup to accept notifications from this site send broadcast push alerts from a page within admin It doesn't have a 'widget' but easy enough to create a fieldsetpage with the relevant fields and add that fs page to any appropriate templates, then with a hook, send the notification. Need to be careful that once published/sent, the notification is not automatically re-sent on subsequent page edits. Looking for help/collaboration on how best: to send a notification, eg from a blog post, then track the statistics. Dilemma is that the push notification must come from the admin page. Responses go to the sending page which, as it's an admin page, is restricted and will not accept the https response. This is where the other CMS integrations stop. The only json response from PushAlert is the status, eg 'success', and the notification id. There is no opportunity at this point to capture the sending page id. handle, 'once sent on page publish', do not automatically resend on future page edits Am thinking along the lines that FS Page will have a @kongondo runtime markup field https://modules.processwire.com/modules/fieldtype-runtime-markup/ to pull the stats from PushAlert. Every time an admin visits the page, the stats will update. Once an admin checks the 'Send notification on page publish' checkbox, a hook creates new front end page that records the 'sender page', sends the notification request to PA, which then uses that newly created frontend page, as the response endpoint. Another rook re-associates the front end page with the admin page (eg blog post), to update the stats. Potential use cases: Notify individual and/or users with a particular role of an event, eg "New work opportunity" for job seekers; new blog post published; entries now open, etc... Looking for help/ideas/collaboration on this module. Please let me know if you're interested and as I do, believe this would be a great addition to ProcessWire
- 15 replies
-
- 6
-
-
- push
- notifications
-
(and 1 more)
Tagged with:
-
I have indeed – and I dig it from the perspective of rapid development. As I understand it though, it comes with a runtime that contains things that may or may not be used. Sure, the Alpine runtime is small, but the build file I have in Svelte is looking a bit smaller (so far). That aside, enjoying Svelte so far – this is the first time I'm exploring all of its features.
-
You can either register your own api variable, eg in ready.php $wire->wire('contact', $yourpage); Or you simply add whatever property you need at runtime to the rockfrontend object: $rockfrontend->foo = 'Foo!'; $rockfrontend->bar = 'Bar!'; Then you can simply access those variables in your latte files: {$contact->title} {$rockfrontend->foo} {$rockfrontend->bar}
-
Hi, this is not so clear to me in part "pass variable to hidden input"? If need to save image path value to hidden input, than maybe it's better to go with hook in backend (after page save or other). Another option coud be to save image path value to hidden input in runtime (???), if that is the case, than try something like this: <?php foreach($page->dev_repeater as $repeater) { $image_field = $repeater->image_field; foreach($repeater->dev_child_repeater as $url) { // some other stuff, link etc... // check and save hidden_field value inside runtime (???) if($url->hidden_field == ""){ $url->of(false); // $url->save(); uncomment if save on second reload $url->hidden_field = $image_field->url; // <= this? $url->save('hidden_field'); } else { // hidden_field has some value echo $url->hidden_field; } } } ?> But also if there is any option to avoid nested repeater that would be better, and also try to think about using hooks in backend to avoid save in runtime. To me it's ok when need to save "page view counters" or some other events triggered by front-end users/vistors. Sorry if I don't understand your question well. Regards.
-
Module Module: RuntimeMarkup Fieldtype & Inputfield
MarkE replied to kongondo's topic in Modules/Plugins
Great module, but I'm having a couple of minor issues (unrelated, I think). The first issue seems intermittent and I can't work out why : In some cases, I can't get the inclusion of .js and .css to work. I've triple-checked all the naming etc. but the files just don't seem to load. My work-round (easy enough) is just to load the files in the php. The second issue may be because I am stretching the fieldtype's capability! I am using it within a PageTable field as follows. The PageTable field ("panelled_carousel") has a template "Panelled_carousel" which has fields "title", "imagePages" (a page reference field linking to a page with template "Image" and an image field "image_single") and "runtime_markup_images" (a runtime markup field with php file "RuntimeMarkup/Images.php"). The php file is (including a bit of debugging): $imagePages = $page->imagePages; bd($page, 'page with carousel'); $out = ''; wire()->log->save('debug', 'Page is ' . $page->title); foreach ($imagePages as $imagePage) { bd($imagePage, 'imagePage'); foreach ($imagePage->image_single as $image) { bd($image, 'image'); if (is_a($image, '\ProcessWire\Pageimage')) $out .= '<img src="' . $image->pia("width=200")->url . '"/>'; } } return $out; The RM field is updated when the imagePages field changes by javascript/AJAX : When editing the Page Table field, this all works well - any changes in the imagePages (add/re-order/delete etc) are immediately reflected in the RM field. However, when saving the Page Table Field and returning to the host page, the RM PHP throws an error unless I catch it with the condition - is_a($image, '\ProcessWire\Pageimage') - in the code above. The reason is that in some cases $image seems to be taking a string, integer or boolean value, even though $imagePage has class Page and the dump shows it is the right page. Trapping this error means that the images in the table are all blank after the save. However refreshing the page puts everything right again. So not a deal-breaker but a bit odd. To illustrate, here is the top page with the page table (including images): Clicking on "Blue" to edit an item we get: Then, clicking save and returning to the top page, the images do not render: The debugging shows that this is not because Images.php has not run, but because $image is of the wrong type (as described above). Refreshing the page restores the images. Any ideas? EDIT: I should add that the problem does not seem to be related to my .js script, or even RuntimeMarkup specifically as exactly the same issue happens in a Page Table with @Robin S's RuntimeOnly module with no js attached to it. So it seems to be something to do with how the runtime markup is interacting with the page table display. -
Please don't use this module any more. I think in the end it just adds more complexity (and dependencies) than benefits. See this tutorial how simple it is to create a custom runtime-only Inputfield: WHY? I've started building this module because the existing solutions by @kongondo and @kixe (https://modules.processwire.com/modules/fieldtype-runtime-markup/ and https://github.com/kixe/FieldtypeMarkup) did not exactly fit my needs. Actually this module is aimed to be a base module that can easily be extended by other modules. It takes care of the heavy lifting that has to be done when working with custom fieldtypes in ProcessWire (injecting scripts and styles, handling JS events, doing translations). See RockTabulator as an example. I'm quite sure more will follow (eg ChartJS)... WHAT? This module helps you injecting ANY php/html/js/css into any PW backend form (either on a page or in custom process modules). It also comes with a sandbox process module that helps you setup your fields and provides handy shortcuts that integrate with TracyDebugger and your IDE: WHERE ...to get it? At the moment the module is released as early alpha and available only on github: https://github.com/BernhardBaumrock/RockMarkup2 If you have any questions or ideas please let me know ? PS: This module shows how easy it is to extend this module for your very own needs. All you need to do is providing the module's info arrays and then overwrite any methods that you have to modify (eg the InputField's render() method): https://github.com/BernhardBaumrock/RockMarkupExtensionExample
- 17 replies
-
- 12
-
-
// example 1: modify page title (runtime) for a specific template in Page Edit Interface $this->addHookBefore('ProcessPageEdit::execute', function($e) { $id = wire('input')->get->id; if (!$id) return; $page = wire('pages')->get($id); if ($page->template != 'specific') return; $page->title = "I am a runtime title for pages using template 'specific'"; }); // example 2: modify fields in Profile $this->addHookBefore('ProcessProfile::execute', function($e) { // not for superuser if (wire('user')->isSuperuser()) return; // the user should check 2 checkboxes in its profile // after checking and saving the related checkbox disappears // if both are checked a markup field 'info' is shown $profileFields = $e->object->profileFields; if (wire('user')->checkbox && wire('user')->checkbox_2) $profileFields[] = 'info'; else { if (wire('user')->checkbox != 1) $profileFields[] = 'checkbox'; if (wire('user')->checkbox_2 != 1) $profileFields[] = 'checkbox_2'; } // update profile fields $e->object->profileFields = array_unique($profileFields); });
-
Nothing is required outside of your module - make your module autoload and use the init() method in your module. The filename is not a property that is saved to the database - it is generated at runtime from the template name, so if you want to set a custom filename then this must be done at runtime. The comment in the Template class is clear about this: @property string $filename Template filename, including path (this is auto-generated from the name, though you may modify it at runtime if it suits your need). #pw-group-files
-
Module Module: RuntimeMarkup Fieldtype & Inputfield
bernhard replied to kongondo's topic in Modules/Plugins
Hey @psy I'd create a custom runtime module, it's not too hard: 1) Create the fieldtype: 2) Create the inputfield: RockMarkup is deprecated because I don't plan to use it as base module for other Fieldtypes in the future. I think it makes things more complicated and that's not worth it. Building custom fieldtypes + inputfields is easy once you know how things work. Especially runtime fields are easy because you don't need all the DB related parts. If you need any help just ask. -
Hi everyone, Processwire is in the following folder in my server: var/www/html/project/processwire I've got the following configuration in my .htaccess: ################################################################################################# # START PROCESSWIRE HTACCESS DIRECTIVES # @version 2.2 ################################################################################################# # ----------------------------------------------------------------------------------------------- # Don't show directory indexes, but do follow symbolic links # ----------------------------------------------------------------------------------------------- Options -Indexes Options +FollowSymLinks # ----------------------------------------------------------------------------------------------- # Let ProcessWire handle 404s # ----------------------------------------------------------------------------------------------- ErrorDocument 404 /index.php # ----------------------------------------------------------------------------------------------- # Handle request for missing favicon.ico/robots.txt files (no ending quote for Apache 1.3) # ----------------------------------------------------------------------------------------------- <Files favicon.ico> ErrorDocument 404 "The requested file favicon.ico was not found. </Files> <Files robots.txt> ErrorDocument 404 "The requested file robots.txt was not found. </Files> # ----------------------------------------------------------------------------------------------- # Protect ProcessWire system files (part 1) # ----------------------------------------------------------------------------------------------- <FilesMatch "\.(inc|info|module|sh|sql)$|^(\..*)$"> Order allow,deny </FilesMatch> # ----------------------------------------------------------------------------------------------- # Override a few PHP settings that can't be changed at runtime (not required) # ----------------------------------------------------------------------------------------------- <IfModule mod_php5.c> php_flag magic_quotes_gpc off php_flag magic_quotes_sybase off php_flag register_globals off </IfModule> # ----------------------------------------------------------------------------------------------- # Set default directory index files # ----------------------------------------------------------------------------------------------- DirectoryIndex index.php index.html index.htm # ----------------------------------------------------------------------------------------------- # ProcessWire requires mod_rewrite # ----------------------------------------------------------------------------------------------- <IfModule mod_rewrite.c> RewriteEngine On # ----------------------------------------------------------------------------------------------- # Set an environment variable so the installer can detect that mod_rewrite is active. # ----------------------------------------------------------------------------------------------- SetEnv HTTP_MOD_REWRITE On # ----------------------------------------------------------------------------------------------- # Optional: Set a rewrite base if rewrites aern't working properly on your server. # And if your site directory starts with a "~" you will most likely have to use this. # ----------------------------------------------------------------------------------------------- # RewriteBase / # RewriteBase /pw/ # RewriteBase /~user/ # ----------------------------------------------------------------------------------------------- # Access Restrictions: Keep web users out of dirs that begin with a period # ----------------------------------------------------------------------------------------------- RewriteRule "(^|/)\." - [F] # ----------------------------------------------------------------------------------------------- # Optional: Redirect users to the 'www.' version of the site (uncomment to enable). # For example: http://processwire.com/ would be redirected to http://www.processwire.com/ # ----------------------------------------------------------------------------------------------- # RewriteCond %{HTTP_HOST} !^www\. [NC] # RewriteRule ^ http://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301] # ----------------------------------------------------------------------------------------------- # Access Restrictions: Protect ProcessWire system files (part 2) # ----------------------------------------------------------------------------------------------- RewriteCond %{REQUEST_URI} (^|/)\.htaccess$ [NC,OR] RewriteCond %{REQUEST_URI} (^|/)(site|site-[^/]+)/assets/(cache|logs|backups|sessions|config|install)($|/.*$) [OR] RewriteCond %{REQUEST_URI} (^|/)(site|site-[^/]+)/install($|/.*$) [OR] RewriteCond %{REQUEST_URI} (^|/)(wire|site|site-[^/]+)/(config|index\.config|config-dev)\.php$ [OR] RewriteCond %{REQUEST_URI} (^|/)(wire|site|site-[^/]+)/templates-admin($|/|/.*\.(php|html?|tpl|inc))$ [OR] RewriteCond %{REQUEST_URI} (^|/)(site|site-[^/]+)/templates($|/|/.*\.(php|html?|tpl|inc))$ [OR] RewriteCond %{REQUEST_URI} (^|/)(site|site-[^/]+)/assets($|/|/.*\.php)$ [OR] RewriteCond %{REQUEST_URI} (^|/)wire/(core|modules)/.*\.(php|inc|tpl|module)$ [OR] RewriteCond %{REQUEST_URI} (^|/)(site|site-[^/]+)/modules/.*\.(php|inc|tpl|module)$ [OR] RewriteCond %{REQUEST_URI} (^|/)(COPYRIGHT|INSTALL|README|htaccess)\.txt$ [OR] RewriteCond %{REQUEST_URI} (^|/)site-default/ RewriteRule ^.*$ - [F,L] # ----------------------------------------------------------------------------------------------- # Ensure that the URL follows the name-format specification required by ProcessWire # ----------------------------------------------------------------------------------------------- RewriteCond %{REQUEST_URI} "^/~?[-_.a-zA-Z0-9/]*$" # ----------------------------------------------------------------------------------------------- # If the request is for a file or directory that physically exists on the server, # then don't give control to ProcessWire, and instead load the file # ----------------------------------------------------------------------------------------------- RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !(favicon\.ico|robots\.txt) # ----------------------------------------------------------------------------------------------- # Optional: Don't send missing image requests to ProcessWire (uncomment below to enable). # This might be helpful if you are launching a new site and lots of images have moved. # It will reduce the load on the server not to have ProcessWire trying to serve those requests. # ----------------------------------------------------------------------------------------------- # RewriteCond %{REQUEST_URI} !\.(gif|jpg|png|ico)$ [NC] # ----------------------------------------------------------------------------------------------- # Pass control to ProcessWire if all the above directives allow us to this point. # For regular VirtualHosts (most installs) # ----------------------------------------------------------------------------------------------- RewriteRule ^(.*)$ index.php?it=$1 [L,QSA] # ----------------------------------------------------------------------------------------------- # If using VirtualDocumentRoot: comment out the one above and use this one instead. # ----------------------------------------------------------------------------------------------- # RewriteRule ^(.*)$ /index.php?it=$1 [L,QSA] </IfModule> ################################################################################################# # END PROCESSWIRE HTACCESS DIRECTIVES ################################################################################################# and the following on my Apache server config: <VirtualHost *:80> ServerAdmin webmaster@localhost DocumentRoot /var/www/html/project/processwire <Directory /var/www/html/project/> Options Indexes FollowSymLinks AllowOverride All Require all granted </Directory> ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined <IfModule mod_dir.c> DirectoryIndex index.php index.pl index.cgi index.html index.xhtml index.htm </IfModule> </VirtualHost> My website opens normally, but when I try something broken like https://mywebsite.com/dfvjdbvknbk it opens a standard apache 404 page and not my custom one. My custom 404 page is inside processwire/site/templates Can anyone help me understand what is broken here? Thanks in advance!