-
Posts
5,039 -
Joined
-
Days Won
340
Everything posted by Robin S
-
Thanks @BitPoet! I think there might be some typos in the mutator example - maybe you meant: $blogposts = $pages->find("template=blog-post, sort=created"); $grouped = $blogposts->groupBy(function($pg) { return array(strftime('%Y', $pg->created), strftime('%m', $pg->created)); });
-
@ridgedale, the essence of your scenario is that you have some newsletters, and for each newsletter you have: 1. A file 2. Some metadata about that file (its month and its year) You want to associate the metadata with the file. Using a file naming scheme and a folder structure is one way to associate the metadata with the files, but it's not the only way, nor is it the "ProcessWire way". The ProcessWire way is to use pages and/or the metadata fields that are built into File fields. If you have a lot of metadata to associate with a file then the most powerful approach is the "one page per file" approach, which is what @LMD is suggesting. This way you can use all the available PW fields in your file page to store different kinds of metadata about each file. But the downside to this approach is that the UI/workflow can be a bit less than ideal for clients, especially if they have a lot of files that they want to upload at once and populate metadata for. That's because, generally speaking, they will have to edit each file page individually (although there can be solutions to this such as Lister Pro inline editing, Batch Child Editor, and automatically creating a page for each file similar to what is done in AutoImagePages). But you only have a little bit of metadata per file so I don't think you need to go this sophisticated. Instead I suggest you use a repeater for the years, and file tags for the months. See these screenshots... Then you can get the latest newsletter like this... $newsletters_page = $pages->get("template=newsletters"); $latest_year = $newsletters_page->newsletters->find("newsletter_files.count>0, sort=-year")->first(); $latest_newsletter = $latest_year->newsletter_files->sort("-tags")->first(); $month = substr($latest_newsletter->tags, 3); echo "<a href='$latest_newsletter->url'>$month $latest_year->year</a>"; The pages that visitors browse the newsletters through can be completely decoupled from the storage of the newsletter files. You just get the relevant repeater items by year according to the page being viewed, e.g. $years = $newsletters_page->newsletters->find("year>=1980, year<1990, sort=year"); You could even do it without actual pages for each decade, and use URL segments to get any range of years.
- 8 replies
-
- 6
-
-
- data archive
- custom upload method
-
(and 1 more)
Tagged with:
-
@bernhard, you are of course free to put whatever you like into your modules. However, having your modules "phone home" like this discloses data that users may not want shared. At the minimum the website URL is disclosed. Not every site that exists on the internet is intended for public access. There are things like staging servers, and probably a whole range of other sensitive sites. My personal opinion is: 1. I think there should be a very clear and prominent statement so that users know that the module will send data to a third party, and what data will be sent. And I'm not sure that only a notice in the module readme would be satisfactory because users might download via the PW admin without seeing the readme. And if you start adding this to existing modules that didn't have it before it could pass by unnoticed when the module is updated. Basically there needs to be informed consent before data is sent, and probably also a privacy policy. 2. I think this crosses a line that shouldn't be crossed, and sets a dangerous precedent that if followed by others could be harmful to the PW project/ecosystem. There is a huge amount of trust placed in third-party modules by users. Modules can potentially access any website data. The very notion that a module phones home erodes trust. We don't want to create a sense of unease where every time a user contemplates installing a module they feel like they ought to comb through the source code to see what the module might be disclosing to a third party. In the bigger picture, I'd like to see PW get a reputation as being a system suitable for large institutional and government clients. Here in New Zealand, SilverStripe is in the enviable position of being seen as the go-to system for government websites. I think PW should be competing in this space. But government and institutional clients won't touch PW with a pole if there is a perception that there are privacy issues with modules in the PW ecosystem. I think the right way to track software popularity is by counting downloads, not phoning home. Sadly GitHub and GitLab don't provide useful tools for this, but that is another discussion.
- 17 replies
-
- 11
-
-
PW does not really use the concept of folders. I agree with @flydev - you should use pages in place of folders. I've used a repeater for doing something quite similar to what I think you are describing. Create a page that will be the central place where all files are uploaded. Add a repeater to that page's template, containing an integer field for year and a files field to hold the uploads. Users will upload their files to the relevant year item. Using API code you can get the most recent year (i.e. the highest integer) and the most recently added file in that year (the last file in the field). For automatic upload renaming there is @adrian's Custom Upload Names module.
- 8 replies
-
- 3
-
-
- data archive
- custom upload method
-
(and 1 more)
Tagged with:
-
Would you mind clarifying what you mean here? Are you saying the PW modules you share here with the community might start sending data to your Google Analytics account?
-
You have to check from the module which has its class name stored in the modules directory. For Hanna Code this is TextformatterHannaCode (not ProcessHannaCode). For modules such as Hanna Code that contain additional sub-modules the simplest way to update is probably via ProcessWireUpgrade - then you don't need to think about which class name is the one stored in the modules directory.
-
Hi @adrian, I'm seeing an issue in the Console panel where the indentation (tabs) of saved snippets gets lost when the page is reloaded. In the screen capture below I save the snippet with the correct indentation and I can load that snippet again okay until I reload the page. After that the snippet doesn't load with the correct indentation.
-
[solved] when default field value is an image file
Robin S replied to neosin's topic in Getting Started
Not sure what you mean here. When you use the feature I mentioned to select a page that will hold the default value for the image field, the image field will have the value of the default field when it is empty on a particular page. The value will be a Pageimage object or a Pageimages object depending on the field settings (and assuming you have one or more images in the field on the page used for the default value). You shouldn't need to do anything different to get the object or any of its properties (url, etc) than you would do if the field was populated on the page. In other words, you can do something like... $page->image->size(400,300)->url ...and it will work the same regardless if the image is coming from an image that is actually in the field on that page, or the default value when the field is empty. -
[solved] when default field value is an image file
Robin S replied to neosin's topic in Getting Started
-
I had a look at this, and it seems it isn't possible to directly set the optionAttributes property of inputfields that extend InputfieldSelect. That is probably why @kixe made this module. But what you can do is use a hook to remove the existing options, and then add them back with some attributes... $wire->addHookBefore('InputfieldCheckboxes::render', function(HookEvent $event) { $inputfield = $event->object; // Only for a specific field if($inputfield->hasField != 'your_field_name') return; $options = $inputfield->options; // Get the existing options $inputfield->options = []; // Remove all the existing options // Add the options back with attributes foreach($options as $value => $label) { // Set whatever attributes you want as $key => $value in the last argument of addOption() $inputfield->addOption($value, $label, ['disabled' => 'disabled', 'data-foo' => 'bar', 'class' => $this->sanitizer->pageName($label, true)]); } $event->return = $inputfield; });
-
Extending template role access with some custom code
Robin S replied to The Frayed Ends of Sanity's topic in General Support
If it's working for your purposes then I think it's fine to do it the way you are. My suggestion is that you have the function return false by default rather than true, and reverse the logic in the conditionals. In general, when permissions are involved I'd say it's best practise that the default state be that the user can do nothing, and then you actively add permissions as needed. This post did get me thinking about if you could use the core permissions system for your needs. I found that when creating a new custom permission, if you prefix the permission name with "page-" then it gets some special features: namely that you can activate that permission for a role individually for each template. So that sounds promising for your needs, but I found that the downside is that the user must have the "page-edit" permission in order for the individual template activation to work. So that probably rules the option out because it's likely that you would want these permissions to be usable on roles that aren't allowed to edit pages. Maybe someone can shed some light on how "page-" prefixed permissions work. Are they mentioned anywhere in the docs or a blog post? Is there any other way to assign permissions on a per-template basis besides making them "page-" permissions? And do folks think it would be worth opening a request for per-template permissions that don't require the page-edit permission? -
We do really need @since added to the documentation so module developers can know which methods will require which PW versions, and avoid to confusion when working on older sites. Maybe you could "thumbs up" the existing request and hopefully Ryan will act on it soon: https://github.com/processwire/processwire-requests/issues/158
-
No, I don't mind. Go right ahead.
-
How long have you been using this mouse for? Do you really prefer using those mouse buttons over keyboard buttons? I'm always looking for better efficiency and ergonomics, but I've always found the mouse to be the least ergonomic component of computers. I find I get mouse fatigue much faster than keyboard fatigue (the scroll-wheel in particular is a killer). Those 12 thumb buttons are interesting, but I would have thought that going from using all ten fingers/thumbs on a well-spaced keyboard to doing more work using a single thumb in a tiny space would be less comfortable and more prone to RSI. And for coding, isn't using the keyboard unavoidable? If the keyboard is unavoidable, wouldn't it be most efficient to do as much as possible with the keyboard and as little as possible with the mouse? Genuinely curious because I've never used a mouse like this before.
-
The PHP docs for the function say "yes".
-
Add Helper.php file to Uikit Admin Theme, to allow hooks
Robin S replied to Federico's topic in Themes and Profiles
In terms of adding markup to admin themes, the following hookable methods are common to all admin themes: AdminThemeFramework::getUserNavArray Allows you to add items to or remove items from the "user" dropdown menu (Edit Profile, etc). AdminTheme::getExtraMarkup Allows you to add markup to the following regions of the admin template: head notices body masthead content footer sidebar For example... $wire->addHookAfter('AdminTheme::getExtraMarkup', function(HookEvent $event) { $regions = $event->return; $regions['masthead'] .= '<p>hello</p>'; $event->return = $regions; }); So not every place in the admin theme markup is covered (I don't see how it could be), but it allows for simple additions to the admin theme. No doubt you would need some custom admin CSS to position and style whatever markup you add. Other approaches... Manipulate the rendered markup string For some cases this might do the job. For example... $wire->addHookAfter('Page::render', function(HookEvent $event) { $page = $event->object; if($page->template == 'admin') { $out = $event->return; $out = str_replace('<div class="uk-navbar-right">', '<div class="uk-navbar-right"><p>hello</p>', $out); $event->return = $out; } }); Copy your preferred admin theme module from /wire/modules/AdminTheme/ to /site/modules/ Make whatever changes you need to the copied files, perhaps by including a separate PHP file at the right place in the template markup. That will make it easier to update the admin theme module from the core version when you choose to. -
To check if a given file exists, I think you would be better off using PHP's file_exists(). It's very fast and it caches so I doubt it would have any significant impact on performance.
-
I got tired of having to open the link dialog in CKEditor in order to check where a link is pointing to, so made this simple plugin. Link Hover A plugin for CKEditor. Shows the href attribute of a link in a tooltip when the link is hovered. This saves you from having to open the link dialog in order to check where a link points to. Installation This readme assumes installation in ProcessWire CMS. The plugin folder must be named "linkhover" – if necessary, rename the folder to remove the "-master" suffix added by GitHub. Copy the "linkhover" folder to /site/modules/InputfieldCKEditor/plugins/ In the field settings for each CKEditor field that you want to activate the plugin for, check the "linkhover" checkbox at Input > Plugins > Extra Plugins https://github.com/Toutouwai/linkhover
-
In this situation you aren't using WireUpload directly - rather Pageimages::add(). You can only give this method one image path at a time, but if you call it repeatedly in a loop it will keep uploading the images you give it until it is finished (or until PHP times out - you might want to increase max_execution_time if you have a lot of images to upload).
-
is there a list of core field options/properties for module development?
Robin S replied to neosin's topic in Getting Started
Besides Adrian's excellent suggestions... Many of the common inputfield properties are outlined here: https://processwire.com/api/ref/inputfield/ For properties specific to a particular inputfield type you can read the code comments in the core files, or if you have the very handy API Explorer pro module you can browse the properties in a nice interactive interface within the PW backend: -
For a page $p with images field "images" and an array of image paths/URLs... $p->of(false); $u = new WireUpload('image_check'); foreach($image_paths as $image_path) { // Get path parts $parts = pathinfo($image_path); // Convert filename to PW format $image_name = $u->validateFilename($parts['basename']); // Look for filename in images field if(!$p->images->get($image_name)) { // Image does not already exist in field, so add it $p->images->add($image_path); } } $p->save();
-
This fieldtype wont be suitable for what you want. Instead, add a hidden textarea field to your templates, then in a saveReady hook loop over the template fields and add markup-free text (use strip_tags) to the textarea. You'll need an if/else structure to handle all the different field types you want to support.
-
Oh man, I want the best of both worlds - some of those pimped out Aussie 4WD campers are insane! Kiwis love their off-roading but I've never seen such amazing 4WDs until we went to the top end. Some folks have dropped some serious money on those. Proper go-anywhere Landcruisers with every conceivable mod-con built in. Love it.
-
Not at all. My partner and I had three weeks exploring NT's top end last winter and had nothing but good experiences. The Aussie grey nomad idea is genius - that's how I want to spend my retirement.