Jump to content

Jan Romero

Members
  • Posts

    612
  • Joined

  • Last visited

  • Days Won

    15

Everything posted by Jan Romero

  1. I take it you don’t want to show the date the page was created? That would be $page->created. $page->sort gives you the zero-based sort index, but it’s only unique in relation to the parent. This might be the closest to your requirement. $page->id is not necessarily consecutive and starts at 1000, but it’s unique site wide. I believe ProcessWire doesn’t reuse deleted IDs, so they should reflect the order of page creation. However, every new admin page and repeater item will increase this number. Do with that what you will.
  2. I assume you have a special template for /functions/ and you have set up your config.php to auto-append _main.php. You can exclude templates from auto-appending and auto-prepending in the “files” tab of the template settings. If auto-append is active, there will be a checkbox called “Disable automatic append of file: _main.php”. Regardless, it’s always a good idea to die() as soon as possible. In your case, I would advocate putting a die() at the end of each if ($command ...) block, unless there’s something you need to do afterwards. Probably a good idea to use a switch, too, then.
  3. Sure, just link to the page without the GET parameters, check if they’re in $input->get or not, and build (or omit) your selector strings accordingly. I’m sure you can figure it out By the way, you should read up on sanitizers and use them with $input, because you’re essentially letting anyone modify the variables in your PHP script now.
  4. Oh, nah, $city is just a page object and weather is a field. The sample was taken out of a foreach loop. To set the city id via API, you can do $page->weather = 12345 and save the page/field.
  5. Ooooh, I didn't know about $input->it. That's awesome. Where does it come from, though?! I've never seen it anywhere. Where in the core is it prepared?
  6. Your code looks very mixed up. We’ll assume that we’re working on the parent page of Bassisten, Fluitisten, and Trombonisten. Thus, those three pages are in $page->children. We’ll refer to them as $categories. Each category has a number of artists as its children (grandchildren of $page). Each category should have one <ul> element containing the artists. We’ll call an artist page $muzikant and create an <li> element. First of all, let’s get the categories. Create a $categories variable and fill it with the children of $page. $categories = $page->children(); Now loop over these categories and create a <ul> for each one. foreach($categories as $category) { echo "<h3>$category->title</h3>"; echo '<ul>'; echo '</ul>'; } Inside the foreach we now have the variable $category, which refers to a single category. Let’s get its children and call them $muzikanten. Then loop over $muzikanten the same way and echo <li>s. Our complete code now looks like this: $categories = $page->children(); foreach($categories as $category) { echo "<h3>$category->title</h3>"; echo '<ul>'; $muzikanten = $category->children(); foreach($muzikanten as $muzikant) { echo "<li>$muzikant->title</li>"; } echo '</ul>'; } This should just give us all the categories and all the artists in whatever order they come in. To get only one specific category, we need a selector. If you’re unfamiliar with selector strings, take a quick look at the docs. We’re going to use the "sort=" selector to order our $muzikanten, and the "name=" selector to filter the $categories. For example, to get only Bassisten, the selector would be "name=bassisten" (provided that’s the actual name of the page). Let’s put that between the parentheses of $page->children(): $categories = $page->children("name=bassisten"); Now the page shows only Bassisten, but there’s still no order (probably). To sort, we have to know by which field to sort. We’ll use the title field. The selector for that is "sort=title". To sort Z-A instead of A-Z, it would be "sort=-title", with a minus/hyphen symbol. So we have: $categories = $page->children("name=bassisten"); foreach($categories as $category) { echo "<h3>$category->title</h3>"; echo '<ul>'; $muzikanten = $category->children("sort=title"); foreach($muzikanten as $muzikant) { echo "<li>$muzikant->title</li>"; } echo '</ul>'; } The next step would be to use $input->get to determine what goes into our selectors. Let’s assume our address should look like this at the end: ?selectedcategory=bassisten&sortby=-title (You will want to do this differently in reality, but let’s roll with it for now) As soon as you add that part to the address in your browser, $input->get will have two new properties: selectedcategory and sortby. Store them in some variables. $selectedCategory = $input->get->selectedcategory; $sortby = $input->get->sortby; Now we can use these variables inside our selector strings. Our finished code: $selectedCategory = $input->get->selectedcategory; $sortby = $input->get->sortby; $categories = $page->children("name=$selectedCategory"); foreach($categories as $category) { echo "<h3>$category->title</h3>"; echo '<ul>'; $muzikanten = $category->children("sort=$sortby"); foreach($muzikanten as $muzikant) { echo "<li>$muzikant->title</li>"; } echo '</ul>'; }
  7. It’s only visible to accounts that have a license and if I recall correctly, you have to renew your license to get access (i. e. support) annually. Renewal is not required to use the module itself, only for continual support 1 year after the purchase. If you didn’t buy it, you should probably talk to Ryan and the person who did, in order to transfer the license?
  8. I just tested it and I think this is what you want. Here’s a complete demo module: class NotFoundIntercept extends Wire implements Module { public static function getModuleInfo() { return array( 'title' => 'Not Found Intercept ', 'version' => 001, 'summary' => 'Hooks into pageNotFound so you can handle URLs that don’t belong to any page.', 'href' => 'https://processwire.com/talk/topic/8510-module-intercept-ajax-call/', 'autoload' => true, ); } public function init() { wire()->addHook('ProcessPageView::pageNotFound', $this, 'intercept404'); } protected function intercept404($event) { $url = $event->arguments('url'); if ($url != '/my_pseudo_page/') return; //Let pageNotFound() handle it header($_SERVER['SERVER_PROTOCOL'] . ' 200 OK', true, 200); $name = $_GET['name']; if ($name) die("Hola $name! Como estas?"); else die("Sup, guest?"); } } Now you can open ejemplo.es/my_pseudo_page/?name=Manol and – provided that page doesn’t exist in PW – it will greet you. Of course, if the front page has urlSegments enabled, it will just accept that instead, and your module won’t be triggered...
  9. I like GET because it’s associative and order independent and doesn’t care about missing values. They’re different tools for different jobs ¯\(ツ)/¯
  10. (On mobile, haven’t tested) Maybe try hooking into ___PageNotFound() in ProcessPageView. It gives you the requested URL, so you can check if that’s what your module expects and process it. That way your module could remain self-contained. If $input isn’t populated at that point, you should always be able to go through $_POST.
  11. Whoops, sorry, I’m embarrassed. I only skimmed the code samples. @Manol: if I understand correctly, you want to create this “pseudo page” (web-accessible, but not any distinct file or PW page) from within your module?
  12. $variables are only resolved when inside "double quotes". With the 'single quotes', $pages->find() will always look for /tags/$tag/, never /tag/green-energy/, etc.. Might just be a typo in your post, but I thought I’d mention it.
  13. You can create a web-accessible php file anywhere on your server and bootstrap ProcessWire from there, without creating a page as far as PW is concerned. An example: <?php /* This file is nowhere in particular and not a template or anything. */ require_once("./cms/processwire/index.php"); $name = $wire->input->post->name; if ($wire->input->post->name == 'manol') { $m = $wire->modules->get('CoolModule') die($m->welcome($name)); } die('Hello anyway.'); I have no experience with this, so I can’t tell you about potential drawbacks, if there are any. Another way to avoid creating a “page” would be to allow urlSegments for your root page and handle the input there. It would look like any other page but it won’t disturb anyone’s aesthetic sensibilities in the admin backend.
  14. No, although you could use the parent pages you already have: Bassisten, Fluitisten, and Trombonisten. In your example, the groups only go up to C. If you’re only dealing with a few items, it might be fine to do all filtering with Javascript. You could add an id attribute with the group’s name to your <ul> element, and simply hide all the others if the user selects a filter. Sorting could be implemented this way as well. However, that’s not a ProcessWire solution. To do the filtering server-side with PW, you will want to accept GET parameters in your page template. GET parameters are those values that sometimes appear at the end of URLs. On your page, it could look something like this: http://www.deliciousthoothpaste.nl/muzikanten/?filter=bassisten or http://www.deliciousthoothpaste.nl/muzikanten/?sort=descending or even http://www.deliciousthoothpaste.nl/muzikanten/?filter=bassisten&sort=descending Now the page /muzikanten/ has these variables built in and you can use them in your template. They are in the $input->get API variable. $sort = 'title'; if ($input->get->sort === 'descending') $sort = '-title'; //Put a - in front to sort Z-A $muzikanten = $item->children("sort=$sort, sort=id"); //always sort by id to break ties consistently foreach($muzikanten as $muzikant) { ... } Now you just need to get the user to visit your page with the GET parameter in the URL. As soon as he selects a sorting option, you send him to it using Javascript: window.location = '/?sort=' + selection; As you can see, Javascript is sort of required if you want the changes to apply (i. e. to reload the page) immediately. You can however avoid this by setting up a form with a submit button. The downside is, of course, that the user has to press the button in addition to selecting a value from your dropdown. <form method="GET"> <!-- If you leave out the action attribute, it will just reload the page, but with the added parameters --> <select name="sort"> <!-- this is the parameter name that will be in $input->get --> <option value="ascending">A-Z</option> <option value="descending">Z-A</option> </select> <input type="submit" value="Apply Filters" /> <!-- gotta click here to do stuff --> </form> (Not too firm on the HTML syntax here, best read up on it yourself)
  15. Ah, good catch . The API key was a field setting before I put it into the module config. Wonder why I didn’t get that. I assume they’re only shown in debug mode? Thanks for the kind words everyone. I appreciate it :)
  16. Sup. FieldtypeOpenWeatherMap [GitHub] This module fetches and stores current weather data from the OpenWeatherMap.org service and helps you manage icon markup. To limit requests, OpenWeatherMap.org’s JSON-response is cached in the database and only refreshed once the field is accessed and the cache has a certain age that you define. The fieldtype is sadly not multilingual, but you can configure the language of the weather descriptions OpenWeatherMap.org provides you with. It would not be hard to make the output multilingual by referencing weather codes and translating them with ProcessWire’s built in tools. You install FieldtypeOpenWeatherMap just like any other module, by placing the two files into ProcessWire’s modules directory. Once installed, you want to create a new field of the type OpenWeatherMap and assign it to a template. The template now has a text field that stores a city id. In the field settings, you may configure how and when the data is requested. That is, the requested language, units (eg. °C/°F/K) and the cache duration. The module does not provide you with built in icons or otherwise limits you to predefined markup (which I consider a good thing ). The icon in my example above is courtesy of Alessio Atzeni’s Meteocons (custom free license). To make generating icon markup a little easier, you can configure your own markup snippets in the module configuration: As you can see, in this example I’m using an icon font whose appearance is defined elsewhere in my CSS, but you’re free to put in image urls or just unicode entities or whatever. Rendering it is now quite simple. The following markup would result in something like the image above: <?php $w = $city->weather; $temp = round($w->temperature); ?> <p><?php echo "{$w->renderIcon()} {$w->description} at {$temp} °C"; ?></p> <h2><?php echo $city->title; ?> <span class="ico-rightarrow"></span></h2> <!-- irrelevant line --> The variable $w is now a WeatherData object that exposes the following properties: json //The raw JSON response from OWM timestamp //The time of the request city_id //The city id you entered in the admin sunrise //The time of sunrise sunset //The time of sunset main //The main weather name, e. g. “Rain”, in the configured language description //A slightly longer, more precise description like “occasional rain” iconcode //The internal icon code for this weather temperature //The temperature in the format you requested min_temperature //... max_temperature //… wind_speed //I believe the wind speed is also affected by the unit settings. As well as the method renderIcon(), which you already know. If you access a WeatherData object as a string, you will get the city id. This is so that the city id will correctly appear in the admin page edit form. I should mention that there is some more information in the JSON, such as wind direction. The module also exposes the method multiRequest(PageArray $pages, $fieldname). If you want to fetch data for a bunch of pages at the same time, you may want to use that so as to reduce unnecessary requests to the service. I haven’t really used this yet, so consider it experimental, I guess. As of now, this also disregards the cache freshness. If you’re still reading, there’s a chance you might be interested in using this. Allow me to clarify that right now there is no support for forecasts or historical data (yet?). Sorry :> Here’s the GitHub link: FieldtypeOpenWeatherMap.
  17. Check out the Hanna Code module if you don’t want to use a WYSIWYG editor. It’s perfect for this.
  18. They aren’t. Although from the looks of it, it seems to be partly the repeaters’ fault?! Cloning a page also clones the repeater pages as expected, but for some reason they’re parented to page-id 0, so they don’t show up in the admin. Things quickly get sort of messy, but it shouldn’t be too hard to fix, actually.
  19. On the Rabotheater page the DOM doesn’t change at all. The buttons just change the class of the list, thereby changing the CSS. I would recommend this technique unless you want your views to show different data. You can solve the different presentations either for the entire list, or for the individual films. I would probably go with the latter: You have three templates for a film page: film.php – Just your regular page template to display a specific film. This is the only film template that is represented in the Admin. film_list_image.php – Only the markup for a list item showing the film and perhaps some relevant info in the “collage” style. film_list_title.php – List item markup including the film title and perhaps release year, review score, or whatever. On the list page, you render films using the $page->render() method with the chosen template as the first argument: $film->render('film_list_image.php'); You can switch between styles by reloading the entire page with Post, Get or urlSegment input, and perhaps store the preference in $session or $user. You could also load the films with AJAX and call $film->render() with the template there, then return the new markup to the list page. Of course, it might be better to return the film information in JSON format and build the presentation markup of choice with JavaScript on the list page. As you can see, there isn’t one technique that fits all. The CSS option is definitely the fastest, simplest and arguably the best way, provided you can keep the markup the same between both list styles. Just have a look at the Rabotheater site in your Element Inspector. Wicked fast, no DOM changes except one class attribute, no additional server requests. You could even animate the change. I only go into the other stuff because it incorporates ProcessWire and because it answers your question about having two templates for one page.
  20. So I suppose this is a somewhat pointless addition, seeing as drafts are about to come to the core, but I needed this right now and ProcessWire made it possible for me to implement over the last two days. An experience that convinced me once more that ProcessWire is absolutely amazing. GitHub link. So what does this do? This module allows you to create a draft version of (hopefully) any page, which can be edited while the public facing page remains in place and unchanged. Drafts are placed under a special Admin page, which also doubles as a rudimentary manager. It shows what pages have drafts assigned and lets you update the original page with its draft. I need all this mainly for front-end editing, so for me the focus is on the added API methods. I have added functionality to redirect every edit to a draft page for testing, and it can make sense to have that behavior of course, so it will probably become a config setting. How does it do that? Page cloning is very very handy for this purpose, so that’s mostly what I’m doing here. It’s elegant in that very little code is needed, but it is perhaps somewhat crude to delete pages, including their field data and files on the file system, so much. I needed some hacky-feeling tricks to convince PW to delete pages that have children and clone pages to my custom admin page even when their template prohibits that sort of parent. What doesn’t this do (well)? Since a draft is linked to its page by having the page ID for a name (!), which conviniently also guarantees uniqueness, modifying page names should be pretty much impossible. It would be best to create a table to store the references, but I kind of like that you can keep everything 100% PW API. The most complicated fieldtypes I have tested this module with are Images/Files and Multiplier. That covers my immediate need, but perhaps PageTables will cause problems. I don’t have any experience with those. There are probably a lot of other things to look out for, but I can’t remember any more right now. Be aware this is most definitely not production ready or anything. I would like to thank Teppo Koivula, whose Changelog module I used for inspiration downright based this on. Great work there, and a lot to learn from. If you find fragments of Changelog in this module, that’s no coincidence. Also hugely helpful are the great members of this forum and Ryan’s code, which I assume we all use as our main documentation <3 Please absolutely tear this apart, if you can spare the time to have a quick look. I like to think I did okay, but I’m eager to learn and I’m sure this is full of questionable practices, bugs and inefficiencies. So yeah, its unlikely anyone will have the need to use this on a site, but hopefully I can get some feedback out of it and perhaps it can teach other beginners like me a trick or two. GitHub link again. /wall of text
  21. By the way, there is also closest($foo) and parentsUntil($foo).
  22. That shouldn’t happen, actually. Does it do that on your site?! It’s supposed to return the parent closest to Home, as matjazp said. I mean, what would be the point of just returning Home for every single page on the site
  23. Try $page->parent("parent=$foo") edit: parent, not parents.
  24. If I understand correctly, for that trick to work you don’t need to literally host your images in a seperate location. It should suffice to have a subdomain that points to the same paths you’re normally using. Basically, the benefit comes from loading images via a different domain, because it makes the browser allow a parallel connection. Not sure how relevant this is with modern browsers, though.
  25. There is start? $posts = $pages->find('template=news, sort=-created, start=80, limit=40');
×
×
  • Create New...