Leaderboard
Popular Content
Showing content with the highest reputation on 02/12/2022 in all areas
-
This module enables Selectize (which is bundled with the PW core) on all Select and AsmSelect inputfields in the PW admin. As described below in the readme, Selectize is initialised/destroyed as the revelant select is focused/blurred in order to support select options that change after the page is loaded. Therefore Selectize is styled to match the AdminThemeUikit select as closely as possible to minimise the visual change as the select is focused and blurred. I'm developing on Windows so I'm not sure how the module will render on other operating systems. It doesn't help that the PW admin uses different fonts depending on the OS - I wish PW would bundle its own webfont for a standardised appearance everywhere. Incidentally, I was a bit disappointed with the state of the Selectize project. I had to fix or work around a number of bugs and shortcomings, including things you would think would just work out of the box such as disabled options, matching the width of the replaced select, or the standard select behaviour where a selection is required when there is no empty option. The Selectize issues repo is full of arbitrarily closed bug reports and pull requests and there are no updates for the last 6 years. I've tried to catch everything that would affect this module but I wouldn't be surprised if there are still some bugs. Selectize All Enables Selectize on all InputfieldSelect and InputfieldAsmSelect fields in the ProcessWire admin. The module activates Selectize on the <select> element when it is focused, and destroys Selectize when the element is blurred. This allows Selectize to work on selects where the options are changed dynamically after page load depending on other field values, e.g. the "Select File" field in the CKEditor link modal or a dependent select in Page Edit. Only AdminThemeUikit is tested and supported. Usage In the module config you can choose if Selectize should be used with InputfieldSelect, InputfieldAsmSelect, or both. If you want to disable the module for a specific Select or AsmSelect inputfield you can hook SelectizeAll::allowSelectize. This method receives the Inputfield object as the first argument. Example: $wire->addHookAfter('SelectizeAll::allowSelectize', function(HookEvent $event) { $inputfield = $event->arguments(0); // You can also get any associated Page and Field objects via $inputfield->hasPage and $inputfield->hasField // Disable the module for the inputfield named "template" if($inputfield->name === 'template') $event->return = false; }); https://github.com/Toutouwai/SelectizeAll https://processwire.com/modules/selectize-all/13 points
-
This week I've bumped the dev branch version to 3.0.194. Relative to last week, there are a few commits fixing minor issues. Last week we covered some fairly major updates and I've not come across any concerning side effects, so figured it's a good day to bump the version. Next week my kids are out of school for winter break so I'll be around but I don't expect I'll have much in terms of updates to report next week, but definitely will the following week. Thanks and have a great weekend!7 points
-
Hi all, I got inspired to writing this little tutorial by @FireWire's post. We are using the same deployment workflow that he mentions for all new projects. I tried different approaches in the past, also github Actions and gitlab Runners. Setting those up always felt like a PITA to me. Especially since all I wanted was to automatically deploy my project to staging or live on push Whom this is for Single devs or teams who want to streamline their deployment process with native git methods. Requirements shell access to the server git installed on the server and locally If you don't have shell access and git on the server, upgrade or switch hosting. Walkthrough In this example we will be using github to host our code and a server of our choice for deployment. The project is called myproject. Step 1 (github) Create a repository named myproject. Let's assume that is available at git@github.com:myaccount/myproject.git. This is our remote URL. Step 2 (local) create a project in the folder myproject and push it to github like you usually would. The remote of your project should now read like this inside the myproject folder $ git remote add origin git@github.com:myaccount/myproject.git $ git remote -v origin git@github.com:myaccount/myproject.git (fetch) origin git@github.com:myaccount/myproject.git (push) Step 3 (server) Login via ssh to the server and go to the document root. We assume this to be '/var/www/'. We further assume the command for connecting to our server via ssh is 'ssh myuser@myserver'. Go to web root, create a directory that will hold a bare git repo, cd into it and create the bare git repository. A bare repo is one that does not contain the actual project files but only the version control information. cd /var/www/ mkdir myproject-git && cd myproject-git git init --bare Step 4 (server) Create the root directory for your ProcessWire installation cd /var/www/ mkdir myproject Step 5 (local) Now we add information about the bare git repo to our local git config. So that when we push changes, they will be pushed both to github and to the bare git repo on our server. Inside our project folder we do git remote set-url --add --push origin myuser@myserver:/var/www/myproject-git After that we need to add the original github push origin again, because it got overwritten by the last command git remote set-url --add --push origin git@github.com:myaccount/myproject.git Now the list of remotes should look like this $ git remote -v origin git@github.com:myaccount/myproject.git (fetch) origin myuser@myserver:/var/www/myproject-git (push) origin git@github.com:myaccount/myproject.git (push) We have one fetch and 2 push remotes. This means that if you push a commit, it will be pushed to both github and your server repo. Step 6 (server) Here comes the actual deployment magic. We are using a git hook that fires a script after every push. This hook is called a post-receive hook. We move into the directory with the bare repository, change to the hooks directory, create the file that triggers the hook and open it for editing with nano $ cd /var/www/myproject-git/hooks $ touch post-receive $ nano post-receive Now we paste this script into the open editor and save it #!/bin/bash # Bare repository directory. GIT_DIR="/var/www/myproject-git" # Target directory. TARGET="/var/www/myproject" while read oldrev newrev ref do BRANCH=$(git rev-parse --symbolic --abbrev-ref $ref) if [[ $BRANCH == "main" ]]; then echo "Push received! Deploying branch: ${BRANCH}..." # deploy to our target directory. git --work-tree=$TARGET --git-dir=$GIT_DIR checkout -f $BRANCH else echo "Not main branch. Skipping." fi done What this does is checking out (copying) all files that are in the repository to our ProcessWire root directory every time we push something. And that is exactly what we wanted to achieve. This example setup is for a single branch. If you wanted to make this work with multiple branches, you need to make some small adjustments. Let's assume you have one staging and one live installation where web root for live is at /var/www/myproject and for staging at /var/www/myproject-staging In Step 4 above you would create a second dir $ cd /var/www/ $ mkdir myproject $ mkdir myproject-staging And the content of the post-receive hook file could look like #!/bin/bash # Bare repository directory. GIT_DIR="/var/www/myproject-git" while read oldrev newrev ref; do BRANCH=$(git rev-parse --symbolic --abbrev-ref $ref) if [ $BRANCH == "master" ]; then TARGET="/var/www/myproject" elif [ $BRANCH == "staging" ]; then TARGET="/var/www/myproject-staging" else echo "Branch not found. Skipping Deployment." fi # deploy only if var TARGET is set if [ -z ${TARGET} ]; then echo "no target set" else echo "STARTING DEPLOYMENT..." echo "Push to ${BRANCH} received! Deploying branch: ${BRANCH} to: ${TARGET}" # deploy to our target directory. git --work-tree=$TARGET --git-dir=$GIT_DIR checkout -f $BRANCH fi done Now everything you push to your staging branch will be deployed to /var/www/myproject-staging. Commits to master branch to /var/www/myproject We really do enjoy this deployment workflow. Everything is neat and clean. No need to keep track of which files you uploaded already via SFTP. Peace of mind :-) I basically put together bits and pieces I found around the web to set this up. Would be eager to see how you implement stuff like this.2 points
-
2 points
-
2 points
-
+1 +1 Could be a good first (or next) step towards automated file based migrations with rollback feature! ?2 points
-
Hi, thanks @Robin S for your hook example, but also (in my case) I had a problem to save values inside repeaters. I use 3 fields per/row and out of repeaters everything works fine (PW 3.0.146.). The images below shows my page tree and two different situations (after save). --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Here is another hook example ("cascade" case like on images) but before test, please read setup notes: 1) For the first column field (continents / categories) set parent page inside field setup. 2) For subfields (country and city) set template (eg. "blank") inside field setup. 3) Write selector strings for subfields inside hook configuration (ready.php). PHP (ready.php) <?php namespace ProcessWire; /** * Configuration: * Field names and selectors * * For subfields and after save problem * need to write string selectors here, and leave empty * that part inside field setup. */ $config->names = array( 'continent' => '', 'country' => 'parent=page.continent', 'city' => 'parent=page.country', ); $wire->addHookAfter('InputfieldPage::getSelectablePages', function ($event) { $inputfield = $event->object; $field = $inputfield->hasField; $names = $this->config->names; if (isset($names["$field->name"])) { $selector = $names["$field->name"]; if (trim($selector) !== "") { if (strpos($inputfield->name, '_repeater') !== false) { $id = str_replace($field->name . "_repeater", "", $inputfield->name); foreach ($names as $n => $s) { if (strpos($selector, $n) !== false) { $repeater_name = $n . '_repeater' . $id; $selector = str_replace($n, $repeater_name, $selector); } } } $inputfield->findPagesSelector($selector); } } } ); Here is screen record: Regards.2 points
-
Natasha Marques is a desserts chef and chocolatier from Brazil with an international carreer. Now established in my hometown Porto, she's about to open a shop and already shipping her premium line of sweets and desserts. The website is my usual combo of PW with StencilJS frontend with a content blocks approach. Minimal stack of modules: SeoMaestro, WireMailSmtp, and my own block selector module which is a hacked version of FieldSelectFile. The site is only in portuguese, but have a look anyway: https://arbynatashamarques.com/1 point
-
I'm using DDEV now for my local development and there's one thing that I'm missing: I can't click on links on error screens or in the dump bar, because the files live inside docker ( /var/www/html/... ) whereas I have them in my IDE (on my host) at ~/foo/bar While looking for a solution I saw in the code that there's already the localRootPath config setting, but this does not solve the problem I think. The reason is that it seems to work only on live systems? Why? First, I have to force tracy into DEV locally due to the issue we talked about lately (on DDEV the detection does not work). Second, we work in a team and everybody has a different local root path. That means we'd need to put that in a config file that is custom for each user. Or maybe you have an idea for a better solution? The thing is we can't even define something like this: [ 'bernhard' => '/Users/bernhard/siteX/', 'adrian' => '/Users/adrian/siteX/', ] because we all use the same admin user on local dev... That's why I think it would be best to have a config setting that we can all put in our config-local.php which is not shared via GIT Thx!1 point
-
1 point
-
Same issue here in terms of links pointing to wrong location (virtualbox based dev environment). Not a big deal for me personally, but sure it would be nice if they worked. Just had a look and I'm wondering if there's a real need for the "Only used if you are viewing a live site" part — why does it work like that, and could it be overridden somehow? I guess it makes sense if "local" means that you're literally developing on the local machine without any extra layers, but since "local" is also used to identify other whether this is a "development environment" vs. "production environment", this is indeed problematic ? Developer specific config file would also make sense because the developer is not necessarily logged in when viewing Tracy panels. It'd be even harder to distinguish between guests ?1 point
-
We have given Wordpress enough advantage of the doubt ...... Here it goes again: https://www.zdnet.com/article/php-everywhere-wordpress-plugin-code-execution-bug-impacts-thousands-of-websites/ Give the Client a WebSite that he really deserves ... with Processwire !1 point
-
I firmly believe that Ryan should be the one to do it, even thought he does not (yet) need it for some reason. I would only be willing to add money to the "pool" if he is the one who implements AND maintains it. So why don't we just pledge that we collect the amount he asks for its initial development and ask him to do it? New features for ProDevTools perhaps?1 point
-
You need to give them this mantra: "pull - merge - push" and let them recite it 100 times a day at least ? It only knows that it needs to deploy on push. So it won't deploy when someone merges stuff on the server. From that perspective it is pretty fail safe. Give it a try, think you'll love it.1 point
-
Exactly. staging.myproject.tld would point to folder /var/www/myproject-staging We never merge things on the server, always merge stuff locally first and then push. For the post-receive hook fires only after a push. The most important thing to remember when working with this strategy is: always pull/merge before you push.1 point
-
This is kind of cross-post... in order to keep this thread updated with related thoughts. In summary... @ryan and @horst use what PW provides... @bernhard uses his RockMigration... all others of us use what ever fits our need and I'm totally fine with that... and really appreciate that. Yet... somehow I'd really love to see a CraftCMS-like (even though I never saw or used it) JSON/YAML-Recorder-style tool @bernhard showed to us. What if we open a money-pool for such a development? Someone interested? If I could have some kind of a solid working solution for a real time JSON/YAML-file-export/import solution which I only need to migrate via Git, without writing any functions, code or whatever, solely based on my PW-setup, to make all my instances the same... sure with some checks in the background but... YES... that would be my dream. Still... I want and have to try and test the solution CraftCMS has available. I put my money where my mouth is and start upfront with EUR 500 in the pool. I will post some details of all the features I'd like to have and see in such a module in the upcoming days, maybe a week or two. Yet... whoever wants to join, let me know. In case you want to develop such a module, PLEASE let me know. I guess I want to see this module happen in some kind or another (community or pro module). My goal is... making PW even better. And maybe this could be another step. Crossposted from1 point
-
Thx for that example. I understand now. <?php // migrate field content only if the address field exists if($rm->fields->get('address')) { // first we make sure the fields exist $rm->createField('foo', 'text'); $rm->createField('bar', 'text'); $rm->createField('baz', 'text'); // then we make sure they are added to xyz template $rm->addFieldsToTemplates(['foo','bar','baz'], 'xyz'); // then we migrate data foreach($pages->find('template=xyz,address!=') as $p) { $parts = ...; // split address into parts $p->of(false); $p->foo = $parts[0]; $p->bar = $parts[1]; $p->baz = $parts[2]; $p->save(); } // then we delete the obsolete field $rm->deleteField('address'); } // then we use the existing migration config for future use // so you can easily add other stuff (like whatsoever field) $rm->migrate([ 'fields' => [ 'foo' => [...], 'bar' => [...], 'baz' => [...], 'whatsoever' => [...], ], 'templates' => [ 'xyz' => [ 'fields' => ['foo', 'bar', 'baz'], ], 'whatsoever' => [ 'fields' => ['whatsoever'], ], ], ]); If you are inside a module that uses a migrate() method to migrate data this could easily been refactored to this: <?php class MyModule ... { public function migrate() { $rm = $this->wire->modules->get('RockMigrations'); $this->migrateAddressData(); $rm->migrate([ 'fields' => [ 'foo' => [...], 'bar' => [...], 'baz' => [...], 'whatsoever' => [...], ], 'templates' => [ 'xyz' => [ 'fields' => ['foo', 'bar', 'baz'], ], 'whatsoever' => [ 'fields' => ['whatsoever'], ], ], ]); } public function migrateAddressData() { // if the address field does not exist any more // we can exit early as we have nothing to do if(!$rm->fields->get('address')) return; // first we make sure the fields exist $rm->createField('foo', 'text'); $rm->createField('bar', 'text'); $rm->createField('baz', 'text'); // then we make sure they are added to xyz template $rm->addFieldsToTemplates(['foo','bar','baz'], 'xyz'); // then we migrate data foreach($pages->find('template=xyz,address!=') as $p) { $parts = ...; // split address into parts $p->of(false); $p->foo = $parts[0]; $p->bar = $parts[1]; $p->baz = $parts[2]; $p->save(); } // then we delete the obsolete field $rm->deleteField('address'); } } This is one of the situations that are not possible using YAML of course ? But the "migrateAddressData" could be done in PHP while the migrate() could migrate YAML data still.1 point
-
You can do this with the undocumented dependent selects feature, which AJAX loads the selectable pages in a Page Reference field based on the value of another Page Reference field in the same page being edited. Your "homes_in_neighborhood" field would use this as the "Selector string" setting: neighborhood=page.neighborhood, neighborhood!='' You can limit by template, parent, etc too if you want. Based on my previous experience: Both Page Reference fields must use a Select, Select Multiple or AsmSelect inputfield. Dependent selects do not work inside Repeater fields. When changing the "source" Page Reference field you sometimes randomly get an option preselected in the "target" Page Reference field. Not a major problem but just something to keep an eye on to avoid accidentally saving an unintended value. If these limitations are a problem and you don't mind having to save the page after changing the "neighborhood" field then you can use the "Custom PHP code" option for selectable pages instead.1 point
-
Just for the info this can be used to autoload only if the template of the edited page in the admin is "basic-page": 'autoload' => function() { return wire('pages')->get(wire('input')->get->id)->template == 'basic-page'; },1 point
-
I have been reading these posts with great interest but also a great deal of confusion. It seems that there are maybe 3 conversations going on simultaneously. Or maybe they are one and the same (or sides of the same 3-sided coin ?) and it is me who is not getting it. I suspect the latter. #1 Conversation 1: Create fields and templates quickly using a configuration file. #2 Conversation 2: Deploying sites from local to production. #3 Conversation 3: Versioning fields and templates. It is #3 that I don't understand at all. Maybe this is because I always use #2 in my 'deploy to production' strategy. This is not a criticism against #3. I genuinely don't understand why you would need to version templates and fields (but especially templates). I have read most of the posts but it is still not sinking in. Could someone please briefly explain this (i.e., why one would want to version templates and fields)? By versioning a field, for instance, does it mean that if the field label or description, etc. changes, that you need to be able to roll back those changes? Something more complicated than that? Please don't' laugh ?.I am probably exposing my ignorance here but happy to learn ?. Thanks.0 points