Jump to content

Jan Romero

Members
  • Posts

    612
  • Joined

  • Last visited

  • Days Won

    15

Everything posted by Jan Romero

  1. I agree that’s a great feature, but what is your request exactly?
  2. @snck Maybe you want take my fork for a spin: https://github.com/JanRomero/AdminPageFieldEditLinks I’ve only done rudimentary tests, but those seemed fine. It just adds a span around the locked inputfield’s value that tells the module’s javascript part what to do. edit: the fork is gone since @thetuningspoon was so kind as to merge the changes. please blame me if I broke anything!
  3. If you install the fieldtype first, it’ll actually install the inputfield automatically, but not the other way around ?
  4. You mean when you set the inputfield’s visibility to “Locked”? Because I’m gonna open a pull request for that later when I get home ?
  5. @Leftfield Mh, that seems strange? It should simply update the row. A row will look like this, where the second column is “data” and contains the latest result from OpenWeatherMap and the last column is “timestamp” and remembers when the result was obtained: 2287 {"coord":{"lon":-55.1700000000000017053025658242404460906982421875,"lat":5.87000000000000010658141036401502788066864013671875},"sys":{"country":"SR","timezone":-10800,"sunrise":1587547818,"sunset":1587592050},"weather":[{"id":802,"main":"Clouds","description":"M\u00e4\u00dfig bew\u00f6lkt","icon":"03n"}],"main":{"temp":23.3299999999999982946974341757595539093017578125,"feels_like":25.0799999999999982946974341757595539093017578125,"temp_min":23.3299999999999982946974341757595539093017578125,"temp_max":23.3299999999999982946974341757595539093017578125,"pressure":1010,"humidity":93},"wind":{"speed":4.32000000000000028421709430404007434844970703125,"deg":53},"clouds":{"all":34},"dt":1587543285,"id":3383329,"name":"Distrikt Paramaribo"} 3383329 2020-04-22 11:12:14 That’s from the table “field_weather” (depending on what you called the field in your setup). Do you mean a different table, maybe?
  6. The thing about the screenshot is that the module doesn’t generate markup unless you configure it to. You can specify the markup you want to output for each weather condition in the module settings according to OpenWeatherMap's icon codes. See the other screenshots for an example. It's a bit awkward ;‍)
  7. @bernhard Hi, yeah, it seems to work perfectly fine for the humble job it does ? It runs every couple of hours on Ennepe-Ruhr-Tourismus (it alternates between showing the weather and a tag line).
  8. @Leftfield Uh, hey man, sorry, never saw your comment. I updated the module to use ProcessWire’s WireHttp, which should pick an appropriate way to request the data. I think it prefers cUrl and falls back to fopen. I also submitted it to the modules directory, because why not, I still run it in production… Not sure what you mean in your second question. The module only stores the latest data it got as a cache. It won’t append records to the database. Every database row corresponds to a single page in your ProcessWire setup that uses the field.
  9. Hi, I would post an issue on GitHub, but I’d like to understand the problem better. Because us Germans are very diligent and conscientious about that sort of thing, my users do things like upload images containing a copyright symbol in the file name… ProcessWire wants to sanitize this and puts it through, among other things, Sanitizer->nameFilter(). This is called with Sanitizer::translate in the $beautify argument (what is beautify?), so it puts the file name through mb_strtolower() (why is it only lowercased if Sanitizer::translate is passed and multibyte support is on?). After that, because the $beautify argument was anything, not necessarily Sanitizer::translate, the file name is also put through iconv("UTF-8", "ASCII//TRANSLIT//IGNORE", $value). That’s the point at which “©” is converted to “(C)”, capital C. More things happen, but the capital C stays and becomes part of the file name in the page’s assets dir. Then a bunch of other things happen and later PW wants to check the file with filemtime(), looks for the name in all lower and throws because it doesn’t find it. So somewhere in the process, PW handled the file name or path in two seperate ways, one time resulting in an all lower case version and one time still containing the C. Now I’d just make a pull request where I do another mb_strtolower() after iconv, but I figure there is a reason why those things happen in separate code paths. Obviously the nameFilter() method is not expected to only ever give all-lower results. Here is the snippet: if($beautify && $needsWork) { if($beautify === self::translate && $this->multibyteSupport) { $value = mb_strtolower($value); if(empty($replacements)) { $configData = $this->wire('modules')->getModuleConfigData('InputfieldPageName'); $replacements = empty($configData['replacements']) ? InputfieldPageName::$defaultReplacements : $configData['replacements']; } foreach($replacements as $from => $to) { if(mb_strpos($value, $from) !== false) { $value = mb_eregi_replace($from, $to, $value); } } } //this happens independently of the lowercasing if(function_exists("\\iconv")) { $v = iconv("UTF-8", "ASCII//TRANSLIT//IGNORE", $value); if($v) $value = $v; } $needsWork = strlen(str_replace($allowed, '', $value)); } So, maybe the iconv() business should go inside the preceding if block? Maybe it should just go above? Maybe the capital C is expected from this method and the fix is somewhere else entirely. I’ve also tested ®, ™ and ℗. ℗ actually works because it’s just stripped at some point. ® and ™ both end up in caps and throw. Thanks for reading ;‍)
  10. Can you show the structure of your data in PW? E.g. where and how is “April 10” stored? I gotta say, I do not like that site. Why does the navigation disappear when I choose a date?! Why does resetting the navigation require a full page reload when everything is still on the page, just hidden?! As I understand it, it’s a collection of links in which each link has a url, a description, a date and a category. Initially all links are displayed, grouped by category, sorted by date (desc). Each link’s date is stored as a class on its list item in the form “d2020-03-31”. The sidebar is just all dates and if you click one it hides everything that doesn’t have the corresponding class using Javascript. The reset could just be: document.querySelectorAll('h3, li, .nav').forEach(li => {li.style.display = null}); (or something extremely similar) If I were going to replicate this frontend I would probably put the dates into data attributes instead of classes. And I’d make a fallback for people without javascript where the sidebar links to a urlSegment and the list is filtered on the server unless JS hijacks the click events. I might also think about ways not to load everything every time, although there are pros and cons. The bandwidth is negligible, but users might be intimidated by the long page and browsers might struggle to keep up, but on the other hand I love a site that is complete and searchable as soon as it’s done loading…
  11. Easiest way might be to hook after Pagefiles::delete and just empty the “unlinkQueue” array. delete() just calls remove(), which removes the item from the Field and schedules the file for deletion by putting it into unlinkQueue: https://github.com/processwire/processwire/blob/51629cdd5f381d3881133baf83e1bd2d9306f867/wire/core/Pagefiles.php#L433 edit: okay, that won’t work because unlinkQueue is protected. i’m running out of ideas. if you modify core/pagefile.php to add three underscores in front of unlink(), you can replace that method with a hook: wire()->addHookBefore('Pagefile::unlink', function (HookEvent $event) { $event->replace = true; }); that’ll work, but it’s ugly.
  12. Can you not just load the page and access the repeater items from there? Not sure if there is a way to do this with a $pages->find() selector, seems like it would be useful though.
  13. Have you considered using the custom user template and parent feature? That way you wouldn’t need to link the profile page to a user. You could just put user pages in the appropriate place in the page tree ans use those as profiles.
  14. Are you talking about ethicalby.design? Because there the form’s action points to "./" regardless of the page you’re on, so if you only process the form submission on the home page, it should always be directed there, i. e. "/".
  15. How to add a new method with a hook. So if you take your that code from Pagefiles->findTag(): /** * Return all Pagefile objects that do NOT have the given tag(s). * * Given tag may be any of the following: * * - `foo` (single tag): Will return all Pagefile objects not having the specified tag. * - `foo|bar|baz` (multiple OR tags): Will return Pagefile objects having not having ANY of the tags listed. * - `foo,bar,baz` (multiple AND tags): Will return Pagefile objects having NONE of the tags listed. * - `['foo','bar','baz']` (multiple AND tags array): Same as above but can be specified as an array. * * @param string|array $tag * @return Pagefiles New Pagefiles array with items that didn't match the given tag(s). * @see Pagefiles::getTag(), Pagefile::hasTag(), Pagefile::tags() * */ wire()->addHook('Pagefiles::excludeTag', function (HookEvent $event) { $pagefiles = $event->object; //the Pagefiles object. For every instance of $this from the original code we will use $pagefiles instead. $tag = $event->arguments(0); //the argument passed to the method. so it will be e.g. $images->excludeTag($tag) $items = $pagefiles->makeNew(); foreach($pagefiles as $pagefile) { if(!$pagefile->hasTag($tag)) //the only real change is introducing this exclamation mark to negate the condition $items->add($pagefile); } $event->return = $items; }); Now because we just negate the result of $pagefile->hasTag(), we need to be aware of the inverted logic. If you pass multiple tags it should act the way I described in the comment above, which is just Ryan's comment inverted. So if you pass 'foo,bar,baz', you may still get images tagged as 'foo'. (i haven't tested any of this. i may have done it completely wrong.) Edit: Apologies, I did indeed do it wrong. Fixed the code above. @Andi
  16. The code says no. Arguably the function should use $options['allowSchemes'][0] if present, or something. I would suggest just replacing it: $url = substr_replace($url, 'https://', 0, 7);
  17. In a template $page is the current page that your visitor has requested and is being output for them. $pages gives you access to all pages in the system by calling methods like $pages->find() or $pages->get(). “Child” is only one child. When you call $page->child() it will give you the first child. If your page has multiple children, you may want all of them. That’s when you call $page->children(). If you want only some children, you can pass a selector to the method. See the docs herehttps://processwire.com/api/ref/page/child/ and here https://processwire.com/api/ref/page/children/. “Render” usually implies that the method generates markup aka HTML code for you. When you use get() you simply get the thing you asked for. It may be a Page object or the contents of some field or something else, depending on the context. ProcessWire has the concept of “Output Formatting”, which means that field values can sometimes also generate/contain markup themselves, without the word “render” showing up anywhere. So it’s not all that clear cut, but that’s the basic idea. ”Rendering“ means taking something that can’t be output to the browser directly and formatting it, usually as HTML. Sometimes ProcessWire makes its features available to you as properties AND as methods. This can be convenient but also confusing. You’ll have to consult the docs for each individual case, or just test out what works. If you want to pass arguments/options, you must use the function way. If you’re not familiar with the concepts of properties and methods/functions, perhaps familiarize yourself with PHP basics before reading the ProcessWire docs, or just read the PHP docs as you go along. Or ask in the forums here, PW has an exceptionally friendly community. Welcome to ProcessWire ? Edit: To answer your actual question, you cannot do $page->children->image->url, because children is a PageArray. It's a way to collect multiple pages, in this case all the child pages of $page. So when you call children->image, it doesn't know which child page to take the image from. You could do $page->child->image->url. That would give you the image from the first child page. Be aware that there may be no children, or the first child may not have an image. These cases may need to be considered as your website grows.
  18. Indeed, that’s because the the message is set before the admin controller actually runs and saves the the change. Basically, every page in the admin backend executes a specific “Process”. You can hook into the base Process class to add your message only after a process has been executed: $this->addHookAfter('Process::execute', function($event) { if ($this->wire('user')->isLoggedin() && $this->wire('config')->myCrazySetting) $this->message("Hope you know what you’re doing with that setting!"); }); This can be put in the same file, above the controller line.
  19. You could just put it into templates/admin.php. The file should already be there. Here is the entire default file plus a line for the notice: <?php namespace ProcessWire; /** * Admin template just loads the admin application controller, * and admin is just an application built on top of ProcessWire. * * This demonstrates how you can use ProcessWire as a front-end * to another application. * * Feel free to hook admin-specific functionality from this file, * but remember to leave the require() statement below at the end. * */ if ($user->isLoggedin() && $myCrazySetting) $this->message("This is the notice text"); require($config->paths->adminTemplates . 'controller.php');
  20. This is what it should look like on page 4, I assume? I’m not sure this will be possible with a single call to renderPager(). MAYBE you’ll be better off just rolling the pagination markup yourself. For example you could do this: $totalPages = ceil($posts->getTotal() / $posts->getLimit()); for ($i = $input->pageNum+1; $i <= $totalPages; $i++) { echo "<li><a href='{$page->url}{$input->urlSegmentString}/page{$i}'>{$i}</a></li>"; } for ($i = 1; $i <= $input->pageNum; $i++) { echo "<li><a href='{$page->url}{$input->urlSegmentString}/page{$i}'>{$i}</a></li>"; } Mostly you’ll need to look out for the href attribute, i.e. my code throws away any GET variables and uses the default pagination prefix “page”. Also you don’t get any of the niceties ProcessWire gives you by default. If you rely on those, maybe use renderPager() and rearrange the generated Markup. Both options are pretty hackish. You’ll have to choose which one is the least pain in the butt for your system…
  21. Btw, if you’re going to do $page->references()->count(), you will be better off telling references() that you just need the cound directly. In the end, these methods and properties all end up in FieldtypePage and provide some efficiency tricks like this. However, this will always query the database for every page in your array and every page field in your system, so if you want to get real gainz, you're probably best off just asking the database for your pages and the count somewhat like this: $query = wire('database')->prepare('select data, count(paged_id) from field_yourpagefield group by data'); $query->execute(); $results = $query->fetchAll(\PDO::FETCH_KEY_PAIR); $brands = wire('pages')->getById(array_keys($results), ['template' => wire('templates')->get('brand') , 'findTemplates' => false , 'getNumChildren' => false , 'joinSortfield' => false]); echo $brands->each(function ($brand) { return '<li>' . $brand->title . ' was referenced ' . $results[$brand->id] . ' times.'; }); At least that is what I was going to write reflexively before checking the core for something ready-made. That's the amazing thing about ProcessWire, that something like this just already exists and makes everything super easy.
  22. It’s actually really easy: $brands = $pages->find('template=brand'); echo $brands->sort('-numReferences')->each("<li>{title}: {numReferences}"); Whether it’s very efficient is a different story. I wouldn’t know. Be aware that you have to sort the PageArray. Putting it in the find() selector won’t work. Edit: actually, you probably want hasReferences, as per the documentation: $numReferences Total number of pages referencing this page with Page reference fields. $hasReferences Number of visible pages (to current user) referencing this page with page reference fields.
  23. To take the last element of a WireArray and put it at the beginning, you can do this: $products->prepend($products->pop()); To get only pages after the current product, you can do this: $products = $pages->find("sort>{$page->sort}") Maybe post some of your code?
  24. Your code as well as eelkenet’s should work if you set output formatting to false at the top instead of at the bottom. AFAIK, without output formatting, File fields always return a WireArray, or rather, a Pagefiles array, which inherits from WireArray. In general the reason you disable output formatting is that you can work with the “raw” data before saving. Changing the formatted data and then only disabling output formatting before the save() should be pointless and/or introduce errors. For example, if you have a field with Markdown formatting and you modify its contents without disabling output formatting, you’re modifying and saving the rendered HTML, destroying your original Markdown markup.
  25. An easier way to set the status code: http_response_code(303); Available since PHP 5.4.
×
×
  • Create New...