Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 07/28/2021 in Posts

  1. I developed the new Geffen Playhouse website over the course of 2018/2019 and launched it in September 2019. It has been perhaps the largest project I have been involved in. The Geffen Playhouse went through an entire re-branding done by Base (including a custom font), and I worked with Teak on the new website. Website: https://www.geffenplayhouse.org/ Wikipedia: https://en.wikipedia.org/wiki/Geffen_Playhouse Base write-up: https://www.basedesign.com/work/geffen-playhouse-always-geffen-playhouse-always-new Teak SF write-up: https://teaksf.com/work/geffen-playhouse-ticketing-ecommerce-website-design/ Their previous website was severely antiquated and it wasn't a responsive website (as of 2019!). Instead, it forwarded mobile users to a "mobile-friendly" website on a different subdomain, which I think was hosted by a third party service. However the data containing all the actors, shows, seasons, news and press articles were all in there. So one major aspect of this website was de-duping and importing their data into ProcessWire, along with some post-import cleaningโ€ฆ that's ~25 years of data. The site is built with UIkit 3 for the most part, and also uses FullCalendar for the large and small calendars. There is a custom integration with AudienceView, their ticketing system, which is used to import all the performance showtimes of their shows into ProcessWire. It's not the easiest API to work with (XML), but I eventually got it working. Repeater Matrix is being heavily used for section-based page building. Building out all the necessary matrix types took a long time as there was quite a bit of thinking what types and layouts we needed as we went along. However the end result has given the editors a lot of flexibility. ProCache is being used as well, including a CDN for all assets. This is crucial because when opening season sales are announced, the site gets slammed, but with caching turned on, it's not a problem anymore. On a deeper level, the site uses my new (well 2 years old now), universal and very opinionated base module that provides a menu builder, a standard set of fields/templates/pages, and a bunch of other tweaks that I tend to use on every site. All the fields, templates and pages are set up in a streamlined and editor friendly way. I wasn't able to access their previous CMS backend for various reasons (I only got the MySQL dump), so when developing the site and data model in ProcessWire, I was able to completely re-envision the editor experience and the data model without bias. A quote from one of the marketing directors at Geffen Playhouse: "We absolutely love ProcessWire."
    4 points
  2. Update: Here's a little snippet how to use dynamic navigation items using the NavJSON feature: // in getModuleInfo() 'useNavJSON' => true, // enable JSON nav feature 'nav' => [ [ 'url' => 'contacts', 'label' => 'Contacts', 'icon' => 'users', ],[ 'url' => 'mailings', 'label' => 'Mailings', 'icon' => 'folder-open-o', 'navJSON' => 'mailings-nav', // this will call executeMailingsNav() to get items ],[ 'url' => 'groups', 'label' => 'Groups', 'icon' => 'users', ], ] // and in the module /** * JSON nav for mailings */ public function executeMailingsNav() { $options['add'] = null; // no link to add pages $options['edit'] = $this->mailer()->url."new/?channel={name}"; $options['itemLabel'] = 'label'; // use the label property as item label (default is name) $options['items'] = []; foreach($this->mailer()->channels as $channel) { $data = $this->wire(new WireData()); /** @var WireData $data */ $data->name = $channel->short; $data->label = "New ".$channel->name; $data->icon = "plus-circle"; $options['items'][] = $data; } return parent::___executeNavJSON($options); }
    4 points
  3. FieldtypeDecimal uses InputfieldFloat as its inputfield, and it's the renderValue() method that determines what is shown when a field is not editable. So you could do this: $wire->addHookAfter('InputfieldFloat::renderValue', function(HookEvent $event) { /** @var InputfieldFloat $inputfield */ $inputfield = $event->object; $field = $inputfield->hasField; if($field && $field->name === 'your_field_name') { $event->return = '$' . number_format((float) $inputfield->value, 2); } });
    3 points
  4. Or you use the new InputfieldTextTags: https://processwire.com/blog/posts/pw-3.0.177/ ๐Ÿ˜‰
    2 points
  5. I really must make more of an effort to add more sites to this forum - we've done some nice work really. Women / Theatre / Justice is a case in point. WTJ is the umbrella title for research and public engagement activities undertaken by academics from various universities in partnership with Clean Break theatre company. Clean Break was founded in the 1970s by two women in prison and focuses on using theatre to help create positive change in the lives of women with experience of the criminal justice system. We wanted to reflect the origins of the organisation so we created a home made 'zine' like design with typewriter fonts and adding noise to the photographs and images to get a photocopied feel: There's not too much bespoke coding going on functionally - we created the usual blog and events as well as a simple photogallery, but most of the technical effort went into working out the best way to apply textures and filters to the images so that the admins could upload new content without needing to phaff around in photoshop ( CSS 'backdrop-filter' for the win). One interesting thing got thrown up in accessibility testing; originally we'd created the design using a fixed with typewriter font and even though we'd set a pretty large font size with good contrast that passed our automated accessibility testing, we found that real world users still had difficulty reading it. So we changed that to a more modern and readable slab serif. Testing with real users is always a good move.
    2 points
  6. Token is stored in session data and thus indeed automatically invalidated if session expires. It can also be invalidated if another CSRF check runs meanwhile, so technically user doing something else on the site that triggers a CSRF check could result in such an issue. (It's possible to provide an ID argument for getTokenName(), validate(), etc. which may help with this, although it is likely quite a rare occurrence.) In my experience an issue like this would most commonly be a result of something in the user's environment changing, i.e. IP or some other value used for session fingerprinting has changed and thus session gets invalidated. This behaviour can be tweaked via the $config->sessionFingerprint setting. In my opinion a background process is rarely needed / useful. I wouldn't bother with it, unless this is a critical feature that definitely should never cause errors and where users are likely to spend loads of time. Also: session_start() would not remove the fingerprint issue, so this will likely have limited applicability. You could probably build a setup where the token is checked and/or regenerated periodically, but this is most likely overengineering. By the way: you can use echo $session->CSRF->renderInput() and use if ($session->CSRF->hasValidToken()) { ... } instead of custom markup and try-catch. Not a big deal, they just make things sightly more convenient ๐Ÿ™‚
    1 point
  7. I do it very similar. I use a settings page with a unique template name where the family settings are restricted to use it only once (for a single page). Then I can connect to the content by using a selector with the template name. This way it is save, even if later the page gets deleted (by accident) and recreated. Also the user is free to rename its title and URL without interfering the content pickup in my initial codes. (Selector without ID, path, name, title, etc) For contact information I used a Pro Field of type Textareas some years, that was named contact. It subfields have names like company, phone, email, address or street zip city, etc. Including links of social platforms etc. Now I use the newer Pro Field type Combo(!) for this, as it allows more flexibility. In the site/templates/_init.php I use a snippet like this to serve a shortcut for the use in my templates to this content: // object: firstname, lastname, phone, mobile, email, ... $contact = (object) $pages->get('template=my-unique-templatename')->contact->data;
    1 point
  8. I'm still using this approach and it works great for my needs ๐Ÿ˜‰ Look at the @BitPoet posts ๐Ÿ˜‰ R
    1 point
  9. Thanks @teppo! I used the code in a search function like you do in the Wireframe docs site. The init method works fine. Thanks for your help and for creating Wireframe and SearchEngine, trying to use them on everything i build nowadays.
    1 point
  10. Woah... that's a nice find here. I planned building exactly that tomorrow (but way more primitive than this) for a project.
    1 point
  11. A few days ago I stumbled upon this old module, which had been laying in the modules directory of one of my sites since 2017 in a half-finished state. I have no recollection why I left it like that, but figured it might be useful for someone, so here we go: https://github.com/teppokoivula/Snippets https://processwire.com/modules/snippets/ Snippets is a tool for injecting front-end code snippets (HTML/JS/CSS) into page content. The way it works is that you create a snippet โ€” say, a Google Analytics tag โ€” and then choose... which element it should be tied to (there are some pre-populated choices and custom regex option), whether it should be placed before/after said element or replace it entirely, and which pages the snippet should apply to. The "apply to" option also has some ready to use options (such as "all pages" and "all non-admin pages") or you can select specific pages... or use a selector. Snippets are regular markup, with the exception that you can use values from current page (behind the scenes the module makes use of wirePopulateStringTags()). Available hooks: Snippets::isApplicable, which receives the snippet object and current Page object as arguments and returns a boolean (true/false). Snippets::applySnippet, which receives the snippet object, page content (string), variables (an object derived from WireData), and an array of options for wirePopulateStringTags() as arguments and returns the modified page content string. That's just about it. It's a pretty simple module, but perhaps someone will find this useful ๐Ÿ™‚
    1 point
  12. Just in case... add this: https://processwire-recipes.com/recipes/logging-outgoing-emails/ to your setup and you will see each and every mail in the logs. Should only be used in DEV environments... privacy and such... you know.
    1 point
  13. Or you could use the wireIncludeFile-function of ProcessWire. I prefer this over the PHP include-function. ๐Ÿ˜‰ <?php wireIncludeFile('path/to/partial', [ "foo" => $foo ]);
    1 point
  14. Many examples on the net https://css-tricks.com/the-simplest-ways-to-handle-html-includes/ https://www.thoughtco.com/html-in-many-docs-with-php-3469181 https://www.phptutorial.net/php-tutorial/php-include-file/
    1 point
  15. Create a new php file inside template folder (or a subdirectory of it, ex. "inc") and paste your html portion you want to include in all the other templates, save it. Then, in all the templates, where you want that portion to appear just: <?php include('path/to/partial.php'); ?> // replace the path with yours.
    1 point
  16. I worked on this too. Attached is my modified admin theme I posted somewhere on the forum, but this version is bit modified, I tried to fix some focus issues... admin.less
    1 point
  17. I've tweaked the default colours (using the handy tool at https://learnui.design/tools/accessible-color-generator.html ) to be as close to the current colours as possible but still hitting AA contrast requirements. Here's before and after screenshots for comparison. I don't think it's too drastic a change... The admin.less changes for that are: /************************************************************** * Primary variables * * Adjusted to hit AA accessibility. * */ @reno-text-color: #354b60; @reno-link-color: #df2b5b; // #e83561; @reno-link-hover-color: darken(@reno-link-color, 10%); @reno-dark-background: #1C2836; @reno-muted-background: #f0f3f7; @reno-muted-text-color: #6f7580; // #8d939e; @reno-muted-text-color-alternate: #577898; // #6c8dae; @reno-primary-background: #008668; // #3eb998; @reno-secondary-background: #e2e9ef; @reno-success-background: #8bccde; @reno-success-color: @reno-text-color; @reno-warning-background: #FFD15E; @reno-warning-color: @reno-text-color; @reno-danger-background: #bc283d; @reno-danger-color: #fff; @reno-alert-background: #ffd; @reno-alert-color: @reno-text-color; @reno-primary-headline-color: #1C2836; @reno-secondary-headline-color: lighten(@reno-primary-headline-color, 30%); @reno-notes-text-color: @reno-muted-text-color; @reno-notes-background: #ffd; @reno-masthead-background: @reno-dark-background; @reno-masthead-link-color: rgba(255, 255, 255, 0.7); @reno-masthead-link-hover-color: lightblue; @reno-masthead-link-current-color: #fff; @reno-masthead-icon-color: #6f7580; // #8d939e; @reno-masthead-search-text-color: #8d939e; // #008668 @reno-masthead-search-background: transparent; @reno-masthead-search-border-color: lighten(#253447, 10%); @reno-masthead-search-focus-background: lighten(#253447, 5%); @reno-masthead-search-focus-text-color: #fff; @reno-masthead-search-focus-border-color: @reno-masthead-search-focus-background; @reno-masthead-search-icon-color: @reno-masthead-icon-color; @reno-button-text-color: #fff; @reno-button-background: @reno-primary-background; @reno-button-hover-background: @global-link-color; @reno-button-secondary-background: @reno-muted-text-color-alternate; @reno-dropdown-background: #fff; @reno-dropdown-color: @reno-text-color; @reno-dropdown-hover-background: #e2e9ef; @reno-dropdown-border-color: #d9e1ea; @reno-dropdown-border: 1px solid @reno-dropdown-border-color; @reno-dropdown-nav-icon-color: #667982; //#97aab4; @reno-page-list-link-color: #7a002b; @reno-page-list-link-open-color: #bb153e; @reno-page-list-icon-color: @reno-link-color; @reno-page-list-link-active-color: @reno-link-hover-color; @reno-page-list-link-hover-color: @reno-link-hover-color; @reno-page-list-action-link-color: #fff; @reno-page-list-action-link-background-color: @reno-link-color; @reno-page-list-action-link-hover-color: #fff; @reno-page-list-action-link-hover-background-color: @reno-link-hover-color; @reno-inputfield-border: 1px solid #d9e1ea; @reno-inputfield-input-background: #f0f3f7; @reno-inputfield-input-border-color: #b1c3d4 #cbd7e3 #cbd7e3 #cbd7e3; @reno-inputfield-select-background: #f0f3f7; @reno-inputfield-select-border-color: #cbd7e3; @reno-form-radio-checked-background: @reno-muted-text-color-alternate; @reno-offcanvas-text-color: @reno-text-color; @reno-offcanvas-link-color: @reno-text-color; @reno-offcanvas-link-hover-color: @reno-link-color; @reno-offcanvas-link-open-color: @reno-link-color; @reno-offcanvas-background: @reno-secondary-background; @reno-offcanvas-search-background: #fff; @reno-language-tab-background: transparent; @reno-language-tab-color: @reno-text-color; @reno-language-tab-current-background: #d2dce6; @reno-language-tab-current-color: @reno-primary-headline-color; @reno-language-tab-hover-background: @reno-muted-background; @reno-language-tab-hover-color: @reno-text-color; @reno-language-tab-empty-color: @reno-muted-text-color; @reno-table-header-color: @reno-muted-text-color-alternate; @reno-table-header-current-color: @reno-primary-background; I think it'd be worth updating to the defaults to something like this - seems an easy step in the right direction.
    1 point
  18. Thanks for your answer! I changed the .../site path just for the forum post. After restarting the browser (new session) the privace wire toolbar is shown up!
    1 point
  19. This feature sort of exists already, and it's set on the parent template. If a template is allowed to have only a single child template then there is a setting "Name format for children" available on the "Family" tab. Info: https://processwire.com/docs/modules/guides/process-template/ There is a module that extends the feature: But my preference is to just set a date format like "Y/m/d H:i:s" for "Name format for children" and then set the final title/name in a hook to Pages::added, e.g. $pages->addHookAfter('added', function(HookEvent $event) { /** @var Page $page */ $page = $event->arguments(0); if($page->template == 'your_template') { // Set whatever you want the title and name to be $page->of(false); $page->title = "Page ID: $page->id"; $page->name = $event->wire()->sanitizer->pageName($page->title, true); $page->save(); } }); Unfortunately "modified" and "created" cannot be used in a Pages::added hook because these properties are not populated on new pages until the next request. But you could use time(), or subsequently use the modified/created properties to set the title in a Pages::saveReady hook.
    1 point
  20. Thanks to bernhard and Autofahrn i have come up with this example code and run it in TracyDebugger on a test page with a image field and it works beautifully. <?PHP /* get and save a new image to image field Pageimages array */ $page->of(false); $pageImages = $page->images->add('https://www.somesite.com/image_of_tree.jpg'); /* save the page (perhaps not needed but there for comfort.) */ $page->save(); /* get the last added image */ $lastImage = $page->images->last(); /* debug before changes */ d($lastImage, '$lastImage before changes'); /* add tags to the image and description */ $lastImage->addTag('test'); $lastImage->addTag('Tree'); $lastImage->addTag('Syren'); $lastImage->addTag('Sun'); $lastImage->addTag('Sunny'); $lastImage->description = 'This is a beautiful tree.'; /* debug info */ d($page->images, '$page->images'); d($lastImage, '$lastImage'); /* save the page */ $page->save(); ?> I used the following API docs and mentioned forums users help to accomplish this: https://processwire.com/api/ref/pageimage/ https://processwire.com/api/ref/pageimages/ https://processwire.com/api/ref/pagefile/ https://processwire.com/api/ref/pagefiles/ Just wanted to post this at the end so others who wonder about this could get a starting point.
    1 point
  21. I sometimes end up with orphaned files as a result of doing mass imports during development. My code won't be quite right the first time around and I'll end up with extra and/or duplicated files. At least that was the case this last week. It was on a pretty large scale, so not something I wanted to clean up manually. Here's how I cleaned them out. Place this in a file in your site root called clean-files.php and then load it in your browser. /clean-files.php <pre><?php ini_set('max_execution_time', 60*5); // 5 minutes, increase as needed include("./index.php"); $dir = new DirectoryIterator(wire('config')->paths->files); foreach($dir as $file) { if($file->isDot() || !$file->isDir()) continue; $id = $file->getFilename(); if(!ctype_digit("$id")) continue; $page = wire('pages')->get((int) $id); if(!$page->id) { echo "Orphaned directory: " . wire('config')->urls->files . "$id/" . $file->getBasename() . "\n"; continue; } // determine which files are valid for the page $valid = array(); foreach($page->template->fieldgroup as $field) { if($field->type instanceof FieldtypeFile) { foreach($page->get($field->name) as $file) { $valid[] = $file->basename; if($field->type instanceof FieldtypeImage) { foreach($file->getVariations() as $f) { $valid[] = $f->basename; } } } } } // now find all the files present on the page // identify those that are not part of our $valid array $d = new DirectoryIterator($page->filesManager->path); foreach($d as $f) { if($f->isDot() || !$f->isFile()) continue; if(!in_array($f->getFilename(), $valid)) { echo "Orphaned file: " . wire('config')->urls->files . "$id/" . $f->getBasename() . "\n"; // unlink($f->getPathname()); } } wire('pages')->uncache($page); // just in case we need the memory } When you can confirm that it has found the right files (and no false positives) uncomment the "unlink" line above to have it remove the files on the next run.
    1 point
  22. hi, i'm probably a bit late... but i would have suggested to use markup regions which is imho the king of easy ways to do what you are looking for ๐Ÿ™‚ have a nice day
    0 points
ร—
ร—
  • Create New...