Jump to content

Jan Romero

Members
  • Posts

    680
  • Joined

  • Last visited

  • Days Won

    18

Everything posted by Jan Romero

  1. Can you not do this? $cl = $languages->get($user->language->name); $blog_title = empty($page->getUnformatted('title')->getLanguageValue[$cl]) ? 'Look Ma No Title' //user’s language title is empty : $page->getLanguageValue($cl, 'title'); //user’s language title is not empty The unformatted value of language fields should be a LanguagesPageFieldValue object that you can ask about language values without fallback: https://github.com/processwire/processwire/blob/dev/wire/modules/LanguageSupport/LanguagesPageFieldValue.php
  2. Try this? <?php $events = $pages->find('template=calendar-post'); // populate dayname according to user’s language $grouped = [ 'Mon' => (object)['events' => [], 'dayname' => 'Ponedeljek'], 'Tue' => (object)['events' => [], 'dayname' => 'Torek'], 'Wed' => (object)['events' => [], 'dayname' => 'Sreda'], 'Thu' => (object)['events' => [], 'dayname' => 'Četrtek'], 'Fri' => (object)['events' => [], 'dayname' => 'Petek'], 'Sat' => (object)['events' => [], 'dayname' => 'Sobota'], 'Sun' => (object)['events' => [], 'dayname' => 'Nedelja'] ]; foreach ($events as $event) { $dayname = date('D', $event->getUnformatted('Start_date')); $grouped[$dayname]->events[] = $event; } ?> <div class="tabs movies"> <!-- tab buttons --> <ul> <?php foreach ($grouped as $anchor => $day): ?> <li> <a href="#<?=$anchor?>"><?=$day->dayname?> (<?=count($day->events)?>)</a> </li> <?php endforeach;?> </ul> <!-- /tab buttons --> <!-- tab contents --> <?php foreach ($grouped as $anchor => $day): ?> <div id="<?=$anchor?>"> <?php foreach ($day->events as $p): ?> <div class="row movie-tabs"> <div class="col-md-2 col-sm-3"> <a href="<?=$p->url?>"><img alt="Movie title" src="<?php echo $config->urls->templates?>assets/images/movie-6.jpg"></a> </div> <div class="col-md-10 col-sm-9"> <span class="title">Action, Adventure, Fantasy</span> <h3 class="no-underline"><?=$p->title?></h3> <?=$sanitizer->truncate($p->body, 150);?> <p><a class="arrow-button" href="<?=$p->url?>">Beri več</a></p> <div class="row"> <div class="col-md-8 col-sm-9"> <hr class="space-10"> <span class="viewing-times"><i class="material-icons">access_time</i> Viewing times</span> <span class="time past">14:45</span> <span class="time">18:30</span> <span class="time">20:30</span> <span class="time">24:45</span> </div> <div class="col-md-4 col-sm-3 running-time"> <hr class="space-10"> 105 mins <span class="certificate">15</span> </div> </div> </div> </div> <?php endforeach ;?> </div> <?php endforeach ;?> <!-- /tab contents --> </div>
  3. strftime() is deprecated, you shouldn’t use it anymore. You can use IntlDateFormatter to format localised dates: $weekdayFormatter = new \IntlDateFormatter('es_CO', \IntlDateFormatter::FULL, \IntlDateFormatter::NONE, null, null, 'eee'); $events = $pages->find('template=calendar-post'); $grouped = []; foreach ($events as $event) { $dayname = $weekdayFormatter->format($event->getUnformatted('Start_date')); $grouped[$dayname][] = $event; } I wouldn’t really do this because you may get unexpected results and maybe even characters that are illegal in URL fragments (?). For example with de_DE you’ll get “Mo.” and “Lun.” with es_CO. I would probably keep the URL fragments English and have a second localised string. Also, the method above will only give you days that actually have events, so maybe pre-populate the $grouped array with all 7 days.
  4. I see, well, try this maybe? $events = $pages->find('template=calendar-post'); $grouped = []; foreach ($events as $event) { $dayname = date('D', $event->getUnformatted('Start_date')); $grouped[$dayname][] = $event; }
  5. Please use code formatting with the correct language. It’s the „<>“ button in the comment editor. Here it is: <?php $events = $pages->find('template=calendar-post'); $grouped = []; foreach ($events as $event) { $dayname = $datetime->date('%A', $event->Start_date); if (isset($grouped[$dayname])) { $grouped[$dayname][] = $event; } else { $grouped[$dayname] = [$event]; } } ?> <div class="tabs movies"> <ul> <!-- Events by day START --> <?php foreach ($grouped as $dayname => $eventsingle): ?> <li> <a href="#<?= $dayname ?>"><?= $dayname ?></a> </li> <?php endforeach;?> <!-- Events by day END --> <li class="date"><span>Wednesday, 8 March</span> </li> </ul> <!-- Events by day END --> <?php foreach ($grouped as $dayname => $eventsingle): ?> <div id="<?= $dayname ?>"> <!-- EVENT START --> <?php foreach ($eventsingle as $p): ?> <div class="row movie-tabs"> <div class="col-md-2 col-sm-3"> <a href="<?=$p->url?>"><img alt="Movie title" src="<?php echo $config->urls->templates?>assets/images/movie-6.jpg"></a> </div> <div class="col-md-10 col-sm-9"> <span class="title">Action, Adventure, Fantasy</span> <h3 class="no-underline"><?=$p->title?></h3> <?=$sanitizer->truncate($p->body, 150);?> <p><a class="arrow-button" href="<?=$p->url?>">Beri več</a></p> <div class="row"> <div class="col-md-8 col-sm-9"> <hr class="space-10"> <span class="viewing-times"><i class="material-icons">access_time</i> Viewing times</span> <span class="time past">14:45</span> <span class="time">18:30</span> <span class="time">20:30</span> <span class="time">24:45</span> </div> <div class="col-md-4 col-sm-3 running-time"> <hr class="space-10"> 105 mins <span class="certificate">15</span> </div> </div> </div> </div> <?php endforeach ;?> <!-- EVENT END --> </div> <!-- Events by day END --> <?php endforeach ;?> </div> What is $datetime? Also, what is $event->Start_date? That is to say, what types are they?
  6. If you’re running MySql 8 you can use the row_number window function: update pages p inner join (select id, row_number() over (partition by parent_id order by rand()) - 1 as randomsort from pages where parent_id = :YOUR_PARENT_ID) as r on r.id = p.id set p.sort = r.randomsort There may be faster ways to give consecutive sort numbers to random children, but this runs in the blink of an eye (Adminer says 0.005s for my 986 pages). Repeat until you get the order you like. Make sure you set the parent to “manual drag-and-drop” or you won’t see any effect.
  7. Hi, sounds like you want this: (only without the negating “!” in your case)
  8. This is in the selector docs, right were you would expect it ? Granted, the page is pretty long and cluttered when you’re just scrolling through, but it’s great for CTRL+F’ing and the table of contents at the top is very helpful. Mostly “find“ means “I have some criteria, give me any pages that match it” (only those the user may view, by default). “Get” means “I know exactly which page I want, give it to me”. Get gives you one specific page, Find gives you multiple. There is also pages()->findOne() if you only want a single page – the difference here is that this will check if you have access first, while pages()->get() will always give it to you if it exists, even if it’s unpublished or hidden. Anyway, rock on! I’m sure you will be enjoying PW for years to come ?
  9. What you’re doing very much hinges on the stability of your products and the order they’re in between rendering the form and processing its submission. If you open the form in your browser and let it sit there for an hour while you or someone else adds, removes or modifies a product, you will update the wrong products when you get back to the form! This is because you’re using the products’ positions in the selector results to identify them. It would be better to use their IDs or their page names because those are much less likely to change. Consider this: <form method="post"> <?php $products = $pages->find("template=product, sort=title"); foreach ($products as $product) { ?> <li> <h3><?=$product->id?>&nbsp;&nbsp;<input type="number" value="<?=$product->amount ?: 0?>" name="product[<?=$product->id?>]" min="0" style="width: 50px;">&nbsp;&nbsp;<?=$product->title?></h3> </li> <?php } ?> <button type="submit" name="submit" value="update" style="width: auto;">Bestand aktualisieren</button> </form> if ($input->post->submit) { $amounts = $input->post->product; $products = $pages->find("template=product, sort=title"); if ($amounts) { foreach ($amounts as $id => $amount) { $products->getPageByID((int)$id)?->setAndSave('amount', $amount); } } } Well, one answer is “because Ryan didn’t program it that way”. You were giving $pages->get() a Page that you already had. It certainly could work, because all the necessary information is there, but the get() method wasn’t programmed for that situation, because if you have the Page object already, why would you need to get it again? You can still do so by converting the Page object to a string (which is always its ID) or just getting its ID explicitly. Because your Page object was named $id, that would have been $pages->get($id->id). Here is an unrelated tip: you can just use single quotes instead of escaping the double quotes, because mercifully both are legal in HTML. You can even mix them in the same tag: <input type="text" value='call me ishmael'/>
  10. Yes, in a file with namespace ProcessWire that will let you use it: $foo = new \stdClass(); You can also put “use \stdClass” at the top if you need it a lot. The same goes for all the other stuff outside PW’s namespace. Often you’ll need \DateTime or \IntlDateFormatter for example. Edit: the technical term is “The Global Space”: https://www.php.net/manual/en/language.namespaces.global.php
  11. Put a backslash in front if you want to use PHP classes, or am I missing something? It’s near impossible to answer your question without knowing why you want to use stdClass. Could well be that ProcessWire has something suitable for your use case, but what is your use case?
  12. Granted, I don’t have much experience with the complex column types (I only just updated after 10 years or so, to get the Page type), but if you primarily use primitive types, ProFields Table has the benefit of being a single SQL join away. So if you’re like me and you sometimes want to do custom queries, that’s pretty cool. Plus, while I have nothing against repeaters, for some things it just feels icky to have the Page overhead. I have a site with playlists, so there’s a table with Artist, Title and some auto-generated normalisation columns for search, for example. Another site manages ”trips“ using a column for the place and two DateTime columns for the duration. I think the need to connect multiple Page references to some metadata like dates is pretty common, and ProFields Table is perfect for that.
  13. if ($input->post->submit) { //it is a mystery to us what this, and since it comes //from the client, it may also be a mystery to you $amounts = $input->post->product; //you’re looking up pages, so this will be a PageArray //with arbitrary numerical indices $products = $pages->find("template=product, sort=title"); if ($amounts) { //apparently we’re assuming the client sent us an //array with meaningful indices foreach ($amounts as $index => $amount) { //because $products is a PageArray, you’re going to //get NULL or a Page object when you access it like //this. In your case probably NULL unless your client //can somehow divine what pages result from the above //selector AND in what order $id = $products[$index]; //because $id is either NULL or a Page, this selector //cannot work. It will work if you put $id in quotes: //– if $id is NULL it will look for nothing and give you // a NullPage. //– if $id is a Page, PHP will call toString() on it, // resulting in its ID, so you’ll just get the same // Page back. //Both paths seem useless though? $pages->get($id)->setAndSave('amount', $amount); } } } This is my understanding from looking at it… Can you explain what $input->post->product contains?
  14. Looks like I subscribed not a moment too soon ? ProFields Table is the greatest ???
  15. I just stumbled upon this pretty recent article by Ionos, one of the biggest hosting providers in Germany (formerly 1&1, not sure how big they are elsewhere): https://www.ionos.com/digitalguide/hosting/cms/processwire/ It’s in english and includes a comparison to Wordpress (the tabular comparison is kind of broken, though).
  16. Interesting problem. If I understand correctly, you want to have two sources of truth that you need to connect somehow, i.e. the data inside the SVG and data from ProcessWire? I wonder if that’s worthwhile, because what are the chances you’ll want to change something on one side and not the other? To get translatable strings inside the SVG you could always use {placeholders} and populate them with WireTextTools, but as soon as you significantly change a text’s length, you’ll need to touch the SVG anyway, plus you will need to keep the placeholder names in sync. Obviously authoring the SVG is the most annoying part of managing this content, but I don’t see how you would get around it, so maybe try and make it the only part? You could cram everything into the SVG in some standardized way, like predefined classes and data- attributes, then analyze it with JS and build all the toggles dynamically.
  17. I just had this problem as well, using a path hook like this: wire()->addHook('/my/path', function($event) { /*…*/ }); In conjunction with a form like this: <form method="POST" action="/my/path/"> ProcessWire redirects the version with the trailing slash to the path matching the hook. I presume the same thing happens with normal pages and url segments as well, depending on the template settings. So if your redirect goes from /action_page to /action_page/ or vice versa, just request the exact url directly.
  18. To limit how many characters can be input, to go the field settings and set "maximum length" in the Input tab to a value greater than 0. You can also do this per template if you switch to a template using the dropdown in the upper right corner. Or you can go to the template settings and click the field there. To shorten the string during output, you can use WireTextTools: WireTextTools::truncate() method - ProcessWire API
  19. Yes, I couldn’t get it to work either, I amended my comment ? Bernhard’s snippet has a syntax error, here’s the working code: wire()->addHookAfter('Pages::saveReady(template=foo, id=0, status&'.Page::statusTemp.')', function($event) { $event->arguments(0)->status = 1; }); I also added the status check, because you don’t need this to run for every new page. API-created pages will be published by default, for example. Also I’m not sure I would just set the status to 1, in case PW or some other hook wants to set something else, like Locked or Draft or something. Probably better to just remove the ones you want to remove specifically.
  20. When ProcessPageAdd quick-creates a page, it gives it a temporary status Page::statusTemp that is removed when the page is next saved using the UI. I imagine you need to remove this status in your hook to make the lightning symbol go away. The temporary status is there so pages that were accidentally created can be cleaned up automatically. I would probably hook ProcessPageAdd::processQuickAdd instead of Pages::save: https://github.com/processwire/processwire/blob/master/wire/modules/Process/ProcessPageAdd/ProcessPageAdd.module#L1091 Edit: Can’t get processQuickAdd to work… Maybe because it redirects the hook doesn’t get a chance to run? Still, it should be sufficient to hook into ProcessPageEdit::execute: wire()->addHookBefore('ProcessPageEdit::execute', function(HookEvent $event) { /** @var Page $page */ $page = $event->object->getPage(); //if the page has statusTemp it was probably created by ProcessPageAdd::processQuickAdd if ($page->hasStatus(Page::statusTemp)) { $page->removeStatus(Page::statusTemp); $page->removeStatus(Page::statusUnpublished); $page->save(['quiet' => true, 'noHooks' => true, 'noFields' => true]); wire()->message('Auto-published that for you. You’re welcome.'); } });
  21. Well, it’s kind of a broad question. If you’re talking about having different language versions of your pages, ProcessWire comes with built-in support for managing that content. You’ll have to figure out whom to show which language content yourself, though, for example by using the Accept-Language header. If you only need region-specific content and no multi-language, you could abuse ProcessWire’s language system for that, too. If you need both dimensions, you’ll have to figure out how to manage all that content. Do you need everything for every region and language, or maybe just a sprinkle here and there such as “this site is not available in your country thanks to the S. Fischer Verlag GmbH”? I guess the answer is, it’s up to you? ProcessWire doesn’t have a built-in feature that lets you connect content to predefined regions or detects users’ regions for you, but you’ll want to decide these things for yourself anyway. My example used an external service that looks up IP adresses. There are drawbacks to that technique that you may not want. Other options include just asking the user or using the browser’s geolocation API (AFAIK this will only give you coordinates, so again you’ll need to use a service to get the “region”, or calculate it yourself if you’re into geomatics).
  22. Wow, I didn’t believe this until I tried it ? However, since you’re only looking for one image, try using get() instead of find(): $image = $p->images->get("videocounter=270"); Or use first() to get the first matching image: $image = $p->images->find("videocounter=270")->first(); Otherwise find() will give you a Pageimages object that potentially holds multiple images, so calling url() on it won’t work.
  23. Sure, just copy and paste this to your site $http = new WireHttp(); $region = $http->getJson("http://ip-api.com/json/{$session->getIP()}?fields=city,countryCode"); user()->setLanguage($region['countryCode']); //well… it’s not *this* easy. you’ll have to connect your languages to ISO 3166-1 alpha-2 country codes somehow echo '<marquee><blink>' . sprintf(__('Hot milfs looking to hook up in %s!'), $region['city']) . '</blink></marquee>';
  24. There is nothing like this specific to ProcessWire, you can just use any CSS you want. For example this is the first Google hit for “css framework”: https://github.com/troxler/awesome-css-frameworks
×
×
  • Create New...