Leaderboard
Popular Content
Showing content with the highest reputation on 06/26/2017 in all areas
-
Hi everyone, I'm proud to share my first fieldtype module and I think it's a quite handy one It helps you to create all kinds of table/matrix inputs very quickly and easily. You have loads of options for customizing your field via plain javascript. See the handsontable docs for that Please consider this module ALPHA until i got some more time to test it. Any help would be highly appreciated Numbers are for example always tricky. Different locale settings, different types, rounding errors and so on... Download: https://gitlab.com/baumrock/FieldtypeHandsontable Result: Installation/Configuration: Just install the Fieldtype, add a field to your template and set the handsontable options in the fields details. If you have InputfieldAceExtended installed you will also have code highlighting for your code: Get data: If you retrieve the data from the API with outputformatting ON you have some helper methods available: getData() + getRows() get all data of the field getRow($row) get one special row, eg getRow(1) or getRow("2017") getCols() get all data but by columns not by rows getCol($col) get one special column, eg getCol(1) or getCol("mycolumnheader") You can also access rowHeaders and colHeaders directly (see examples) Simple Example: Caution: the examples below are outdated! see this post:6 points
-
Some more nice features copy&paste (eg from excel) that way the field could be used as an import-interface with live preview (much more userfriendly than CSV in my opinion) auto-add-rows (coulb be used as something like a repeater-replacement) hot.updateSettings({ colHeaders: ['Foods'], minCols: 1, maxCols: 1, rowHeaders: false, minRows: 1, minSpareRows: 1, }); auto-add-cols (like tagging) hot.updateSettings({ colHeaders: false, minCols: 1, minSpareCols: 1, rowHeaders: ['Foods'], minRows: 1, maxRows: 1, });5 points
-
You can do it per template, by going to the template edit page and click the title field. Everything you set there is gonna affect that template only.4 points
-
I think there are good examples when page references are overkill, such as simple form options (list of countries, list of contact types in a simple contact form, etc...) As a rule of thumb I use this reasoning: am I absolutely sure I do NOT WANT more than simple options? If in doubt, I use page references just to make things extendable in the future.3 points
-
Hi rushy and welcome. It sounds like your .htaccess file isn't working. Check that it has been renamed from /processwire-master/htaccess.txt to /processwire-master/.htaccess and if it hasn't been, try renaming it manually. If it has been renamed already, or after you rename it you still can't access /processwire-master/about/, open .htaccess in your preferred text editor and type some random characters at the top of the file and save it. That should get you a 500 error, which is ok, because it means that Apache is processing .htaccess. If you do get a 500 error, revert the changes and save it again. Then come back to the forum and we will try some more steps. <edit>Should have mentioned https://processwire.com/docs/install/troubleshooting/!</edit>3 points
-
Thank you DaveP I searched the forum a bit more and found some similar problems people had encountered and I managed to get it working now! I'm not sure if it was related to the .htaccess you mention, but I changed an entry in my /etc/apache2/apache2.conf file - the AllowOverride was "None" and changing it to "All" and restarting apache has done the trick. I think it allows rewrites to my /var/www folder? Anyway many thanks for your help - let's see if i can make some progress now...! <Directory /var/www/> Options Indexes FollowSymLinks AllowOverride All Require all granted </Directory>2 points
-
hi @Juergen of course i can, there are a lot In general this field is useful whenever you need array- or matrix-like inputs. I use the field for my custom CRM to input the controlling values for my clients revenues. | jan | feb | mar ... ------------------------------------- goal 1 | 10.000 | 15.000 | 20.000 goal 2 | ... goal 3 It replaces lots of repeaters and not so userfriendly inputs. I didn't mention that you also have lots of possibilities of live-validating your data (you could for example make all cells with not properly formatted dates have a red background). You see the inputfields at the bottom of the screenshot? It was too complicated to build a table-like input for that values (month values). Pagetable is too bloated for that. Maybe the matrix inputfield would have been an option, but still i think the handsontable has a huge potential. So i ended up having a simple textfield input and telling my client to devide all values by commas... not the best way!! So whenever you have thought of a field telling your clients "one on each line" or "devided by comma..." this field could help you out.2 points
-
@JimSee, that error can sometimes be caused by a weird invisible whitespace character in your code, particularly if you copy/pasted it from somewhere. Try deleting this part... $content .= $page->comments->render(array( 'headline' => '<h2>Read Comments</h2>', )); ...and then typing it out again from scratch.2 points
-
Is this a known bug that has been reported at GitHub? I couldn't find any report for it so have opened a new issue here. @JimSee, until this is fixed in the core you can work around the date format issue by supplying a date format as part of the $options array when you render the comments list, e.g. echo $page->comments->render(array( 'headline' => '<h2>Read Comments</h2>', 'dateFormat' => 'm/d/y g:ia', )); The website is rendered as a link using the commenter's name as the link text:2 points
-
"AllowOverride directive is used to allow the use of .htaccess within the web server to allow overriding of the Apache config on a per directory basis." Just search the web: https://www.google.hu/search?q=what+is+AllowOverride+All Happy ProcessWire tinkering!1 point
-
What did you try on the if? It could be something like: <?php if (date('d-m-Y') == date('d-m-Y', $single->Start_date) : ?> <div class='Danes-text'>TODAY!</div> <?php endif; ?>1 point
-
Hi, There is a list of reserved words which cannot be used for a Field, see: https://github.com/processwire/processwire/blob/master/wire/core/Fields.php#L36 I do not remember exactly when, but limit was added to this list, hence you cannot upgrade without first renaming the Field in question in the admin. You will probably need to change some code too, in order to accommodate to this change.1 point
-
1 point
-
You just need to add the Russian language pack to the admin and set the Russian language on each admin user profile. A language pack is a zip containing many files that will translate the admin pages, fields etc. Download the package: http://modules.processwire.com/modules/russian/ After that, go to /admin/setup/languages/, edit Russian and upload the file on the "Core Translation Files" section.1 point
-
1 point
-
Thank you fbg13, Robin S and Mike Rockett ! For now, the Comments work good enough with page->comments->renderAll(); Still, I do look forward to the date being fixed. My last efforts were: Upgraded my Wamp so that i'm using PHP 7. Downloaded, unzipped and installed ProcessWire 3.0.62 Added Comments but first saved the array stuff in Notepad to be sure that any strange spaces were avoided. When it failed, used page->comments->renderAll(); to be sure that I didn't have some other kind of problem. Thank you again!1 point
-
Didn't read the whole thread but just wanted to let you know that you don't need the hook here. The body has a class with the template name, so a single css selector would be enough Don't know when this feature was implemented though. EDIT: this is a feature of AOS, not core... body.ProcessPageEdit-template-YOURTEMPLATE ...1 point
-
Will this do the trick? https://processwire-recipes.com/recipes/activate-all-languages/1 point
-
Side notes: If you're on PHP 5.5, you should be using square array notation. So instead of array(...), use [...]. I also recommend that you upgrade to a newer version of PHP. The oldest version with any kind of support at all is 5.6, and so check if you can upgrade to that or 7.0 or 7.1. For local development, might be better to use EasyPHP as you can switch between versions easily.1 point
-
I still prefer the Page Reference because the flexibility to get more values from the page itself1 point
-
The option was hard coded to 'relative' instead of using the user set option. I submitted a pull request. Did you do anything else beside adding the comment field? It works for me on pw version 3.0.42 and php 5.5 on the intermediate profile. Make sure you don't have any typos in your code. Also when sharing code use the code button <> and add the code that way.1 point
-
@JimSee The date part is a bug with PW. No idea about the error, works for me (copied your code and just replaced the comments field name). What pw, php versions are you using? Is your server able to send emails? Ask your host if you don't know.1 point
-
You disabled everything for the fileCompiler, but wireCache and the fileCompiler are two totally different things. The first one is a multiple purpose cache for data you handle in your code. The fileCompiler is there to dynamically add the ProcessWire namespace needed in php files since pw 3.0, a.k.a. it's literally changing your php files and is not a cache for data at all. You could do this: // in config.php $config->cacheTimeMultiplier = 1 if($config->debug) $config->cacheTimeMultiplier = 0 // elsewhere echo $cache->get("hello-world", 3600 * $config->cacheTimeMultiplier, function() { echo "<p>Hello World</p>"; });1 point
-
On the edit page of the title field, go to input tab, open the pattern field, there you can add a regular expression pattern ( [-+]?[0-9]*[.,]?[0-9]+ (for numbers with or without decimals)). Or you can add a hook and check the title before saving. https://processwire.com/api/hooks/1 point
-
I have been working on regular repeater support, but it's not quite there. The current problem is that the event object is taking its data from the parent page, in the case of a repeater, it's the repeater page (not what we want). So I have to do a bit more work detecting if it's in a repeater and use getForPage() to populate the event object. A couple other little details. Getting close, but still not there. It's coming though!1 point
-
Many new things are hidden in blogposts...like $urls for example is not in the API Reference....or just i did not find it. no problem for me since i like finding treasures and loot on the way - but just wanna mention it. Is there a chance to get involved or people could help extracting important bits from blogposts to the docs?1 point
-
If you want even shorter version of your code, you can remove completely the repeating lines and just leave the differences as @szabesz suggested earlier: <?php foreach($page->Slides as $Slides) { $image = $Slides->images->first(); if ($Slides->Link) { $link = $slides->Link; } else { $link = ""; }; echo "<li data-transition='$page->Slide_Effect' data-slotamount='7' data-link='$link' data-target='_blank' >"; echo "<img src='$image->url' alt='$image->description'>"; echo "<div class='tp-caption' data-x='100' data-y='115' data-speed='700' data-start='1000' data-easing='easeOutBack'><h2>$Slides->title</h2></div>"; echo "</li>"; } ?> Hope that helps1 point
-
<?php foreach($page->Slides as $Slides) $image = $Slides->images->first(); if ($Slides->Link) { ?> <li data-transition="<?php echo $page->Slide_Effect; ?>" data-slotamount="7" data-link="<?=$Slides->Link ?>" data-target="_blank" > <img src="<?php echo $image->url; ?>" alt="<?php echo $image->description; ?>"> <div class="tp-caption" data-x="100" data-y="115" data-speed="700" data-start="1000" data-easing="easeOutBack"><h2><?=$Slides->title ?></h2></div> </li> <?php } else { ?> <li data-transition="<?php echo $page->Slide_Effect; ?>" data-slotamount="7" data-target="_blank" > <img src="<?php echo $image->url; ?>" alt="<?php echo $image->description; ?>"> <div class="tp-caption" data-x="100" data-y="115" data-speed="700" data-start="1000" data-easing="easeOutBack"><h2><?=$Slides->title ?></h2></div> </li> <? }; }?> Something like this might make it shorter. Please excuse me if I forgot to close a { or else as the browser is not my best editor. Basically I removed $image defininition in your second case as it is already defined before the if and is not changing.1 point
-
I actually think for this module the client expressed interest in us releasing it available for others to use once it's finished. I will confirm though. I used the process outlined on this page (link) to do a lot of it, though admittedly there was also a lot of stuff to figure out with some trial and error.1 point
-
Maybe here's a bit more information about it: https://processwire.com/docs/security/file-permissions/#securing-your-site-config.php-file Also the installer option for file/folder permissions wasn't present in earlier versions of processwire if I recall correctly(https://github.com/ryancramerdesign/ProcessWire/commit/f7c308566bebf0d39e8ec688d1e7795bf0c17f50) and it seems like it was only added to supply the values into the config.php and not to do any permission changes on installation. I think that's the confusion here: That modules/assets/templates weren't updated with the chmod setting supplied in the installer. Making the config.php readonly by default is not something i would advice, because it can firstly brick your installation and secondly it will prevent any runtime changes to this file and there are modules out there which do write to that file. So it would probably be nice to have the option, that the installer does also clean up any incorrect file/folder permission when installing – possibly even by default, because it'll show incorrect settings much earlier and not if the first file uploads do fail or something like that. Making the config.php readonly should still be considered a manual or at least a opt-in task.1 point
-
Note: this functionality is now built into AdminOnSteroids. I'd hate to know how much accumulated time I have spent and how much eye-strain I have experienced over the last couple of years, hunting through the 675 icons in the "all icons" view for the one I want. Today I finally got around to doing something about it. IconsFilter Allows the "all icons" view in InputfieldIcon to be filtered by name. Usage Install the IconsFilter module. When viewing "all icons" in InputfieldIcon (Advanced tab of field/template settings) you can filter the icons by name using the filter input at top right. https://github.com/Toutouwai/IconsFilter @tpr, something that could be merged into AdminOnSteroids?1 point
-
I've added Robin's code to AOS (unreleased yet) with some tweaks (use placeholder search character instead ::before pseudo, on enter select first match and do not submit the form, focus on expanding the icons and position the filter next to the Show all button instead floating. I've also posted a PR to the core InputfieldIcon.1 point
-
I think it would be great to start the marketplace precisely by doing it with Processwire as a module, then that module is also on offer as a platform demonstration. Maybe?1 point
-
A proof-of-concept module. ImageToMarkdown Alt+click an image in Page Edit to copy an image markdown string to clipboard. Usage Install the ImageToMarkdown module. Alt+click an image in Page Edit to copy an image markdown string to clipboard. If the "Description" field is populated it is used as the alt text. https://github.com/Toutouwai/ImageToMarkdown1 point
-
http://fontawesome.io/icons/ have this using the Argolia search engine.. maybe we can have something similar using this https://jets.js.org/ .. is very easy to use with html/data tags and really fast1 point
-
After this tutorial you'll have learned how to: Build a Process module Make an AJAX request to backend Serve JSON as response Let's say you want to display the latest orders in a dashboard that you can access from admin panel. And you want it to refresh its content with a button click. Most straightforward and proper way (that I know of) is to create a Process module, as they're built for this purpose. First, create a directory under /site/modules/, call it ProcessDashboard, and create a file named ProcessDashboard.module under that directory. Following is about the least amount of code you need to create a Process module. <?php namespace ProcessWire; class ProcessDashboard extends Process { public static function getModuleInfo() { return [ 'title' => 'Orders Dashboard', 'summary' => 'Shows latest orders', 'version' => '0.0.1', 'author' => 'abdus', 'autoload' => true, // to automatically create process page 'page' => [ 'name' => 'order-dashboard', 'title' => 'Orders', 'template' => 'admin' ] ]; } public function ___execute() { return 'hello'; } } Once you refresh module cache from Modules > Refresh, you'll see your module. Install it. It will create an admin page under admin (/processwire/) and will show up as a new item in top menu, and when you click on it, it will show the markup we've built in execute() function. All right, now let's make it do something useful. Let's add create a data list to display latest orders. We'll change execute() function to render a data table. public function ___execute() { /* @var $table MarkupAdminDataTable */ $table = $this->modules->MarkupAdminDataTable; $table->setID($this->className . 'Table'); // "#ProcessDashboardTable" $table->headerRow([ 'Product', 'Date', 'Total' ]); // fill the table foreach ($this->getLatest(10) as $order) { $table->row([ $order['title'], $order['date'], $order['total'] ]); } // to refresh items $refreshButton = $this->modules->InputfieldSubmit; $refreshButton->name = 'refresh'; $refreshButton->id = $this->className . 'Refresh'; // "#ProcessDashboardRefresh" $refreshButton->value = 'Refresh'; // label of the button return $table->render() . $refreshButton->render(); } where getLatest() function finds and returns the latest orders (with only title, date and total fields) protected function getLatest($limit = 5, $start = 0) { // find last $limit orders, starting from $start $orders = $this->pages->find("template=order, sort=-created, limit=$limit, start=$start"); // Only return what's necessary return $orders->explode(function ($order) { return [ 'title' => $order->title, 'date' => date('Y-m-d h:i:s', $order->created), 'total' => $order->total ]; }); } When you refresh the page, you should see a table like this Now we'll make that Refresh button work. When the button is clicked, it will make an AJAX request to ./latest endpoint, which will return a JSON of latest orders. We need some JS to make AJAX request and render new values. Create a JS file ./assets/dashboard.js inside the module directory. window.addEventListener('DOMContentLoaded', function () { let refresh = document.querySelector('#ProcessDashboardRefresh'); let table = document.querySelector('#ProcessDashboardTable'); refresh.addEventListener('click', function (e) { // https://developer.mozilla.org/en/docs/Web/API/Event/preventDefault e.preventDefault(); // Send a GET request to ./latest // http://api.jquery.com/jquery.getjson/ $.getJSON('./latest', { limit: 10 }, function (data) { // check if data is how we want it // if (data.length) {} etc // it's good to go, update the table updateTable(data); }); }); function renderRow(row) { return `<tr> <td>${row.title}</td> <td>${row.date}</td> <td>${row.total}</td> </tr>`; } function updateTable(rows) { table.tBodies[0].innerHTML = rows.map(renderRow).join(''); } }); And we'll add this to list of JS that runs on backend inside init() function public function init() { $scriptUrl = $this->urls->$this . 'assets/dashboard.js'; $this->config->scripts->add($scriptUrl); } Requests to ./latest will be handled by ___executeLatest() function inside the module, just creating the function is enough, PW will do the routing. Here you should notice how we're getting query parameters that are sent with the request. // handles ./latest endpoint public function ___executeLatest() { // get limit from request, if not provided, default to 10 $limit = $this->sanitizer->int($this->input->get->limit) ?? 10; return json_encode($this->getRandom($limit)); } Here getRandom() returns random orders to make it look like there's new orders coming in. protected function getRandom($limit = 5) { $orders = $this->pages->find("template=order, sort=random, limit=$limit"); return $orders->explode(function ($order) { return [ 'title' => $order->title, 'date' => date('Y-m-d h:i:s', $order->created), 'total' => $order->total ]; }); } And we're done. When refresh button is clicked, the table is refreshed with new data. Here it is in action: 2017-04-29_19-01-40.mp4 (227KB MP4, 0m4sec) Here's the source code: https://gist.github.com/abdusco/2bb649cd2fc181734a132b0e660f64a2 [Enhancement] Converting page titles to edit links If we checkout the source of MarkupAdminDataTable module, we can see we actually have several options on how columns are built. /** * Add a row to the table * * @param array $a Array of columns that will each be a `<td>`, where each element may be one of the following: * - `string`: converts to `<td>string</td>` * - `array('label' => 'url')`: converts to `<td><a href='url'>label</a></td>` * - `array('label', 'class')`: converts to `<td class='class'>label</td>` * @param array $options Optionally specify any one of the following: * - separator (bool): specify true to show a stronger visual separator above the column * - class (string): specify one or more class names to apply to the `<tr>` * - attrs (array): array of attr => value for attributes to add to the `<tr>` * @return $this * */ public function row(array $a, array $options = array()) {} This means, we can convert a column to link or add CSS classes to it. // (ProcessDashboard.module, inside ___execute() method) // fill the table foreach ($this->getLatest(10) as $order) { $table->row([ $order['title'] => $order['editUrl'], // associative -> becomes link $order['date'], // simple -> becomes text [$order['total'], 'some-class'] // array -> class is added ]); } Now, we need to get page edit urls. By changing getLatest() and getRandom() methods to return edit links in addition to previous fields protected function getLatest($limit = 5, $start = 0) { // find last $limit orders, starting from $offset $orders = $this->pages->find("template=order, sort=-created, limit=$limit, start=$start"); return $orders->explode(function ($order) { return [ 'title' => $order->title, 'date' => date('Y-m-d h:i:s', $order->created), 'total' => $order->total, 'editUrl' => $order->editUrl ]; }); } protected function getRandom($limit = 5) { $orders = $this->pages->find("template=order, sort=random, limit=$limit"); return $orders->explode(function ($order) { return [ 'title' => $order->title, 'date' => date('Y-m-d h:i:s', $order->created), 'total' => $order->total, 'editUrl' => $order->editUrl ]; }); } and tweaking JS file to render first column as links function renderRow(row) { return `<tr> <td><a href="${row.editUrl}">${row.title}</a></td> <td>${row.date}</td> <td>${row.total}</td> </tr>`; } we get a much more practical dashboard.1 point
-
$designers_person = $pages->find("parent=/designers/, designers_lastname!=''")->each(function($designer){ $designer->custom_sort = $designer->designers_lastname; }); $designers_group = $pages->find("parent=/designers/, designers_lastname=''")->each(function($collective){ $collective->custom_sort = $collective->title; });; $all = $designers_person->add($designers_group)->sort('custom_sort');1 point
-
Thanks for the ideas. @mr-fan: I think this might be the sort of thing you're hinting at - at the top of the widget templates... <?php if( empty($options['pageStack']) ) throw new Wire404Exception(); ?> Good info in this post from Jonathan Lahijani here and some info on pageStack from Ryan here. I like this solution. @LostKobrakai: Sounds like this would work, but it seems to me there are downsides to using wireRenderFile() over $page->render(). I have a lot of different widget templates and widgets are selected by editors via a page field, so using $page->render() keeps the rendering code really simple and maintenance-free. foreach($page->widgets as $widget) { echo $widget->render(); } But if I use wireRenderFile() I need a whole chain of logic to check the template of each widget and render it with the correct file for that type of widget. Besides avoiding partial pages being directly viewable, are there other benefits of wireRenderFile() that make it preferable to $page->render()?1 point