Jump to content


  • Posts

  • Joined

  • Last visited

  • Days Won


Everything posted by millipedia

  1. When we've needed to import images from an old CMS (looking at you WordPress) to a new PW installation then I've just used the API to add an image to a field by passing the URL of the image. I normally just run a PHP script that looks something like this <?php namespace ProcessWire; /** * * Import data from a CSV * */ // Boostrap PW. // this example lives in an 'import' folder include("../index.php"); echo 'in import <br><br>'; // read in data from your CSV file in the same folder while ($row = $files->getCSV('your_export.csv')) { // in this case we already had pages created in PW which we mapped to the old system // using a field 'article_key' so we're using that here to find the right page. // You can do something similar or you could create a new page here. $article_key=$row['article_key']; $p = $pages->get("template=article,article_key={$article_key}"); if ($p->id) { // check we've got a page echo '<br> Got page ID: ' . $p->id; // Check if this CSV row has a field containing our image path if ($row['article_pic'] !== '') { // in this case it was the path to a url on the old site (which obvs // still needs to be accessible online). $post_image = 'https://our-old-site.co.uk/uploads/' . $row['article_pic']; $p->setOutputFormatting(false); $p->featured_image->removeAll(); // remove any old version of the image if you want $p->featured_image->add($post_image); // add our new image $p->save(); echo ' Added: ' . $row['article_pic'] . PHP_EOL; } else { echo ' No image'; } } } This code is just cobbled together from things I've done in the past so you'll need to fix it your needs. If you have 4,500 images then you'll want to run the import in batches rather than trying to do them all at once.
  2. If you want to keep it super simple, you can also just use 'now' or 'today' to compare against your date field: $future_events=$page->children("event_when>'now'");
  3. Here's another alternative to add to the list that looks pretty interesting: https://withcabin.com/ Not being charged for pageviews might work for some of our larger clients and the dashboard looks like a happy medium between Fathom and Mamoto both of which we currently use. We've managed to shift a few clients away from GA recently. In part because the shift to GA4 meant there was going to be some disruption anyway so they might as well switch to a more privacy friendly alternative. Also interesting is that I found out about Cabin on Mastodon instead of Twitter .... that's probably a different thread tho.
  4. Grouping your posts by year is a different use case than pagination which is just showing a fixed number of posts per page. For example you might have a year with dozens of posts that still need to be paginated. When we've needed to do this in the past we've used URL segments to pull out a year and then build a selector from that. We can then use the results from that query for pagination if need be. The code below uses a URL like /blog/by-year/2020 ; you could easily build a subnav that has the years in you need to filter by. Obviously you'd need to update the code to match your fields but hopefully it will point you in the right direction. <?php namespace ProcessWire; $filter_title=''; // Do we have url parameters? if ($input->urlSegment1 ) { // in this example we only filter by year if($input->urlSegment1 =='by-year'){ $year=(int)$input->urlSegment2; $year_end=$year . '-12-31'; $year_start=$year . '-01-01'; if($year > 2000 && $year < 2050){ // not really santizing but I just don't want to encourage any Widdecombe of the Week behaviour. $filter_title=$year; } $results = $pages->find("template=news_item, publish_from<=".$year_end.",publish_from>=".$year_start.",limit=12, sort=publish_from"); }else{ $filter_title="Sorry - unknown filter."; } }else{ $results = $pages->find("template=news_item, limit=12, sort=-publish_from"); } if($filter_title){ echo '<h2>' . $filter_title .'</h2>'; } if($results && $results->count){ $pagination = $results->renderPager(); echo '<div class="news-list">'; foreach($results as $result) { echo '<div class="news-item">'; echo '<div class="news-title"><a href="'.$result->url . '">' . $result->title .'</a></div>'; echo '<div class="news-date">' . $result->publish_from .'</div>'; echo '<div class="news-summary">' . $result->summary .'</div>'; echo '</div>'; } echo "</div>"; echo '<div class="text-center">' . $pagination .'</div>'; }else{ echo '<div class="news-list">No results found.</div>'; }
  5. If you're using Markup Regions as your template strategy then make sure you're acually outputing your code into a valid region otherwsise it's going to be discarded (that's fooled me before).
  6. https://50thbirthday.londonfriend.org.uk/ This is a site we created to celebrate the 50th anniversary of London Friend which is the UK's oldest LGBTQ+ charity. It has a timeline that covers significant events of the charity's history together with a showcase of 50 inspirational Londoners who have made a difference to life in the capital. The technical side of things is pretty much as you imagine. One choice we made was not to use ajax for loading the timeline events but instead loading all of the html and then leaning hard into caching and lazy loading of images. We did use @markus_blue_tomato 's imageBlurHash module to produce placeholders for our lazily loaded images - although honestly you rarely get to see them. For some of the pages the client wanted to be able to add footnotes so we created a text formatter than moves any text in a content block surrounded in square brackets into footnotes section and creates an anchor link. I'll tidy that up and pop it on GitHub when I get some time but feel free to nag me if you think it might be useful to you. Other modules of note were ProCache and (of course) TracyDebugger. We also have some galleries on the site that use PhotoSwipe which is still our g to script for phot galleries. We got great marks in Lighthouse, Observatory and Wave (even the timeline itself which is a complicated page still does very well). It was great to be part of the celebrations (just a shame that I'm on holiday when the launch party happens... dammit)
  7. If you're just after making your image a wonky shape then you can probably just use some fancy css border radius values. Here's a handy looking site for generating the code that looks promising: https://9elements.github.io/fancy-border-radius/
  8. I do use Project Manager already and it's definitely a must have extension. Cool. Whilst we're sharing tips though - on a Mac you can set up a Quick Action in Automater to open a folder in VS Code: the command I've got in that Quick Action is open -n -b "com.microsoft.VSCode" --args "$*" On my Linux box I'm using Dolphin on KDE and get offered the option to 'Open with VSCode' when I right click on a folder ... I think thats just happens by default; I don't remember ever setting that up.
  9. Because I have dozens of PW projects on the go (I really must tidy up my code folder) I didn't want to include the core files for each projects. The best solution I managed was to have a single copy of the core files in a folder which I then add to the intelephense environment path settings: "intelephense.environment.includePaths": [ "/Users/stephen/code/stubs/", "/home/stephen/code/stubs/" ], It would be great to have PW stubs in the core Intelephense list but I have no idea how to even start going about that.
  10. My first thought was that URL hooks might help: https://processwire.com/blog/posts/pw-3.0.173/ my second thought is that if your aim is to improve search rankings then I'm not convinced that this is really going to improve things (and indeed might even make thing worse). Having a concise URL is good for humans but I bet Google doesn't care and may even prefer longer URLs. Looking at the site I bet your time would be better spent optimising performance; if you can bump up that Lighthouse score for page speed I bet that would make much more of a difference than tweaking URLs. Great looking pictures though.
  11. In Test A your PHP Social Stream code is loading it's own copy of jQuery. At about line 974 you have: <!-- PHP Social Stream By Axent Media --> <link href="https://www.ncoinc.org/site/templates/social-stream/public/css/colorbox.css" rel="stylesheet" type="text/css" /> <link href="https://www.ncoinc.org/site/templates/social-stream/public/css/styles.css" rel="stylesheet" type="text/css" /> <script type="text/javascript" src="https://www.ncoinc.org/site/templates/social-stream/public/js/jquery.min.js"></script> that's as well as the version of jQuery you're loading at the bottom of the page. Obviously it's not good to be loading two versions of jQuery. In Test B the Hannah code isn't loading its own version of jQuery. I'm guessing the plugin code is looking for the presence of jQuery in the markup and finds it in the second but not the first - perhaps due to the way the page is being built. The first thing I'd try would be to move loading jQuery into the HEAD section of the site rather than leaving it until last. Techincally that's going to slow down your rendering but means jQuery will be loaded early if you want to add scripts inline. Of course the best solution is not to use jQuery or include social media widgets ?
  12. I like a little bit of chaos personally. Can I stick a vote in for NTS Radio - they have a fantastic range of music.
  13. After having logged this on GitHub and having wiser people than me investigate, we managed to figure out that this only happens when using Varnish cache (in particular using Varnish on a Cloudways server). Disabling Varnish was enough to fix the problem. I'll leave it here though because hey, it's a nice bug, and maybe it'll help someone else.
  14. Here's a fun one this morning. I normally set a custom logo in the admin masthead using the settings in the AdminThemeUikit module (mostly so I know which site I'm in when I've got serveral open at the same time). Today I mistyped the logo name when I was setting this for a site so the logo didn't load. But then when I logged out and tried to log in again I got the dreaded red screen of death. After checking all the usual suspects (file permissions, disc space etc) I renamed the logo file to match my misspelled setting and Bob's your uncle, I can log in again. If I delete the logo file the CSFR error comes back, replace it and it's all good. This only happens in debug mode so my guess is that there's some PHP warning message that's mucking up some javascript but I've not managed to find it yet. I'll log it as a bug on GitHub but thought I'd stick it up here cos it's the kind of bug that could have ages to find and I'm feeling smug that I got it quickly (so no one tell me it's a known bug and I could have just Googled it).
  15. @DaveP Thanks for spotting that broken link - fixed now (Its a hard coded link in the template so the weirdness was due entirely to my fat fingered typing). It is possible to get decent scores in WordPress but it's just so much more effort than it is with PW. and @bernhard - good spot on that layout issue. It was a long URL that was pushing a div out wider than it should have been. Interestingly it was fine in Firefox, which is what I use for development, and only breaking in Chrome / Webkit browsers. I guess this means I really ought to use Chrome for development more to catch this kind of bug which is going to affect more users. Shame because I feel we ought to support FF as much as possible.
  16. Migzen.net is a site we designed and built for Lancaster and Birmingham Universities that gathers academic research into the effect Brexit is having on migration. Obviously we'd best not get into the whole Brexit debate here, so just let me apologise profoundly on behalf of my country and move on to the site... It was a new project, so we were able to create the brand and design from scratch which is always nice. It also gives us the opportunity to make sure colours are accessible for use on the website. As well as the usual blog posts and pages, there's a couple of slightly fancy things we did for them; one of which was to automatically import pages and media whenever they add a new episode to their podcast feeds. We do this using a cron job which loads the MarkupLoadRSS module and parses their XML podcast feeds. If we find any new episodes then we create pages for them with the episode summary from the XML and a nicely styled embedded media player to listen to the audio. We also built them a searchable database of academic resources. That was fairly straighforward, but we do make use of WireCache to build the tag cloud when a page is saved - we use $page->references to work out an article count for each tag which would be expensive to do each page load. There's also a neat looking Timeline which is just built using a repeater field. Honestly PW is ideal for this kind of thing. The site gets good scores in Observatory and Lighthouse (thanks ProCache), and most importantly the client is very happy using PW to keep the site up to date.
  17. Just keeping this thread up to date in case anyone is searching for how to do this still (and I know I'll forget so it will probably be me), the ProcessPageList module now has a configuration option to let you hide pages from users:
  18. When I need to shift data over from an old site I normally export the data to a csv file and then just write a PHP script to loop through that csv and add pages. Once you get the idea it's a very flexible way to import data. Here's some completely untested code as an example of how I'd approach it: // bootstrap PW include("index.php"); $filename='data_to_import.csv'; // loop through this CSV if (($handle = fopen($filename, "r")) !== FALSE) { while (($data = fgetcsv($handle, 2000, ",")) !== FALSE) { // say we have a csv that is in the form // 'artist_name', 'artwork_name', 'artwork_dscription' // (I'm assuming this csv doesn't have a header row) $artist_name=$data[0]; $artwork_name=$data[1]; $artwork_description=$data[2]; // see if we have a page for this artist already $ap=$pages->get("template=artist,name={$artist_name}"); // if not then add this artist - in this example // using the template 'artist' and the parent '/artists/' if($ap->id < 1){ $ap = $pages->add('artist', '/artists/', [ 'title' => $artist_name ]); } // now add our new artwork page using the artist_page as a parent $artwork_page = $pages->add('artwork', $ap, [ 'title' => $artwork_name, 'description' => $artwork_description ]); } fclose($handle); }else{ echo 'cant open csv file for import'; }
  19. In the past when a client has asked us to show PDFs in the browser rather than being downloaded we've used Mozilla PDF.js and then created a link that passes the doc name in the form pdfjs/web/viewer.html?file=whatever.pdf In this day and age though I'd question whether this is really necessary. Most browsers have built in pdf viewers anyway : https://caniuse.com/pdf-viewer and if you're overriding the users choice as to which pdf viewer they use then it's probably not great for usability.
  20. There's also the pw-optional parameter for your Markup Regions: https://processwire.com/docs/front-end/output/markup-regions/#defining-an-optional-region You'd need to use an id on your section tag rather than the content div you have at the moment but that would remove the section if it was empty. <section id="section2" class="section" pw-optional> <div class="container is-fluid"> <div id="content2"></div> </div> </section>
  21. Noted. Before I spotted your reply though I'd hooked into ProcessPageEdit to load an external js file: function resizeEditor(HookEvent $event){ $js_path=wire()->config->urls->templates . "resize_editor.js"; wire()->config->scripts->add($js_path); } wire()->addHookAfter('ProcessPageEdit::execute', null, 'resizeEditor'); and then that JS looks like this: // resize ckeditors to height of container. if(typeof CKEDITOR !== 'undefined'){ CKEDITOR.on('instanceReady', function(event){ var input_name=event.editor.name; // this is the id of our field. var parent_height = document.getElementById(input_name).parentElement.offsetHeight; console.log('Setting editor ' + event.editor.name + ' height to' + parent_height); event.editor.resize( '100%', parent_height ); }); } That sets all the editors to the height of their containers.
  22. That's certainly helpful thanks (and honesly will probably do me). I still feel like it should be possible to automatically resize the editor to the height of the container div though. Probably a bit of javascript that uses the CKEditor resize function to match the editor height to its parent. I'll have a play when I have a moment - I was just hoping someone might have done it already....
  23. This is really minor thing but it annoys me that I can't get an instance of a CKEditor to use the full height of a container in the admin. This is especially noticeable where I have fieldset that's pushing the height of a row down; as per this screenshot: I've poked around at various CSS settings but no luck so far. Has anyone managed to do this?
  24. Hopefully those other suggestions will help answer your question, but like @AndZyk I'd be interested to see what the justification is for not organising your pages in sections. My feeling is that hiding navigational elements is more likely to have a detrimental effect on usability (and hence SEO). I can't be the only one who occasionally edits a URL to navigate up a level (ok, I might be). Perhaps it's different if you have a limited number of products on a site but I think having a decent hierarchy is going to be better for users.
  25. Right - as part of my efforts to show off more of the work we've done recently, here's a site we launched earlier this year. On The Record are a not-for-profit that specialise in oral histories and creative media. We've done a few nice projects with them ( A Hackney Autobiography was a lovely project we did with them in our pre PW days). A creative design was very important to them as well as being accessible and usable. There's not too much bespoke backend coding going on. We needed to provide them with a way of easily adding audio and video files but that was mostly done using normal fields and a modified version of Ryan's TextformatterVideoEmbed module adapted for use on plain text fields. Apart from that, it's just the usual supects for extra modules: ProCache LoginPersist and Macrura's ProcessDocumention module which we normally use for provide help pages in the admin area. The front end is pretty much bespoke but with a few components lifted from various places; looks like we used Bootstrap grid for one. It's another site where we used CSS filter properties to apply a consistent look and feel to images the client uploads. I think it looks nice anyway and the client is very happy with it and took to using the PW admin with no problems.
  • Create New...