Leaderboard
Popular Content
Showing content with the highest reputation on 07/12/2023 in all areas
-
The KKP.LAW site has been a Site of the Week in Processwire Weekly in the past. For this reason I would like to share some insights. So I hope someone will get an inspiration and maybe others may provide idees how to improve my process. Development Setup Currently I build my projects with DDEV and upload them to the server using Github Actions. This way I can view and develop them locally and push them to live when I am done. I also have SCSS which I write to a src folder and is watched by DDEV and also by the GitHub action. So it is possible to change SCSS via a browser in GitHub and everything will be deployed automatically. The basics The KKP.LAW was the last project before I develop this orocess with modules. But the basics are almost the same. Years ago I used Typo3 for building websites. But the really complex update routine, the complicated configuration and the ongoing change how you should build templates made it necessary for me to look for a new CMS. So Wordpress was never an option and many others were also very complicated, so I looked at ProcessWire. After a second look I really understood the approach and built my first websites with Processwire. Very quickly I switched from Typo3 to Processwire. Implementing new features into existing websites was so easy with it. But one thing I really liked in Typo3 was the concept of pages and page content. On each page you can have multiple page contents. I.e. text or images or a mix of both. So I started to rebuild this logic in Processwire. I have templates for pages and templates for page contents. I use a page and pagecontent tag for the different types. On the PHP templates I just need to include them. So each page collects its page content children. All page contents can have a wrapper with some css classes. So it is easy to create layouts with this system. CSS Framework For this I use a kind of own CSS framework which is much more individual than big ones like Bootstrap. Personally I like the concept of 10 columns. So I have a 10 + 4 + 3 column system. Paddings are always added inside a column. So I dont need rows. All page content is inside a div tag with display: flex; flex-wrap: wrap;. The result is very clean and I get a slim file sizes. Components Later I changed the page content more into components. They are not as powerful as in modern JavaScript framework. It was more a logical step for me. In my eyes, the massive classes I would need to build responsive websites always displeased me. So more and more I changed my approach to design and configure everything in a component with maybe one or two classes and do the rest in CSS. But in some cases the old approach is still good. Current approach So I made some modules for my basic needs. The current module is very personal build arrount my needs and my DDEV configuration. Each component (or page content) has its own module. So it has some methods, PHP template and basic scss which I bind into my deployment process. I wrote a bash script that sets up ddev, installs Processwire and these modules. Also creates a GitHub brunch with the required action that can be synced into a live server. - So this is a basic overview of my approach. Hope it is an inspiration for you. Questions and suggestions are very welcome. See Website: KKP.LAW My own website: (also Processwire) Jens Weigel – Büro für Design7 points
-
I just took a look at the source code and saw that in WireFileTools::render() all variables are added to data() of the rendered TemplateFile. You can get an array of the variables in your rendered file by $this->data(). Docs for data(): https://processwire.com/api/ref/wire-data/data/3 points
-
On the template: (you see the module approch) getComponent gets all allowed page components, loads it template files, wraps it if needed. Every component has a wrapper builder where I can choose what css class it will use. this will wrap this component into <div class="hero"> <div class="heroinner"> {COMPONENT-CODE} </div> </div>3 points
-
The problem I had was with the way I was using the head-support extension. I was using the "merge" behavior instead of the "append" behavior. Merging would destroy all Tracy injected code that it placed in <head>, but appending preserves it. Appending leaves a bit of extra HTML behind after HTMX does its merge, but it doesn't affect how a page gets rendered or lead to incorrect results.2 points
-
I completely agree with @dragan. The response from your developer doesn't make any sense. Assuming the request actually works correctly, you can use WireHttp which is part of the PW core and has a much nicer interface (and in the end, is a wrapper for curl).2 points
-
Let me start with this: No matter what your goal is, allowing unmoderated edit access to your page is never a good idea! With guests, do you really mean not-logged-in users? Assuming you mean "specific people with a login", why not let them use the backend and all of the tools available there to accomplish this task? You can introduce a new Role and limit that to just being able to edit whatever pages you need them to. With this approach, you do not have to be concerned about validating and sanitizing your form which in turn is another possible weak spot in itself. If not, there is the PRO Module "FormBuilder" which might come in handy in your case. It particularly lets you create pages from form submissions (even unmoderated). With it's hookable interface, you can add whatever functionality you need.2 points
-
Yes of couse All pages with white background are pages. The grey background are page contents. So I have an easy way to rearrange, move or extend. The warm grey sections is for header and Footer wich works in the same way as the pages. So it can have page content like logo or navigation. So you see the main Page "Kanzlei" have 6 page contents. The hero, a text component, the Expertise with some sub pages, Team, News and Events. In this case all of these have subpages. Other example: (Schreinerei Merte) You see a Wrapper wich just create a wrapping div around some kind of content. Output:2 points
-
Is https://path.to.API.endpoint another PW instance? Or completely unrelated to your PW site? I would first try the basics: Make a manual request with something like Postman and see if it works at all. Delete all your cookies from the API endpoint domain. The response from the developer is somewhat confusing, and doesn't make sense. If you can't even get a response from the API due to a server error 400, you also can't deliver a PDF.2 points
-
I already asked him an will let you know what he says1 point
-
I was going to suggest it. Unfortunately, I don't own it I think as I have the very first version. I will take a look. But you could ask Ryan directly. Playing with InputfieldImage and InputfieldFile from frontend is not trivial, as is. If you do not get an answer, I will come back to this thread once I get my hand on the module source-code. Edit: Just in case, you can also implement a custom form for files (https://gist.github.com/jacmaes/6691946) and play with a bit of JS to render things dynamic. And to generate random links, you can take a look at this (I am still using it, even if the module is born almost ten years ago: https://github.com/plauclair/FieldGenerator)1 point
-
I don't know if that can help you, but on my project, backend side, I hide all pages that a user can't edit, with this hook: /** * In PW admin, hide pages that user can't edit. */ $wire->addHookAfter('Page::listable', function (HookEvent $event) { /* @var Page $page */ $page = $event->object; if ($page->path == "/") $event->return = true; else $event->return = wire()->user->hasPermission("page-edit", $page); }); There is no impact on the frontend side.1 point
-
Then you could restrict access to the "Pages" page by using the example provided by @Wanze here. In much the same way, you could hook Page::editable to only allow pages be edited which belong to the user. Further the link provided in your email would then be like https://youdomain.com/adminurl/page/edit/?id=pageId Like that your quasi-guests are locked out of seemingly the whole backend. Another possibility is to add all the fields to their user profile and add only profile-edit capability. This will show an empty backend with a "edit profile" button. And the url in the email then needs to be https://youdomain.com/adminurl/profile1 point
-
An update on this as I now know what the problem is... If using TracyDebugger with HTMX's head-support extension, TracyDebugger's bar will become "unstyled" when doing an htmx-style request. This happens because the CSS that TracyDebugger uses to style the bar gets stripped-out with that extension (since it's in the <head> and the two don't play nicely with each other). I will follow up with a solution if I'm able to find one.1 point
-
OP wants to use InputfieldImage in the frontend with all the bells and whistles to interactively edit a FieldtypeImage field. Problem is, all the infrastructure provided by ProcessWire assumes a login session.1 point
-
Same error for me, it ended up being a attempt to connect with http instead of https.1 point
-
but if you want to move a page content to a other page you need some extra modules. I guess it is a personal flavor how to do ?1 point
-
Well in this case, ProcessWire won't give you an out-of-the-box solution. Other things coming to mind are PageFrontEdit (bundled with PW) but this also only works with an active login session. You would need to use a frontend component to handle the user interaction and also handle the backend on your own. Nonetheless, you are opening almost direct edit capability to anyone but must reimplement everything the PW backend would offer you for free. Also note that "not knowing a direct edit link" doesn't infer security or authentication. You are still adding backend edit capabilities to the frontend without any form of access control. The sheer existence of such a function is a big security hole. And on top of all this, file uploads. I strongly advise against this!1 point
-
Hello, Documentation of this module is here: https://processwire.com/api/ref/textformatter-markdown-extra/ You can do something like: modules('TextformatterMarkdownExtra')->format($text);1 point
-
1 point
-
Hello @ngrmm I am sorry, but this does not work out of the box, but if you want to display a default image if no image was uploaded, you can do it the way as explained here: https://processwire.com/talk/topic/18761-solved-when-default-field-value-is-an-image-file/?do=findComment&comment=163685 Best regards1 point
-
Please be patient - I will add surrounding tags for the dayname and the time(s) for that day, so you will be more flexible. The tags will be variable, so you can choose if you want fe dt and dd or div and span or whatever. The other tags (ul and li) should be also flexible, so you could change them to your needs. Every tag should also be disabled by adding false instead of a tag name - thats my plan. Maybe I can bump up the version with the changes today - we will see ?1 point
-
This would be awesome! I was afraid you would say that, yet I almost knew it. On the other hand I wanted to mention such an addition for your fieldtype. Since my last post I tried a few things more and there is another thing I found... would it be somehow possible to wrap days and times in individual <span>s or define a dl instead of an ul? My goal is to make it look like a table, which is not possible right now - besides using the array version, which isn't that handy - but would work probably. On the other hand... your JSONLD output example is absolutely perfect for what I can tell right now.1 point
-
I see. I'll have a think about how devs can pass configs to the Stripe payment element. I think you should also confirm with Stripe/authorities that removing those fields will not go against the regulations for your country (including your customers' countries).1 point
-
Hello @wbmnfktr Thanks for your post! No, not at the moment, but this seems to be a useful feature to implement. I will try to add a new field to the field configuration, where you can choose, if you want to display the holiday field or not.? This is where the things starts going complicated - I guess this is not really easy to implement. You have to create a field containing all exceptions. This is not what can be achieved very easily, so I guess this feature will not be realized. Best regards1 point
-
That sounds like the correct result. 1500 is greater than or equal to 1000 and less than or equal to 5000. That use of the pipe isn't valid selector string syntax. The pipe is used as an OR operator within the value... firstname=Mike|Steve ...or within the field... body|sidebar*=carbonated But in the example you give you would need to use OR groups. And as Ryan mentioned earlier you will want to use the @ operator too because you want conditions like "price_list.procedure_price>=1000, price_list.procedure_price<=5000" to be matched within a single repeater item, not a staff_profile page that has one price_list item where procedure_price>=1000 and a different item where procedure_price<=5000. template=staff_profile, staff_location=1119, (@price_list.procedure_price>=1000, @price_list.procedure_price<=5000), (@price_list.procedure_price>=10000, @price_list.procedure_price<=15000)1 point
-
Hi, I think you can make it easier without dealing with 404 hook. You should give a read at this blog post about new URL hooks: https://processwire.com/blog/posts/pw-3.0.173/#new-type-of-hook-for-handling-request-urls1 point
-
1 point
-
Edit: Because of the great response to this topic I wrote a guest blogpost: https://processwire.com/blog/posts/building-custom-admin-pages-with-process-modules/ One of the hidden treasures of processwire seems to be the creation of custom admin pages. Technically speaking those pages are ProcessModules - but i guess that's the reason why so many people out there seem to be afraid of building them... it sounds so hard! You've never created a module for ProcessWire? You have never created a plugin for any other CMS? You have no clue about OOP with all its classes, methods and properties? No problem! I'll show you how simple you can start: <?php class CustomAdminPage extends Process { public static function getModuleinfo() { return [ 'title' => 'Custom Admin Page Example', 'summary' => 'Minimalistic ProcessModule to show that nobody has to be afraid of building custom admin pages.', 'href' => 'https://processwire.com/talk/topic/17709-how-to-create-custom-admin-pages-aka-processmodules-yes-its-that-simple/', 'author' => 'Bernhard Baumrock, baumrock.com', 'version' => 1, // page that you want created to execute this module 'page' => [ 'name' => 'customadmin', // your page will be online at /youradmin/setup/customadmin/ 'parent' => 'setup', 'title' => 'Custom Admin Page Example' ], ]; } public function ___execute() { return 'This is the most simple Admin-Page you have ever seen :)'; } } Now save this file as CustomAdminPage.module and place it in your /site/modules folder. After a refresh it will show your module in the modules manager of your site where you can install it: After installation you already have your first very own admin page! Congratulations! Was not too hard, was it? It's as simple as that! Now lets add some more custom HTML. And to show you another nice feature we will add this code to a separate method called executeDemo(). And because everything is so simple we will also add some javascript to this page public function ___executeDemo() { $out = ''; $out .= '<h1>H1 has some special css styling in the admin, thats why it seems to have no effect</h1>'; $out .= '<h2>H2 looks different ;)</h2>'; $out .= '<h3>...and so does H3</h3>'; $out .= '<button onclick="myFunction()">Click me</button>'; $out .= '<script>function myFunction() { alert("this is a demo javascript"); }</script>'; return $out; return ''; } Now thanks to ProcessWire-magic your page will already have its own URL: Just append /demo to your url and see what you get: And of course don't forget to click the button Ok, now that code looks a bit hacky, right? Inputfields and especially InputfieldMarkup for the win! We add another method with some advanced code. To use inputfields we need a form that holds all those inputfields and that makes it possible to handle user input lateron. See somas great tutorial about forms here for a quickstart and more details: public function ___executeAdvanced() { $out = '<h2>A more complex Example</h2>'; $form = wire()->modules->get('InputfieldForm'); $field = wire()->modules->get('InputfieldMarkup'); $field->label = 'Markup Test 1'; $field->value = '<h1>h1</h1><h2>h2</h2><h3>h3</h3><h4>h4</h4>'; $form->add($field); $out .= $form->render(); return $out; } Ok, it get's boring Let's do something more fun and add a chart in a second field and change the fields to 50% screen width (I'm sure you know that already from the GUI template editor)! public function ___executeAdvanced() { $out = '<h2>A more complex Example</h2>'; $form = wire()->modules->get('InputfieldForm'); $field = wire()->modules->get('InputfieldMarkup'); $field->label = 'Markup Test 1'; $field->value = '<h1>h1</h1><h2>h2</h2><h3>h3</h3><h4>h4</h4>'; $field->columnWidth = 50; $form->add($field); $field = wire()->modules->get('InputfieldMarkup'); $field->label = 'Chart Sample'; $field->value = '$chart'; //$field->notes = 'Example code taken from here: http://www.chartjs.org/docs/latest/getting-started/usage.html'; $field->columnWidth = 50; $form->add($field); $out .= $form->render(); return $out; } OK, we are almost there... we only need to add the chart library! To keep everything clean we will put the code for the chart in another method. We will make that method PRIVATE to add some security. Our new Method: private function renderChart() { // prepare chart code wire()->config->scripts->add('https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.1.3/Chart.min.js'); ob_start(); ?> <canvas id="myChart"></canvas> <script> var ctx = document.getElementById("myChart"); var myChart = new Chart(ctx, { type: 'bar', data: { labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"], datasets: [{ label: '# of Votes', data: [12, 19, 3, 5, 2, 3], backgroundColor: [ 'rgba(255, 99, 132, 0.2)', 'rgba(54, 162, 235, 0.2)', 'rgba(255, 206, 86, 0.2)', 'rgba(75, 192, 192, 0.2)', 'rgba(153, 102, 255, 0.2)', 'rgba(255, 159, 64, 0.2)' ], borderColor: [ 'rgba(255,99,132,1)', 'rgba(54, 162, 235, 1)', 'rgba(255, 206, 86, 1)', 'rgba(75, 192, 192, 1)', 'rgba(153, 102, 255, 1)', 'rgba(255, 159, 64, 1)' ], borderWidth: 1 }] }, options: { scales: { yAxes: [{ ticks: { beginAtZero:true } }] } } }); </script> <?php return ob_get_clean(); } Now we just need to call $this->renderChart() in the right place! Here is the complete Module: <?php class CustomAdminPage extends Process { public static function getModuleinfo() { return [ 'title' => 'Custom Admin Page Example', 'summary' => 'Minimalistic ProcessModule to show that nobody has to be afraid of building custom admin pages.', 'href' => 'https://processwire.com/talk/topic/17709-how-to-create-custom-admin-pages-aka-processmodules-yes-its-that-simple/', 'author' => 'Bernhard Baumrock, baumrock.com', 'version' => 1, // page that you want created to execute this module 'page' => [ 'name' => 'customadmin', // your page will be online at /youradmin/setup/customadmin/ 'parent' => 'setup', 'title' => 'Custom Admin Page Example' ], ]; } public function ___execute() { return 'This is the most simple Admin-Page you have ever seen :)'; } public function ___executeDemo() { $out = ''; $out .= '<h1>H1 has some special css styling in the admin, thats why it seems to have no effect</h1>'; $out .= '<h2>H2 looks different ;)</h2>'; $out .= '<h3>...and so does H3</h3>'; $out .= '<button onclick="myFunction()">Click me</button>'; $out .= '<script>function myFunction() { alert("this is a demo javascript"); }</script>'; return $out; return ''; } public function ___executeAdvanced() { $out = '<h2>A more complex Example</h2>'; $form = wire()->modules->get('InputfieldForm'); $field = wire()->modules->get('InputfieldMarkup'); $field->label = 'Markup Test 1'; $field->value = '<h1>h1</h1><h2>h2</h2><h3>h3</h3><h4>h4</h4>'; $field->columnWidth = 50; $form->add($field); $field = wire()->modules->get('InputfieldMarkup'); $field->label = 'Chart Sample'; $field->value = $this->renderChart(); $field->notes = 'Example code taken from here: http://www.chartjs.org/docs/latest/getting-started/usage.html'; $field->columnWidth = 50; $form->add($field); $out .= $form->render(); return $out; } private function renderChart() { // prepare chart code wire()->config->scripts->add('https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.1.3/Chart.min.js'); ob_start(); ?> <canvas id="myChart"></canvas> <script> var ctx = document.getElementById("myChart"); var myChart = new Chart(ctx, { type: 'bar', data: { labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"], datasets: [{ label: '# of Votes', data: [12, 19, 3, 5, 2, 3], backgroundColor: [ 'rgba(255, 99, 132, 0.2)', 'rgba(54, 162, 235, 0.2)', 'rgba(255, 206, 86, 0.2)', 'rgba(75, 192, 192, 0.2)', 'rgba(153, 102, 255, 0.2)', 'rgba(255, 159, 64, 0.2)' ], borderColor: [ 'rgba(255,99,132,1)', 'rgba(54, 162, 235, 1)', 'rgba(255, 206, 86, 1)', 'rgba(75, 192, 192, 1)', 'rgba(153, 102, 255, 1)', 'rgba(255, 159, 64, 1)' ], borderWidth: 1 }] }, options: { scales: { yAxes: [{ ticks: { beginAtZero:true } }] } } }); </script> <?php return ob_get_clean(); } } I hope you enjoyed reading this and it will open up many new possibilities for you! Updates: permissions: https://processwire.com/talk/topic/17709-how-to-create-custom-admin-pages-aka-processmodules-yes-its-that-simple/?do=findComment&comment=174746 tutorial on file uploads: https://processwire.com/talk/topic/17709-how-to-create-custom-admin-pages-aka-processmodules-yes-its-that-simple/?do=findComment&comment=185261 snippet how to use NavJSON: https://processwire.com/talk/topic/17709-how-to-create-custom-admin-pages-aka-processmodules-yes-its-that-simple/?do=findComment&comment=2164121 point
-
I wouldn't call it a manifesto but anyway... let's talk about my workflow. TL;DR I build 90% from scratch. Every time. Each and every project. I don't use frameworks of any flavour.* * except from some JS stuff - see below Long version My boilerplate for new projects: SCSS Skeleton (my personal collection of SCSS Magic) JS Skeleton (my personal collection of JS Magic) HTML/Kit files depending on templates and elements the project needs (inspired by http://bradfrost.com/blog/post/atomic-web-design/) just an empty folder would work totally fine as well Tools I use and need: git Prepros/CodeKit (or ProCache ?) Tools that may be added later (if absolutely necessary): Lazysizes SVGinline jQuery for Slider scripts (slick, OwlCarousel) MixItUp Tools I never use (because I'm too old for that - I guess) Grunt, Gulp, Bower, Webpack, Parcel, ... you get the idea Benefits Projects are portable Projects run everywhere Every part of project can be changed without affecting other things (most of the time) No need for a special setup (at least for the compiled files) Small(est) file sizes and therefore fast websites (in most cases) Downsides Working with others means I have to trust them and their capability to write good CSS/SCSS You have to think at least twice for each step, every time It takes much more time to build everything from scratch It's much more expensive at first Clients often don't understand the benefits and sometimes WANT a Bootstrap website ? FAQ What if you work with others? As mentioned before I have to trust others that they are capable of writing good CSS/SCSS and therefore I tend to work only with very good people I really trust. Is it worth it? Yes! Why? When stuff breaks or needs to be changed, I know where to look, what to change and can do my stuff without the need to take care of any version upgrades, incompatibilities in or with newer version, I don't need a special setup or whatever. AND... if I want to I can still add whatever is needed. Try it the other way around. That's much harder. Are there exceptions? Of course. Backend stuff, admin interfaces and things like - ProcessWire admin is the perfect example. I wouldn't build something like that from scratch. I guess that's my manifesto.1 point
-
@Robin S, bravo! Cannot test it now (moved to a simper solution) but for sure Your proposal should work. The only thing i needed was to get the page holding both repeaters, and You did it using $page = $page->getForPage();1 point
-
It's been a while and i share my first results: 1) Make some pages with FieldtypeMapMarker 2) Build a form with an input for the Zipcode/PLZ and a select for the radius. 3) upload the .tab file in your template (german zipcodes) tomorrow i will make the styling and getting the distance between plz and results and render the google maps. code: define("OGDB_LOCAL_DATA_FILE","./PLZ.tab"); function plztolatlong($plz) { $fileData = @file_get_contents(OGDB_LOCAL_DATA_FILE); if ( $fileData == FALSE ) { die("ABBRUCH: konnte Daten nicht laden (".OGDB_LOCAL_DATA_FILE.")\n"); } $fileData = explode("\n",$fileData); for ( $i=1; $i < count($fileData); $i++ ) { $fileRow = explode("\t",$fileData[$i]); if ( $plz == $fileRow[1] ) { $origin_lon = $fileRow[2]; $origin_lat = $fileRow[3]; $city = $fileRow[4]; } }; $out['lat'] = $origin_lat; $out['lon'] = $origin_lon; $out['city'] = $city; return $out; } $distance = $input->post->radius; // Get distance $plz = $input->post->plz; // Get PLZ $getlatlng = plztolatlong($plz); // plz to lat and long $lat = $getlatlng['lat']; // just for test reasons later $lng = $getlatlng['lon']; // just for test reasons later echo "<pre>"; print_r($getlatlng); echo "</pre>"; echo "LAT: " . $lat . "<br />"; echo "LONG: " . $lng . "<br />"; $radius = 6371; // earth's radius in km = ~6371 // latitude boundaries $maxlat = $lat + rad2deg($distance / $radius); $maxlat = str_replace(',', '.', $maxlat); $minlat = $lat - rad2deg($distance / $radius); $minlat = str_replace(',', '.', $minlat); // longitude boundaries (longitude gets smaller when latitude increases) $maxlng = $lng + rad2deg($distance / $radius / cos(deg2rad($lat))); $maxlng = str_replace(',', '.', $maxlng); $minlng = $lng - rad2deg($distance / $radius / cos(deg2rad($lat))); $minlng = str_replace(',', '.', $minlng); $q = "template=filialen, mapfield.lat>=$minlat, mapfield.lat<=$maxlat, mapfield.lng>=$minlng, mapfield.lng<=$maxlng"; $results = $pages->find($q); echo "<h2>Ergebnisse</h2>"; foreach($results as $r) { echo "<h3>{$r->title}</h3>"; echo "<p>{$r->mapfield->adress}</p>"; echo "<p>{$r->filial_tel}</p>"; echo "<p>{$r->filial_mail}</p>"; echo "<p>{$r->filial_www}</p>"; } echo $ff; FILES: PLZ.tab1 point