Jump to content

Search the Community

Showing results for 'runtime'.

  • Search By Tags

    Type tags separated by commas.
  • Search By Author

Content Type


Forums

  • Welcome to ProcessWire
    • News & Announcements
    • Showcase
    • Wishlist & Roadmap
  • Community Support
    • Getting Started
    • Tutorials
    • FAQs
    • General Support
    • API & Templates
    • Modules/Plugins
    • Themes and Profiles
    • Multi-Language Support
    • Security
    • Jobs
  • Off Topic
    • Pub
    • Dev Talk

Product Groups

  • Form Builder
  • ProFields
  • ProCache
  • ProMailer
  • Login Register Pro
  • ProDrafts
  • ListerPro
  • ProDevTools
  • Likes
  • Custom Development

Find results in...

Find results that contain...


Date Created

  • Start

    End


Last Updated

  • Start

    End


Filter by number of...

Joined

  • Start

    End


Group


AIM


MSN


Website URL


ICQ


Yahoo


Jabber


Skype


Location


Interests

  1. Fieldtype and Inputfield ImageMarker As of 02 January 2018 ProcessWire versions earlier than 3.x are not supported Version: Stable Project Page: Github Modules Directory: http://mods.pw/Bk OR http://modules.processwire.com/modules/fieldtype-image-marker/ Requires: ProcessWire 2.4 or greater ######################## About This module allows you to easily 'place markers' on an image. Each placed marker's position/coordinates (x and y) are saved in the field as well as the ID of the ProcessWire page the marker refers to. In the backend markers are placed on a specified base image. In the frontend, using each saved page ID you can then retrieve any information you want about the pages being referenced and display that on your website over the same base image you used in the backend. The module is useful for a diverse number of uses including: Product demonstration: place markers on various parts of your product to showcase its features. Using a bit of CSS and/or JavaScript you can create pop-up boxes displaying more information about that feature of the product. The information (in this case, feature), would be information you've stored in some field (e.g. a text field) in the page marker (i.e. the page being referenced by the coordinates). Office locations: place markers on a map showing global offices of a multinational company Points-of-Interest: place markers showing points of interest on a map or location or anything. The coordinates are saved as percentages. This means they will scale well with the image being marked. This module came about as a result of this request. @credits Ryan Cramer: This code borrows from his FieldtypeEvents. @credits Helder Cervantes: Module concept, HTML, CSS, JavaScript. @credits Roland Toth: CSS, Inspiration. API In the frontend, the field returns an array of ImageMarker objects. Each of these has the following properties info (integer): The page ID of the marker (i.e. the page being referenced by the marker. Using this, you can get the referenced page and have access to all its data. infoLabel (String): The title of the page (above) referenced by the marker (runtime only). x (Integer): The x-coordinate of the marker (%). y (Integer): The y-coordinate of the marker (%). You grab the properties as in any other PW field, e.g. $out = '<img src="'. $page->base_image->url . '" alt="">';// image to place markers on 'base_image' is the name of the file field foreach ($page->marker as $m) { // do something with the following properties $m->id;// e.g. $pages->get((int) $m->id); $m->x; $m->y; $m->infoLabel; } // the CSS and HTML are up to you but see InputfieldImageMarker.module for examples Frontend implementation is left to you the developer/designer
  2. Just noticed the recent GitHub commit: and looks intriguing... Any chance of some sample code to illustrate how/where this might be used? Thanks in advance
  3. thanks @bernhard, yes I noticed that later on. I managed to get the module to serve my needs, it's here: https://github.com/dtjngl/MenuAllocator I (re)watched your hook-tutorial, it's interesting but I doubt it can help me in this very use-case since I do not really populate fields on the page and the fields in question are rendered at runtime (by a another hook), so I had a hard time saving the values to the page (luckily there's ->meta). I'm not sure if this is the best approach but it works. @everyone, please give it a try, I'd love to get feedback.
  4. As far as I know (and I haven't used this feature yet!) this should be possible (found here: https://processwire.com/modules/rock-frontend/) You can make use of the addIf() function to load a script only under special circumstances. Adding assets to your site (JS or CSS) While you can always add custom <script> or <link> tags to your site's markup it is recommended that you use RockFrontend's AssetsArray feature: $rockfrontend->scripts() ->add('/path/to/your/script.js') // you can add any custom flags to your $rockfrontend variable at runtime! ->addIf('/path/to/foo.js', $rockfrontend->needsFooScript) ->addIf('/path/to/slider.js', $page instanceof HomePage) ->addIf('/path/to/blogscript.js', $page->template == 'blogitem') ; $rockfrontend->styles() ->add(...) ->addIf(...) ; There are several reasons why this is preferable over adding custom script/style tags: addIf() keeps your markup file cleaner than using if / echo / endif It automatically adds timestamps of files for cache busting You can inject scripts/styles from within other files (eg PW modules) RockFrontend itself uses this technique to inject the styles and scripts necessary for frontend editing (ALFRED). Have a look at the module's init() method!
  5. Oh, specifically for the console. I believe I experienced this once as well. Will try to be more attentive. Hasn't happened since. I am not using any Rock modules currently, though since it's only happened once to me I would lean more toward PC performance over module in my instance. Have you tried a different browser just to see if it's primarily a Chrome (on Mac?) thing? Safari / Firefox... If you have access to a Windows or ChromeOS box, maybe try Chrome there too? Chrome has a task manager. When you notice the issue - assuming you've reduced your Chrome tabs to just the one (?), does the task manager give any additional insight? Similarly, Chrome's DevTools offers a runtime performance monitor (not the same thing as is shown in the above photo)... Just some things to look into.
  6. @da² This way of processing a form with the process() method was introduced in PW 3.0.205, so 3.0.210 would have been the first main/master version to support it. The method wasn't present in 3.0.200, so I'm thinking most likely you were using the processInput() method instead? (example here). But it may not matter, as the process() method is just a front-end to the processInput() method to provide a more convenient API usage, as it returns a true or false as to whether the form was processed without errors. But that distinction is significant for your example. It assumes processing the form is a one-time thing and that you aren't going to manually add errors to the form once it has successfully processed, as identifying errors is part of processing. In your case, you are doing a secondary validation manually, adding errors after the form has processed. That's new to me, but if you find it useful then I'm all for supporting it. With regard to "forever cache", the cache is a request cache, not a forever cache. It is a runtime memory-only cache for the one current request, as presumably the same exact form instance won't be processed multiple times in the same request (or at least shouldn't be). The reason for the cache value is that it has to recursively iterate through every single Inputfield in the form to ask each whether it had any errors. For a large form, it can be enough overhead to warrant caching that information, as the method may get called multiple times in the request and have to repeat the same task. But is it worthwhile enough? Maybe not, given your use case. I'll look into dropping it. When you set an error, it will remain in the session until it is displayed. This is because redirects are often involved in forms, in order to prevent re-post by re-load. Form errors would be lost if they weren't remembered until used. This is because the process() method determines if there are errors and returns true (no errors) or false (errors). The processInput() method does not tell you that information and so you'd have to check for errors manually afterwards. So your first example is checking for errors BEFORE you have manually added an error to it (which is what the process method does, and sets that cache), while your second example checks for errors AFTER you have manually added an error. This is why the results are different. Unrelated, but I recommend putting "<?php namespace ProcessWire;" (or any namespace) at the top of your template file, OR setting $config->templateCompile = false; in your /site/config.php file, just so that PW doesn't attempt to unnecessarily compile your template files. Maybe you are already doing this, but just mentioning it just in case.
  7. So I guess you are calling $page->save() somewhere in that endpoint, right? In that case you can just add whatever runtime property you want to that page and then use that as a flag in your hook: <?php // api endpoint ... $page->isFrontendSave = true; $page->save(); // hook, eg in init.php $wire->addHookAfter("Pages::saveReady", function($event) { $page = $event->arguments(0); if($page->isFrontendSave) { // do something } else { // do something else } });
  8. Runtime-only fields and/or the dashboard module may also be helpful.
  9. I'm glad you asked this! This should be pretty much a drop in replacement. The only thing you'd have to do to upgrade to the new version would be setting the language associations again and transfer any settings (like global excluded strings and API key) in the module config. Upgrading later will not cause any loss of website content and the work for developers should be minimal. The new features are implemented behind the scenes, so you just get more cool stuff ?. ProcessWire makes it possible to change editors between TinyMCE and CKEditor without re-creating the field, so using CKEditor editor now and then switching to TinyMCE later shouldn't cause any headaches. It really should be as easy of a transition as you can get with how well TinyMCE is concurrently being implemented (props to @ryan). As for the module, Fluency doesn't care what field/editor you use or if it's changed at any time because fieldtypes are detected and initialized by JS at runtime when the UI loads, not on the back end. So good news- I don't believe that there is anything that keeps you from using Fluency now and upgrading later. I've been working regularly on the module lately, my goal is this month or next. I think a wildcard will be testing but I'll be requesting help from the community here when it's time. I want this version to be the one that breaks out of alpha. Many thanks and I'll report back here when I have updates.
  10. I have had a play and some of the implementation is literally, trivial ?. SSE SSE is so simple it is unbelievable at first. You only need two things: in our case PHP and a modern browser...batteries included! Example adapted from w3schools. More examples at MDN. server-side <?php namespace ProcessWire; header('Content-Type: text/event-stream'); header('Cache-Control: no-cache'); $time = date('r'); echo "data: The server time is: {$time}\n\n"; flush(); client if(typeof(EventSource) !== "undefined") { var source = new EventSource("/some-processwire/url/"); source.onmessage = function(event) { document.getElementById("result").innerHTML += event.data + "<br>"; }; } else { document.getElementById("result").innerHTML = "Sorry, your browser does not support server-sent events..."; } I tested it and it works fine but was getting errors about wrong mime type if I set the headers later, but that is to be expected. Live Preview Refresh - Partial and Full - ajax - htmx I have this working nicely (will try post the demo later today). The premise is: A change happens. The editor client sends the data to the server to save the change (autosave - was just mimicking this part). Server saves and sends back a response including the name of the field that has been saved and the page ID back to the editor client. The editor client communicates with the preview client (a separate window). It sets the page ID and the name of the changed field name in its message to the preview window. The preview window client (htmx) receives the page id and the name of the field that has changed and sends a request to the server to fetch the rendered contents of that field for that page. The server sends back the html for htmx to swap in the DOM. In this simple communication, we have the field name match the html id of the element we are swapping. E.g. <h2 id='headline'>My Headline</h2> This is simple and straightforward and easily achieves partial refresh. However, it will be difficult to handle the more complex cases I mentioned in my previous post. It will also be somewhat dictating how the developer should name their html attributes. In addition, it still leaves the developer's templates with htmx attributes that will not be needed in production. This got me thinking. Live Preview Wrapper - idea #1 In this case, the live preview window would add a wrapper html element around the rendered template file markup. The wrapper html element would have the htmx attributes instead of the template file markup. This idea didn't go very far. It would inevitably lead to broken / incorrect markup in the preview window as the outermost markup of the template file would be <html> tags. In addition, while it solves the problem of unrequired htmx attributes in production, it doesn't solve the problem of selective rendering. It still wouldn't' know what parts of the markup in the preview window to swap. Live Preview Config - idea #2 What if instead of live preview / ProcessWire suggesting things like naming of elements, standard markup, etc. that are needed in a template file in order to get selective markup rendering, we implemented it the other way round? What if the developer instead, via config file(s), passed properties to live preview to implement the htmx attributes needed for a template file / page? The default would be full page refreshes. However, if live preview detected that a partial refresh config was available, it would implement those. This would offer the granularity needed for partial refreshes. If live preview did not receive / detect any configs, the default would kick in. Live preview would remain as agnostic as possible. It could be something like this (assumes use of htmx): A developer places their live preview partial refresh configs in /site/templates/live-previews/basic-page-live-preview.php (or basic-page-live-preview.json). ProcessWire detects that the template file basic-page has a partial refresh config in .../live-previews/basic-page-live-preview.php When ProcessWire loads the preview window, it injects the htmx attributes for each named element in the live preview configs in the corresponding elements in the preview window DOM. Injection is done by a ProcessWire live preview near-agnostic JavaScript script that only runs in the preview window. When the autosave happens in the editor window and the preview window gets informed, htmx kicks in, responding to an event and fires htmx.trigger(elem, event). The element in the markup with the corresponding event listener (hx-trigger='this-element-event-fired') will pick up the event fired by htmx.trigger() and query the server for the changed markup. The attributes set in #3 will ensure only the markup that has a change will fire. Server sends the response back and the element's hx-swap (or even hx-oob) picks it up and swaps the DOM. #6 is still not straightforward though. What will live preview / ProcessWire send back? Here too the config at #1 can help. E.g. it can tell ProcessWire to send <p>My Field Value</p> or just send the value of the field back, i.e. 'My Field Value'. The former is still complicated. Instead of telling ProcessWire I want <p>My Field Value</p>, how about tell it, via the configs at #1 that if requested field is field A, send me back the raw value (e.g. a plain text) but if the request is for field B, use this defined function in basic-page-live-preview.php to send me the rendered partial markup for field B? All ProcessWire would do is pass the value of field B to the said function. This value could be a Pageimages object. The function would iterate the images and send back the 'gallery' markup back to htmx to swap. example live preview config <?php namespace ProcessWire; $livePreviewConfigs = [ [ 'field' => 'headline', 'element_id' => 'my_headline_element_id', 'htmx-attributes' => ['hx-swap' => 'outerHTML', 'hx-trigger' => 'headlineevent'] ], [ 'field' => 'images', 'element_id' => 'gallery', 'handler' => 'renderGallery','htmx-attributes' => ['hx-swap' => 'innerHTML', 'hx-trigger' => 'galleryevent'] ], ]; function renderGallery(Pageimages $images) { // we only need the <li> since we are using innerHTML swap // the target element is <ul id='gallery'></ul> // -------------- $out = ""; foreach ($images as $image) { $thumb = $image->size(200, 200); $out .= "<li><img src='{$thumb->url}' alt='{$image->url}'></li>"; } // --------- // sent back to htmx to swap return $out; } When the preview window loads, ProcessWire sends $livePreviewConfigs to the browser, e.g. ProcessWire.config.LivePreview. The preview window JavaScript would consume it like this: client set htmx attributes @note: JavaScript written in the browser, not tested, could have errors. // get live preview configs const elementsConfigs = ProcessWire.config.LivePreview // loop through configs, find the corresponding element and set their htmx attributes for (const elementConfig of elementsConfigs) { const element = document.getElementById(elementConfig.element_id) if (element) { const htmxAttributes = elementConfig['htmx-attributes'] for (const [prop, value] of Object.entries(htmxAttributes)) { element.setAttribute(prop,value); } } } htmx-ready DOM changes via live preview injection (runtime only in live preview window): <h2 id="my_headline_element_id" hx-swap='outerHTML' hx-trigger='headlineevent' hx-vals='{"field":"headline"}'>My Headline</h2> <!-- gallery --> <ul id="gallery" hx-swap='innerHTML' hx-trigger='galleryevent' hx-vals='{"field":"images"}'> <li><img src='image-1-src' alt='image-1-alt'></li> <li><img src='image-2-src' alt='image-2-alt'></li> </ul> I have partly implement the above (just hard-coded configs for now) and it works nicely. Takeaways ProcessWire's live preview remains as agnostic as possible. Developer give instructions to live preview (via configs) and not the other way round. Live preview ships with minimal defaults, including full page refresh. It seems like a lot of work on the developer's part if they want partial refresh. However, this partly matches the complexity of their template files. Besides, some of the functionality (e.g. renderGallery()) could be something they already use in their template, hence reusable. Developer does not need to have additional markup in their template files in order to see live previews when editing. This means no cleaning up afterwards. Their templates remain clean. Live preview only alters the DOM (of the rendered template) at runtime. Developer can name their markup attributes as they wish. Developer can decide what needs live preview and what doesn't, even on the same page (e.g. hx-select). ProcessWire stays out of the developer's way, as usual.
  11. I use RockFinder together with runtimemarkup-module https://processwire.com/modules/fieldtype-runtime-markup/ to display various page-data in the backend for the content-superusers. There are also some tables in the database that are non-processwire-tables, which I would like to display with RockFinder (if it is possible?). There is my code in the markup-field (it is working): $modules = $this->wire()->modules; $rockfinder = $modules->get("RockFinder3Master"); $rf = $rockfinder->find("template=categories")->addColumns(['id', 'title', 'created']); ob_start(); $rf->dump(); $result = ob_get_clean(); return (string)$result;
  12. Media Manager Released 31 March 2016 https://processwireshop.pw/plugins/media-manager/ Documentation http://mediamanager.kongondo.com/ As of 10 May 2019 ProcessWire versions earlier than 3.x are not supported ******************************************************* ORIGINAL POST ******************************************************* API Example (frontend; will be added to documentation site) Accessing and outputting the contents of the MediaManager field(s) in your template is quite simple. The fields are accessed like many other ProcessWire fields. The fields return an array of type MediaManagerArray that need to be looped to output each media within. Assuming you created a field of type MediaManager named 'media', you can loop through it for a given page as shown below. @note: Each MediaManager object has the following 5 basic properties: DATABASE (saved properties) 1. id => pageID of the page where the media lives (hidden in admin and not important to know about) 2. type => integer denoting media type (1=audio; 2=document; 3=image [for variations this will be 3x, where x is the number of the variation of an original image]; 4=video) RUNTIME 3. typeLabel => user friendly string denoting media type (audio, document, image, video) 4. media => a ProcessWire Image/File Object including all their properties (ext, filesizeStr, height, width, description, tags, filename, basename, etc.) 5. title => title of media (@note: this is the title of the page where the media lives; may or may not be the same as the name of the media file itself). This can be used as a user-friendly name for your media $media = $page->media;// returns a MediaManagerArray. Needs to be looped through foreach ($media as $m) { echo $m->id;// e.g. 1234 (hidden page in /admin/media-manager/media-parent/) echo $m->type;// e.g. 3 (a media of type image) OR 1 (a media of type audio) echo $m->typeLabel;// e.g. 'document' (i.e. type would be 2) echo $m->title;// e.g. 'My Nice Trip' (whose media file could be my-nice-trip.mp4) /* @note: - $m->media returns an object; either a ProcessWire Image (for image media) or File object (for audio, document and video media) - This means you have access to all the properties of that object, e.g. ext, tags, description, url, filename, basename, width, height, modified, created, filesize, filesizeStr, etc as well as associated methods, e.g. size() */ echo $m->media->tags; } // only output images foreach ($media as $m) { if($m->typeLabel =='image') { echo "<img src='" . $m->media->size(100,75)->url . "'><br>"; } } // There's also a toString() method so you can do: echo $page->media; /* All your media will be output wrapped in appropriate HTML tags, i.e.: audio: <audio></audio>; document: <a></a>; image: <img>; video: <video></video>; */ ******************************************************* ORIGINAL POST ******************************************************* The topic of a central media manager feature for ProcessWire has come up several times: https://processwire.com/talk/topic/4330-get-image-from-other-pages-via-images-field/ https://processwire.com/talk/topic/4330-get-image-from-other-pages-via-images-field/?p=42578 https://processwire.com/talk/topic/4330-get-image-from-other-pages-via-images-field/?p=42582 https://processwire.com/talk/topic/425-file-manager/ https://processwire.com/talk/topic/425-file-manager/?p=13802 https://processwire.com/talk/topic/425-file-manager/?p=13861 https://processwire.com/talk/topic/10763-asset-manager-asset-selector/ More recently, regarding my Visual Page Selector module, I have been asked several times why the module does not have an in-built feature to upload images. There's two camps on the topic of a central media manager: those who like them (especially those coming in to PW from other CMSes) and those who don't like them (primarily because of the chaotic way some CMSes (dis)organise their media management) . I think that we can have our cake and eat it too! If done the right way, closely following the principles of and harnessing the power of ProcessWire, we can have a well-implemented, organised, feature-rich, site-wide media manager. Introducing Media Manager: (a commercial module) Alongside a number of modules I am currently working on (both free and commercial), I have been developing a centralised Media Manager for ProcessWire. Before you cast the first stone, no, this is not going to be a one-large-media-bucket as in other CMS where it gets very messy very quickly . In the backend things are neatly stored away, yes, in pages. However, those are pages you will not see (just like repeater pages). Before anyone has a go at pages, remember a page is not that thing you see on the ProcessWire Tree (that's just its visual representation); A page is a record/row in the database . For the end-user of Media Manager, all they will see is the 'familiar media bucket' to select their media from. As long as it works efficiently, I don't think they care about the wizardry behind the scenes . The module allows for the comprehensive management of several media types: Audio Video Images Documents Each media type will be handled by its own sub-module so the user can pick and install/choose the type of media management they want. Features include: Access controls Centralized uploads of media Bulk management of media: tag, delete, describe, replace, etc. Bulk upload: zip; scan, single Quick upload in page edit mode Usage stats across pages (maybe?) Etc.. Would love to hear your thoughts and any feature suggestions. I think there's enough demand for such a module. If not, please let me know so that I can instead focus on other things , thanks. How other CMS do it The more efficient (PW) way of doing it
  13. Here's my complete work-round for the problem with runtime markup images in a Page Table field. Something that prevents the problem occurring in the first instance would be better though! 1. Add the following condition for images rendered in the runtime markup: if (is_a($image, '\ProcessWire\Pageimage')) $out .= '<img src="' . $image->url . '"/>'; 2. Add the following to admin.js (the 2 functions are lifted from InputfieldPageTable.js): /*******************************************************************************************************************/ /* Work-round to reload and re-enable sorting of Page Table field, which includes runtime markup, after modal edit */ /*******************************************************************************************************************/ $(document).on('pw-modal-closed', function(event) { var wrap = $(this).find('.InputfieldPageTable'); if ($(wrap).attr('id')) $('#' + wrap.attr('id')).load(document.URL + ' #' + wrap.attr('id') + '> *'); // To just load the inner html of wrap - avoiding duplicating it }); $('.InputfieldPageTable').mouseenter(function () { if (!$('tbody').hasClass("ui-sortable")) { var $table = $('tbody').closest('table'); InputfieldPageTableSortable($table); } }); function InputfieldPageTableUpdate($table) { var value = ''; if(!$table.is('tbody')) $table = $table.find('tbody'); $table.find('tr').each(function() { var pageID = $(this).attr('data-id'); if(value.length > 0) value += '|'; value += pageID; }); var $container = $table.parents('.InputfieldPageTableContainer'); var $input = $container.siblings('.InputfieldPageTableSort'); $input.val(value); } function InputfieldPageTableSortable($table) { $table.find('tbody').sortable({ axis: 'y', start: function(event, ui) { var widths = []; var n = 0; $table.find('thead').find('th').each(function() { widths[n] = $(this).width(); n++; }); n = 0; ui.helper.find('td').each(function() { $(this).attr('width', widths[n]); n++; }); }, stop: function(event, ui) { InputfieldPageTableUpdate($(this)); } }); } /*******************************************************************************************************************/
  14. Okay understood. About the dev environment, I must say that it's not intended to change your habits. For example, my usual directory structure of my web folder containing the index.php/site/wire is the following: . └── /var/ └── html └── example.com ├── build/ssr/ssr.js <-- run by NodeJS on the server ├── wwwroot <-- directory sent to server hosting │ ├── site │ │ ├── modules │ │ │ └── ViteJS │ │ ├── assets │ │ │ └── static <-- contain assets built by vite │ │ │ ├── layout.abc123.js │ │ │ ├── home.abc123.js │ │ │ ├── about.abc.123.js │ │ │ └── ... │ │ ├── ... │ │ └── templates │ │ ├── _func.php │ │ ├── home.php │ │ └── about.php │ ├── wire │ ├── index.php │ └── .htaccess ├── src <-- development directory & files │ ├── styles │ │ └── app.scss │ └── js │ ├── components │ │ ├── Button.svelte │ │ ├── Hero.svelte │ │ └── ... │ ├── pages │ │ ├── Home.svelte │ │ ├── About.svelte │ │ └── ... │ ├── app.ts │ └── ssr.js ├── .env ├── package.json ├── vite.config.ts ├── tailwind.config.cjs ├── tsconfig.json └── ... The structure can be tweaked as you want. In this example, I'm using TailwindCSS, and Svelte. When developing, the result in your browser will be refreshed when you will save the modified file (it's called HMR for Hot Module Replacement). The same thing will happen when you will modify your ProcessWire templates files. In dev mode, files are served by the vite's local dev server. About your question about the "autobuild", with Vite you have basically three commands. Take a look at the following scripts section of a package.json file: "scripts": { "dev": "vite", "build": "vite build", "preview": "vite preview" }, When you will run `npm run dev` for example, vite will start the development server, the build command will build the production files, and the preview command will start a local server to serve the built production files. You are free to set up any workflow you are interested in, for example like throwing a build on each HMR event (I've given an example about that on stackoverflow, see https://stackoverflow.com/a/69632090/774432). On my side I am mostly working with private servers, but behind the scene the workflow is quite "the same". On my server, I run on closed environment a simple node command `node ../build/ssr/ssr.js` , where eg. on Vercel, you will want to use their Node.js Runtime features through an API. As I said, you can keep your habits in terms of editing content, let them log in ProcessWire backend and filling their body field. The update/preview is just a matter of refreshing or changing page on the site you are working on. The change is dynamic, you are not required to build or commit any change, and as always, you keep the freedom to make only the content you decide to be available - it's a bit , I made you an example on the bottom of the post. I do not use it and I don't remember how it works, but if you can pull data without markup, then all is ✅ even with markup it should work. I will test it. Enregistrement #52.mp4
  15. Ok great, I thought I might be missing something, which can easily happen if you don't use the "regular" approach any more ? For me the runtime approach in general is a huge benefit. Once you start defining things in code all the little details that you would usually avoid because the GUI does not support it suddenly become a no-brainer and very easy to add. All the little customisations that you'd usually need a hook or a module for. They are simply there in your pageclass and you start to develop the backend (page editor) similar to how you'd develop your frontend. <?php public function editForm($form) { if ($f = $form->get('title')) { $f->appendMarkup(" <div>Custom field markup without any hooks...</div> <style>#wrap_Inputfield_title {border: 5px solid red;z-index:1;}</style> <script>console.log('js-demo');</script> "); } } PS: Note that this code will only be added on the page editor of pages having the pageclass where you defined your editForm() method! So if you added that in HomePage.php you'll only get the red border on the "home" page ?
  16. @bernhard At https://github.com/baumrock/RockMigrations#working-with-fieldsets you have e nice description on how to work with fieldsets. This seems to be limited to adding fields to fieldsets at runtime. Is there a way how we can define a migration that puts fields inside a fieldset in template context? Something like 'content-page' => [ 'tags' => 'content', 'fields' => [ 'title' => [ 'label' => 'Page Title', ], 'text' => [ 'label' => 'Subtitle', ], 'content_blocks' => [], 'tab' => [], // this adds the fieldsettab open and close 'fieldname' => [] // how to add this one to the tab fieldset ], It works fine with with $rm->addFieldToTemplate('fieldname', 'content-page' , 'tab', 'tab_END'). Just wondering if it is possible to do this inside the fields array in my example above.
  17. I imagine this may also be achieved without an additional database field using FieldtypeRuntimeMarkup: https://processwire.com/modules/fieldtype-runtime-markup/
  18. Condition is/should be attached to store_template pages. So one store could have one entry "Type1" and another store could have multiple types ("Type2", "Type3"). There's no field yet for it, but it could be anything (simple text field, multi select field, page ref...). The condition to search for "Type1" comes from external at runtime, of course. But the more I think about it, the less likely it seems to be a good solution for database level search.
  19. Ah this looks like its exactly what im looking for. ? Can I just ask, did you get that code to work in order to take that screenshot, as I am getting a null error on the last line. Just curious of your field settings for the runtime fieldtype in this instance incase I need to ammend mine to get the same result.
  20. teppo

    Wireframe

    Just released Wireframe 0.7.0. This version is all about caching: when requesting Controller methods from view (<?= $this->some_controller_method ?> etc.) the return value is now cached (runtime cache). Additionally if method names are added to protected $cacheable_methods property of the controller class, along with an applicable expire time (i.e. "protected $cacheable_methods = [ 'method_name' => 3600 ]"), Wireframe automatically caches the value using WireCache (persistent cache). Caching is usually a good thing, but not always preferred, which is why runtime caching can be prevented by adding the method name to (protected) Controller property $uncacheable_methods (protected $uncacheable_methods = [ 'method_name' ]). Persistent caching is always opt-in. Changelog: ### Added - Runtime caching support for Controller method return values. Values are cached *unless* the name of the method is found from Controller::$uncacheable_methods. - Persistent caching support for Controller method return values. Values are cached only when found from the Controller::$cacheable_methods array. ### Changed - In the View class all internal requests for Controller properties are routed through View::getFromController().
  21. 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:
  22. 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.
  23. @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(); });
  24. @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:
  25. 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 #################################################################################################
×
×
  • Create New...