Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 08/23/2022 in all areas

  1. Woah... there are a lot of moving parts here. First of all: It always takes way longer than anyone expected it would take. I have seen super simple and minimal projects taking weeks instead of days. Yet I've seen quite large and complex projects that took only a few weeks instead of months. In average the PHP/PW part is most of the time the smallest part within a project that's just dealing with content at least in my projects. It can be tricky when you have to deal with lots of data from different sources, especially when you do more than just displaying that data. Most time and energy in my projects go into: Planning out the whole project Designing each and every bit Content audit, creation, and optimisation Frontendwork HTML, CSS, JS Right after that ProcessWire comes into play with these parts: Templates and fields Site structure, setting up basic pages Modules and global settings Backend logic, data automation, cron/lazycron jobs, automated maintenance On average I'd say it's a 70/30 ratio between those two. To get you some numbers here: We talk about at least a few weeks and maybe even months in total with all kinds of related things like meetings, phone calls, organizing, setting up Google and other tools, like tracking tools, newsletter, etc. To make things clear and a bit more transparent, we talk about projects and websites like these: https://www.restaurant-blechnapf.de/ https://www.klippo-nms.de/ https://www.musikschule-neumuenster.de/ In comparison to the above there are projects I built in my spare time without a lot of planning or almost anything - which took a few hours or maybe two days in total. Like these: https://www.jet-fire.de/ https://www.voss-friseure.de/ The main difference is that the first 3 projects are totally custom and fully optimized, multiple user accounts, access rights, automation and maintenance and design-wise on a totally different level. While the last two use UIKIT or Bootstrap, just display simple content and aren't that well optimized to be honest. Last but not least there are projects like this: https://www.restaurants-neumuenster.de/ It started with a simple splash page, a simlpe form and a bit of content and went online within a few hours. Yet as of today there are several hundred hours of work in it. Quite a bit design (had a few relaunches in the past) but way more in terms of data processing, automation, newsletters and lot's of nice things. TL;DR From about 2 days to a couple of months.
    5 points
  2. Check and try the following, I think the link provided all the infos. /// get and mod inputfield submit $wire->addHookBefore('InputfieldSubmit::render', function($event) { /// get page being edited from from query string $id = (int) $this->input->get->id; // ⚠️ sanitize it, do not trust your xss ninja admins $page = $this->pages->get($id); /// i.e. exit if page name is not 'hello' if($page->name !== 'hello') return; /// get the object the event occurred on $submit = $event->object; /// make sure to target the `submit save` button (it could be more than one button) $name = $submit->attr('name'); if($name !== 'submit_save') return; /// change the button's label (attribute: value) $submit->attr("value", "Foobar"); }); /// mod the inputfield submit dropdown $wire->addHookAfter('ProcessPageEdit::getSubmitActions', function($event) { $actions = $event->return; // array actions /// get page being edited from event's object $page = $event->object->getPage(); /// i.e. exit if page name is not 'hello' if($page->name !== 'hello') return; $actions['to_the_moon'] = [ 'value' => 'to_the_moon', 'icon' => 'moon-o', 'label' => '%s + Go Moon ?', // Save + Go Moon 'class' => '', ]; $event->return = $actions; }); /// process the new action dropdown $wire->addHookAfter('ProcessPageEdit::processSubmitAction', function($event) { $action = $event->arguments(0); // action name, i.e. 'cache' if($action === 'to_the_moon') { $event->message("Your page was rocketed to the moon ??", "nogroup"); } }); /// remove all the dropdown action but keep our new one $wire->addHookAfter('ProcessPageEdit::getSubmitActions', function($event) { $actions = $event->return; // array of actions, indexed by name /* bd($actions) ? 'exit' => array 'view' => array 'add' => array 'next' => array */ /// remove all action, let just keep our `to the moon` action foreach($actions as $action) { $name = $action['value']; if($name === 'to_the_moon') continue; unset($actions[$name]); } $event->return = $actions; }); /// bonus - add a second button on the current edit page $this->addHook('ProcessPageEdit::buildForm', function($event) { /// get page being edited from from query string $id = (int) $this->input->get->id; // ⚠️ sanitize it, do not trust your xss ninja admins $page = $this->pages->get($id); /// i.e. exit if page name is not 'hello' if($page->name !== 'hello') return; /// quite self explanatory $href = $this->config->urls->admin."page/edit/?id=$id&to=the_moon"; $field = $this->modules->get('InputfieldButton'); $field->attr('id+name', 'input_moon'); $field->attr('class', $field->class); $field->attr('value', 'To the moon ?'); $field->attr('href', $href); $event->return = $event->return->append($field); });
    2 points
  3. Thank @wbmnfktr. I did see that thread from Ryan, but it didn't seem to cover modifying the default button, more about adding a new one. However on second thoughts I'm going to use the drop down actions anyway as may need more than one option, but it would be good to know about editing the default label if anyone has any insight on this for future reference.
    2 points
  4. 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.
    1 point
  5. I've started with this guide as well, so thx a lot again for sharing that @gebeer but I want to mention that for anybody interested in automatic deployments RockMigrations ships with a ready-made deployment solution that you can use: https://github.com/baumrock/RockMigrations#deployments
    1 point
  6. As we all know, Google's services are never free, we all pay by providing our own data to them: https://thehackernews.com/2022/01/german-court-rules-websites-embedding.html and we never know what they are using our data for, but this monkey business is quite profitable for them for sure.
    1 point
  7. When you search for getSubmitActions you will find some thread talking about adding and removing buttons. At some places you can see how titles/labels of those buttons were set. As a starting point: Maybe that helps? https://processwire.com/talk/search/?&q=getSubmitActions&quick=1&search_and_or=or&sortby=relevancy
    1 point
  8. I am using the latest fork here. Works perfect for me. https://github.com/matjazpotocnik/ProcessWire-AIOM-All-In-One-Minify
    1 point
  9. Sites like that with a small amount of content and low variety in page templates/designs are typically 10-20 hours for me.
    1 point
  10. Well, what is "normal" nowadays? It totally depends on the amount of static pages, the features - and the design (+ custom desktop/tablet/mobile adaptations) Do you start from scratch with a blank processwire installation or did you build yourself a custom development project with a default stylesheet and all kinds of modules, fields and templates predefined (tools you would need in every project) so you can just grab what you need and just alter the layout and data you render? Last but not least it also depends on your skill level as a developer of course. So based on all this I guess someone could either spend 10 or 100+ hours on a project.
    1 point
  11. v1.17.0 adds a nice helper to download webfonts automatically to /site/templates/fonts Austria is hit by a wave of legal letters demanding 190€ from website owners that serve google webfonts from the google servers directly instead of self-hosting them. Selfhosting fonts on the other hand is tedious!! I know there is the google-webfonts-helper, but I wanted something better integretad into my PW workflows. So RockFrontend now downloads all the necessary files for you (eot/woff/woff2/ttf/svg) by sending separate HTTP requests to google with different user agents and saving the fonts with a readable name to /site/templates/fonts Simply paste the url and hit save:
    1 point
  12. I hope you are having a great week. Today I've released new versions of two ProcessWire ProFields modules: Table and Combo. In addition to various minor improvements and fixes, the biggest update in both is the addition of file and image fields. Since this is a fairly major feature addition for both modules, please consider these versions in a beta test stage for the moment. Both are available for download in the ProFields board now. Table v23 In ProFields Table both "file" and "image" column types were added. These are fairly basic file upload fields, but a major improvement over not having them at all. It can hold one file per column per row in the table. You can have as many file columns as you need per row. The front-end value of your file or image columns is one you are likely used to using already: Pagefile or Pageimage objects, just like they would be in a regular single-file or image field. This means your file/image values in your Table rows can benefit from many of the built-in methods you already use, such as the ability to present resized images, WebP variations, etc. When you configure a file column you can specify what extensions you want to allow and the maximum number of bytes you are willing for it to accept in an upload. When configuring an image column, you also gain settings to specify the thumbnail image preview size in both regular and HiDPI resolution. Combo v9 The update for Combo fields was similar to the Table field except that file and image fields go quite a bit further in Combo than they could in Table. Specifically, you get almost the full set of InputfieldFile/InputfieldImage configuration settings and features, including the ability to support both single and multi-file uploads, image actions, variations, focus control, description input, tags input and more. The only things missing relative to a regular File/Image field are the manual Crop action (Image field) and the ability to manage separate custom fields for each file or image. The front-end value for your Combo file fields is identical to what it would be on a regular ProcessWire File or Image field. Specifically a Pagefiles or Pageimages (plural) object if supporting multiple files, or a Pagefile or Pageimage (singular) object if supporting 1 file. To say it another way, you can use this exactly as you use other dedicated file/image fields in ProcessWire. Not yet included is the ability to query the properties of a file/image field from selectors, like when using $pages->find(). I'm still working on that part, but since I know most probably don't need that I decided to get this version out first and then continue working on that part. Core updates The core updates this week were mostly minor, even if there were a lot of them. One of the ways that I stay up-to-speed on all the core code is to regularly read through all of it and make small adjustments along the way... anything that makes the code easier to read, or easier for PhpStorm to inspect it. You've seen these kinds of updates pretty much every week for years, but I hadn't thought to mention it before. This week there were more of these kinds of updates than usual so I just wanted to mention that what it's for. What sometimes looks like micro-optimization or minor code changes is usually just me staying fresh and up-to-date with the core. ? That's all for this week. I hope you have a great weekend!
    1 point
  13. If you want to be sure to support Firefox, it's still best to develop in Firefox. Once finished, you then just need to visually inspect (under various viewport resolutions) with other browsers. Chromium supports more CSS and other technologies before other browser rendering engines, so if you develop to Chrome and then go back to Firefox to fix something, it's very often a forced regression type of fix, which isn't fun. Even worse is Safari... Very happy to see that you had the forethought to include (or in this case, exclude) printable formatting! The attention to detail is great. Congratulations on your launch!
    1 point
  14. Find Merge Adds a Pages::findMerge() method that allows multiple PageFinder selectors to be merged into an efficient paginated set of results. This can be useful when you need more sophisticated sorting of results than what would be possible using only the sort value in a single $pages->find(). Details $results = $pages->findMerge($selectors, $options); $selectors is required and must be an array of selectors. Each selector can be in string format or array format. The findMerge() method will loop over the selectors in the order supplied, adding matching pages to the final results. $options is an optional associative array of options. limit (int) Limit for pagination. start (int) Manually override the start value rather than have it be automatically calculated from the current page number. excludeExisting (bool) Whether or not to exclude pages in each selector that have already been matched by a previous selector. Default is true. keepFirst (bool) When excludeExisting is false then a page might match more than one selector in the supplied array. But each page can only appear once in the results and if keepFirst is true then the page will appear in its earliest position in the results, whereas if keepFirst is false it will appear in its latest position in the results. Default is true. As a shortcut you can supply an integer as the second argument and it will be treated as the limit for pagination. Basic usage For most use cases only a limit will be needed for the $options argument. $selectors = [ 'title%=yellow', // title contains "yellow" 'title^=z', // title starts with "z" 'title=elephant', // title equals "elephant" 'template=colour, sort=-title, limit=3', // 3 colours in reverse alphabetical order 'template=country, sort=title, limit=40', // 40 countries in alphabetical order ]; $results = $pages->findMerge($selectors, 10); if($results->count) { echo "<p>Showing results {$results->getPaginationString()}</p>"; echo "<ul>"; foreach($results as $result) { echo "<li><a href='$result->url'>$result->title</a></li>"; } echo "</ul>"; echo $results->renderPager(); } Advanced usage The following notes are only relevant to rare cases and most users can safely skip this section. In the demo example the colour page Yellow will potentially match both the 1st selector and the 4th selector. Because of this the excludeExisting and keepFirst options will have an effect on the results. excludeExisting option false Note that the 4th selector asks for 3 colour pages (limit=3). By default excludeExisting is true, which means that when the 4th selector is processed it is interpreted as saying "find 3 colour pages in reverse alphabetical order that have not already been matched in an earlier selector". We can see that there are 3 pages in the results from that selector: Violet, Red, Orange. But if excludeExisting is set to false then the results are different. The matches of the 1st selector (Yellow, Yellow Warbler) are not excluded from consideration by the 4th selector (the 4th selector matches will be Yellow, Violet, Red), and because each page can only appear once in the results this means that the 4th selector ends up only adding 2 more pages to the results. $selectors = [ 'title%=yellow', // title contains "yellow" 'title^=z', // title starts with "z" 'title=elephant', // title equals "elephant" 'template=colour, sort=-title, limit=3', // 3 colours in reverse alphabetical order 'template=country, sort=title, limit=40', // 40 countries in alphabetical order ]; $options = [ 'limit' => 10, 'excludeExisting' => false, ]; $results = $pages->findMerge($selectors, $options); keepFirst option false As described above, the Yellow page potentially matches both the 1st and 4th selector. By default Yellow will appear in its earliest position within the results, i.e. the position resulting from it being matched by the 1st selector. But if keepFirst is set to false (and excludeExisting is false) then it will appear in its latest position within the results, i.e. the position resulting from it being matched by the 4th selector. $selectors = [ 'title%=yellow', // title contains "yellow" 'title^=z', // title starts with "z" 'title=elephant', // title equals "elephant" 'template=colour, sort=-title, limit=3', // 3 colours in reverse alphabetical order 'template=country, sort=title, limit=40', // 40 countries in alphabetical order ]; $options = [ 'limit' => 10, 'excludeExisting' => false, 'keepFirst' => false, ]; $results = $pages->findMerge($selectors, $options); keepFirst has no effect when excludeExisting is true. https://github.com/Toutouwai/FindMerge https://processwire.com/modules/find-merge/
    1 point
  15. I can't tell you how the various forks are doing, but my official module is no longer in development and therefore deprecated.
    0 points
×
×
  • Create New...