Leaderboard
Popular Content
Showing content with the highest reputation on 09/10/2014 in all areas
-
Since some others and me have been run into problems with FieldtypeFloat. I want to start a discussion with the purpose to get a consistent FieldtypeFloat and/or to create a new Fieldtype maybe called FieldtypeDecimal to store exact values maybe for currencies. First I will assume some known problems. precision Values of Type Float are stored in most of the Mysql Installations with a precision of 6 by default. PW FieldtypeFloat uses Type float() in the Mysql Database This could cause some problems. For easy understanding look at this table. +---------------+----------------+--------------------------------------------------+ | input | float() | decimal(10,2) | +---------------+----------------+--------------------------------------------------+ | 1234.56 | 1234.56 | 1234.56 | +---------------+----------------+--------------------------------------------------+ | 123456.78 | 123457 | 123456.78 | +---------------+----------------+--------------------------------------------------+ | 12345678 | 12345600 | 12345678.00 | +---------------+----------------+--------------------------------------------------+ | 1.23456789 | 1.23457 | 1.23 | +---------------+----------------+--------------------------------------------------+ | 12345678912345| 12345600000000 | ERROR SQLSTATE[22003]: Numeric value out of range| +---------------+----------------+--------------------------------------------------+ As an example in Apeisas Shoppingcart Module exists a field sc_price of type float(). This field allows a maximum value of 9999.99 Euro Dollar or whatever. Don't use it to sell cars like Ferrari. Try to store the input values of the preceding table in a PW Field of Type Float in your surrounding and look what you get after saving. Threads treating the same problem https://processwire.com/talk/topic/3888-float-field-rounding-problem/ https://processwire.com/talk/topic/86-float-field-rounding rounding Mysql will round anyway the float value to precision. So it is not necessary to round the value in php before storing. To store exact Values it is better to use Type decimal(M,D) where M is the lenght and D the number of digits. Thread treating the same problem https://processwire.com/talk/topic/86-float-field-rounding format We had already some discussion about local settings, storing and output of PHP-Values of Type (float). And Ryan did some Adjustments with number_format. But I don't trust completely, thats why I am using Textfields to store numbers. Would be nice to have a consistent Fieldtype working in different local-settings. Thread treating the same problem https://processwire.com/talk/topic/4123-decimal-point-changed-to-in-base-of-setlocale/ https://processwire.com/talk/topic/86-float-field-rounding What is a float (floating point value), what is decimal? A float is an approximate value and exactly like this it is stored in Mysql. For more understanding two examples. 1. example CREATE TABLE `test` ( `test_float` float(10,2) NOT NULL, `test_decimal` decimal(10,2) NOT NULL ); INSERT INTO `test` (`test_float`, `test_decimal`) VALUES (5.43, 5.43); SELECT (test_float * 1.0000000) AS f, (test_decimal * 1.0000000) AS d FROM test; This will result the following: f = 5.4299998 and d = 5.430000000 source: http://netzgewe.be/2012/03/mysql-und-waehrungsbetraege-float-vs-decimal/ (german) 2. example mysql> create table numbers (a decimal(10,2), b float); mysql> insert into numbers values (100, 100); mysql> select @a := (a/3), @b := (b/3), @a * 3, @b * 3 from numbers \G *************************** 1. row *************************** @a := (a/3): 33.333333333 @b := (b/3): 33.333333333333 @a + @a + @a: 99.999999999000000000000000000000 @b + @b + @b: 100 source: http://stackoverflow.com/questions/5150274/difference-between-float-and-decimal-data-type INFO & LEARNING http://stackoverflow.com/questions/5150274/difference-between-float-and-decimal-data-type http://stackoverflow.com/questions/4520620/float-precision-problem-in-mysql http://dev.mysql.com/doc/refman/5.0/en/problems-with-float.html http://dev.mysql.com/doc/refman/5.0/en/storage-requirements.html INTENTION The intention of this thread is to discuss good solutions for a consistent working FieldtypeFloat which makes clear to Everybody what it is via description. Furthermore to build a new Fieldtype with setting options of total lenght and decimal places. NOTES Please use this thread rather for development than as a help forum. BTW I am not an expert in Mysql PHP or whatever. Maybe there are some guys in the forum which could put the real good stuff here. Thanks a lot and lets go.7 points
-
I am glad you started a thread on this topic. I agree it would be great to see a FieldtypeDecimal module shipping with the core. This is something that's actually on a TODO-list for a big project of ours. It should definitely be a separate module (in other words, leave FieldtypeFloat alone) because floats have a different purpose. The background of the problem is in how computers handle (or should you say, how they support handling) floating point values. It actually doesn't have anything to do with PHP or MySQL, even less with PW - although you can obviously feel the effect of it. Binary floating point values supported by the CPU/ALU/FPU, such as the commonly used IEEE 754 (C, Java, PHP and so on), are always approximations. They are used where speed matters the most and the tiny loss of precision is acceptable. When precision is needed, you actually need something that implements arbitrary-precision arithmetic (bignum). The resulting loss of speed is irrelevant in many cases, such as handling currency. The reason why I'm bringing this up is that even with a FieldtypeDecimal implementation, you would still need to make sure you are handling the values correctly in PHP. If you perform any arithmetic on the value using PHP's arithmetic operators, you are actually causing PHP to cast the value to a floating point representation. That would defeat our purpose here (because you could loose precision). Thus if you need to perform arithmetic on the value, you must use an arbitrary-precision arithmetic library. For PHP you have at least two good options BCMath - http://php.net/manual/en/book.bc.php (simple set of functions, built-in) GMP - http://php.net/manual/en/book.gmp.php (a much larger set of functions, requires an external library) Of course none of this matters unless you can first store the original value in the database without precision loss. This requires a DECIMAL field in MySQL - which indeed was the original topic of the thread Here's a few links for general information. I recommend you to read at least the first one - it's a simple introduction. http://floating-point-gui.de/ http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems http://en.wikipedia.org/wiki/Arbitrary-precision_arithmetic http://en.wikipedia.org/wiki/Double-precision_floating-point_format http://en.wikipedia.org/wiki/Fixed-point_arithmetic5 points
-
@cstevensjr Thanks for this article. That was an interesting read! @adrian I have heard people say that base64 encoded fonts would load pretty fast, so I am really interested to hear about your personal experience when this tasks pops off of your list. @Fokke You saved me from my misery! After removing the alternative font (and changing $config->paths->templates to $config->urls->templates) the fonts finally loaded. For every font I also had to specify the font-style as either 'normal' or 'italic'. Otherwise all fonts would be displayed in italics. Just removing the font-style property from @font-face did not work. This is the final implementation: <?php // Import font based on the user language. $currentLanguage = $user->language->name; $fontPath = $config->urls->templates . "styles/my-fonts/open-sans/"; $css = ""; $fonts = array( 'Open Sans' => array( 'OpenSans-Light' => ['normal', 300], 'OpenSans-LightItalic' => ['italic', 300], 'OpenSans-Regular' => ['normal', 400], 'OpenSans-Italic' => ['italic', 400], 'OpenSans-Semibold' => ['normal', 600], 'OpenSans-SemiboldItalic' => ['italic', 600], 'OpenSans-Bold' => ['normal', 700], 'OpenSans-BoldItalic' => ['italic', 700] ), 'Open Sans Condensed' => array( 'OpenSans-CondLight' => ['normal', 300] ) ); switch ($currentLanguage) { case "default": // English case "ru": // Russian case "es": // Spanish foreach ($fonts as $font => $variations) { foreach ($variations as $variation => $properties) { // Target path: // site/templates/styles/my-fonts/open-sans/<user language>/<font name>-webfont.woff $url = $fontPath . $currentLanguage . "/" . $variation . "-webfont.woff"; $style = $properties[0]; $weight = $properties[1]; $css .= <<<CSS @font-face { font-family: '$font'; src: url('$url') format('woff'); font-weight: $weight; font-style: $style; } \n CSS; } }; break; default: echo "<h2>No CSS Font found!</h2>"; } echo $css; Sample output: @font-face { font-family: 'Open Sans'; src: url('/processwire/site/templates/styles/my-fonts/open-sans/default/OpenSans-Light-webfont.woff') format('woff'); font-weight: 300; font-style: normal; } @font-face { font-family: 'Open Sans'; src: url('/processwire/site/templates/styles/my-fonts/open-sans/default/OpenSans-LightItalic-webfont.woff') format('woff'); font-weight: 300; font-style: italic; } @font-face [...] I wanted to thank you all again for your help! As I am not a web developer by trade, I often get stuck at things that "just should work". Luckily, there is always some great people on the Processwire forum who point me in the right direction. Cheers, Stefan5 points
-
Announcing QBox.co; a simple native PW shop that I'll be using to sell my commercial PW modules. This site has been put together with the aim of giving me an independent platform to sell some of my more specialised packages. The selection is limited at the moment but more will be added soon. Actually, a lot of the packages that I'll be offering on QBox are not limited to ProcessWire applications - they will often provide functionality that you can use in other PHP projects. Before you ask, the shop is running an, as-yet unreleased, version of Antti's shop module suite for PW with some changes to provide additional functionality. Payment is handled by integration with Stripe.com and you'll need Javascript enabled to make it happen. I've already opened a dialog with Ryan about getting the modules represented on QBox.co in to the official PW shop site and we'll see how that progresses. In the meantime, please feel free to let me know if you stumble over any problems; have useful comments or criticisms; want to know anything more about any of the modules offered there or just like what you see.4 points
-
3 points
-
Super quick (and completely untested) idea. Maybe you could just add a markup field that shows the related pages? This would happen after the form is built, so no need to have additional fields assigned to the template. Again, haven't tested this, and wrote it mostly in the browser. <?php class relatedPages extends WireData implements Module { public static function getModuleInfo() { return array( 'title' => 'Related Pages', 'version' => 1, 'summary' => 'untested module to show related pages', 'href' => '', 'singular' => true, 'autoload' => true, ); } public function init() { $this->addHookAfter("ProcessPageEdit::buildForm", $this, "showRelatedPages"); } public function showRelatedPages($event){ // page being edited (viewed) $page = $event->object->getPage(); // check if it's a template we want to do anything with. if($page->template == "client" || $page->template == "properties"){ // form $form = $event->return; // build selector to find related pages. // you may want to find the related pages another way, this is just a quick and dirty example. if ($page->template == "client") $selector = "your selector here"; if ($page->template == "properties") $selector = "some other selector"; // find pages based on the selector above $related_pages = wire("pages")->find($selector); // our find returned some related pages if ($related_pages->count() > 0){ // get the markup module $field = $this->modules->InputfieldMarkup; $field->label = "Related Pages"; // label $field->markupText = $related_pages->implode(", ", "title"); // where do you want to insert this in the admin (after what field?) $form->insertAfter($field, $form->get("field_name_to_insert_after")); } } } }3 points
-
import the two backups to two different tables on your own computer, export them with the same program and check if the results are the same.3 points
-
If you want your editors to be able to insert the button in a textarea field, your simplest option might be a Hanna code so your editors could do something like: [[button label="Click Here" link="http://www.mysite.com/mypage"]] Otherwise you could have a button created to an internal page by providing them with a Pagefield called "linked_page" and set the input field type to PageListSelect+ Then in your template file use the following code: echo "<a href='{$page->linked_page->url}' class='button'>Default Button</a>";3 points
-
Just wanted to let everyone know that I finally got around to implementing netcarver's suggestions! You can now choose to override the parent and child template names from two collapsed fields. If left blank, behavior is as previously - they will be named based on the field name and the suffix supplied in the module config settings. You can now optionally define the field type when using Option 2, eg: Title, Number of Beds>Integer, Number of People>Integer, Kitchen Facilities>Text Single, 1, 1, Fridge Only Double, 2, 2, Fridge Only Suite, 3, 6, Full Kitchen Please let me know how this new functionality works out for you - I am hoping that now there will be no reasons to ever create a Page field setup manually, but let me know if I have missed something that anyone still needs.3 points
-
PageTableExtended Download here: http://modules.processwire.com/modules/fieldtype-page-table-extended/ Extends the Processwire PageTable field for rendering table row layouts. This is great for editors, because they actually see at a glance what the table rows consist of. What it does Turns the Processwire Fieldtype "Page Table" from this: into something like this (sorting capabilities of course still functional): See it in action: Requirements FieldtypePageTable installed (part of the core since Processwire 2.4.10.) Templates used for PageTable need a file associated (otherwise nothing gets rendered) This render method is meant for sites where the PageTable templates only render part of the layout, not complete websites. But you also can define what will be rendered (see below). Options Render Layout instead of table rows Check this for seeing the rows rendered. You can easily turn off the complete functionality by unchecking this. Path to Stylesheet Since the parts are unstyled by default, it is a good idea to define styles for them. All rendered templates are encapsulated in a div with the class "renderedLayout" so you can style them with: div.renderedLayout h2{ color: green; } The path is to be set relative to your templates' folder. Reset Admin CSS Since the parts are rendered inside the Admin, common styles of the Admin Interface apply also to your layout parts. This is not a bad thing, because especially text styles are well integrated in your admin's theme. But if you like to override the admin styles in your table rows completely (more or less), just check this box. Don't forget to define a custom CSS then! Advanced Since this module is meant for parts of your layout you already have defined for your frontend templates, it is a good idea to use a preprocessor like Stylus, Sass or Less for building the custom CSS file. Just outsource your layout part definitions in an extra file, compile that in a separete CSS file and use this as custom CSS for this module. Since your CSS is should be built in a modular way, this works pretty well ;-) Will write a tutorial with a use case once finished testing. Notes: Github: https://github.com/MadeMyDay/PageTableExtended If you want to get rid of the unnecessary step for entering a title before editing the page, just set the "autoformat" value as suggested in the PageTable settings. If you don't want to use a title field at all, see this post from Soma Will put it in the module repository once finished testing. Please test it and give feedback. I haven't used GitHub for a long time, please check if everything is in place and if this will work with the modules manager and the new core module installer once added to the repository. Have fun Module is in the repository now: http://modules.processwire.com/modules/fieldtype-page-table-extended/ Please use GitHub for instructions, I made some additions there.2 points
-
Websites often provide content not only as on list of stuff, but with some sort of category. The most flexible way in ProcessWire to manage such a categorization are with PageFields. Form example with a structure like this. - Magazine (magazine) - Articles - Article 1 (article) - Article 2 - Article 3 - … - Categories - Category 1 (category) - Category 2 - … Templatenames in parentheses Now all articles have a url structure like: "…/magazine/articles/articlename/" The categories are looking like: "…/magazine/categories/categoryname/" But it can be useful to also provide the articles as part of the categories like this: "…/magazine/categories/categoryname/articlename/" Because ProcessWire doesn't provide such functionality by default, we'll use urlSegments. These have to be enabled in the template-settings for the category template. This template therefore fulfills two different jobs. Displaying a list of containing articles, as well as rendering the articles which are linked by the list. A simple example of a existing category.php could be: <?php // category.php $articles = $pages->find("template=article, category=$page"); // This example uses a deligated template approach. // Feel free to use your own way of templating, // but this is also a simple way to explain this. $content = renderArticleList($articles); include("./_main.php"); Now we need to include the logic to seperate the default rendered article-list to the now added rendering of the called article. <?php // category.php // Throw a 404 Error if more than one segment is provided if($input->urlSegment2) throw new Wire404Exception(); if($input->urlSegment1){ // Show the called article // Sanitize the input for pageNames $name = $sanitizer->pageName($input->urlSegment1); // Search for the article with this name $article = $pages->get("template=article, name=$name"); // Throw an 404 error if no article is found if(!$article->id) throw new Wire404Exception(); // Explicitly set the original url of the article for the <link type="canonical" href=""> tag $article->canonical = $article->url; // Render the page, like if it was normally called. // $page->url will not updated to the "categorized" url for the rendering-part // so you need to have that in mind if you provide some sort of breadcrumb echo $article->render(); }else{ // Show the list of articles of the current category $articles = $pages->find("template=article, category=$page"); // The generateCategoryUrls() function is new, because // $page->url would provide the wrong urls. // Details are provided later $content = renderArticleList( generateCategoryUrls($articles, $page) ); include("./_main.php"); } Now if we call this "…/magazine/categories/categoryname/articlename/" we'll get the right article rendered out instead of the article-list. Now we need to talk about the article-list, which would - without changes - still render the "wrong" urls to all those articles. Therefore I added the generateCategoryUrls() function. This function iterates over the pageArray and adds a second url to all those articles. <?php // part of _func.php function generateCategoryUrls($list, $category){ foreach($list as $item){ $item->categoryUrl = $category->url.$item->name."/"; } return $list; } The last thing missing is the actual template which gets rendered by renderArticleList(). This would normally call for $article->url to get the url to the article. We want this to render our second url if we are on a category site. To let the template still be useable by non category sites, we just change the parts, where to url is used form the current $article->url to $article->get("categoryUrl|url"). Only if the additional urls are provided they get rendered or it falls back to the normal urls of the articles. There we go, with such a setup all categorized articles are reachable via both urls. A small addition to explain the $article->canonical I used in the category.php. For SEO it's not good to provide the same content on multiple pages without explicitly declaring which of the duplicated ones should be the original / indexed one. By providing the following link tag we provide this declaration. The extra field I use isn't really necessary, because $page->url still is the standart ProcessWire url of the shown article. But I like this to be visibile in the code, that this is a dublicate. <link rel="canonical" href="<?php echo $page->get("canonical|url") ?>"/> Hope you like the explanation. Feel free to give feedback on this. Based on the example shown in the wiki: http://wiki.processwire.com/index.php/URL_Segments_in_category_tree_example2 points
-
Several templates can have the same fieldgroup. Say you build a site for a greengrocer, and you want to sell fruit. You want to have different templates for apples pears and oranges, but don't need different fields, then you could share 1 fieldgroup with the apples pears and oranges templates. This way you could search $pages->find('template=apples') and find only apples, but use the same logic for pears and oranges. It could save you time & extra logic. When you delete a template with the API, be sure to delete the fieldgroup to, if it is the last template that uses the fieldgroup.2 points
-
I think the project is still in developement and not intended to be live.2 points
-
What Andre said. However, If it is possible to populate one autocomplete field with the pages from another—I feel like it shouldn't allow those pages as values, especially since it looks like your autocompletes are populated based on template—it would seem an odd behavior. What happens if you then remove that page that was set from the other field? Would you expect it to get removed from the original autocomplete? Starts to get complicated quickly. Perhaps I'm reading too much into what you are after.2 points
-
Hi Blad, I have in the past, created two-way relationships like this however, have you considered just having it one-way and using the API to find the reverse? As an example <?php // get all clients properties // assumes a $client variable $properties = $client->properties; // get all clients who have access to a property // assumes a $property variable $clients = $pages->find("template=client, properties=$property"); ?> It depends on whether you really need it to show both ways in the admin, or you just want to be able to display both directions somewhere on the frontend. If you really do need it to show both ways in the admin, you can create a simple module that creates the reverse relationship when you update a certain page.2 points
-
2 points
-
Why did I see this just after setting up four kinds of categorizations on my current project. Next time I need it, I'll install this module.2 points
-
We're aiming for soft launch this Friday and official a week later. Tried for last Friday but still had some issues to resolve + waiting on some things. I believe it's safe to start using now, but you'll still want to upgrade when 2.5 is official.2 points
-
Thank you all. If you have something else on your "wishlist" for development let us know. We spent the last week working on a super boring SAP shop for a university project so progress slowed down a little bit. However, I've made a new video to show the latest features we've been working on. Beside the new "Create site" page and the workflow for new users, we build backend features like the version change and a backup system. The service always has the latest ProcessWire files from github and it's possible to schedule sites for deletion now. Some bugs are still open and the Help page was just started. Our plan is to launch the service to the public in the next week.2 points
-
It depends on what you have. If you have the specialty as a string, you can select for the page’s title field like so: $pages->find('template=physician, specialty.title={$search}'); If you know the specialty’s page-id or path, that should work as well. For example on a specialty page, you would want to list all physicians that have that specialty: $pages->find('template=physician, specialty={$page->id}');2 points
-
The Background Early in December 2013, the National Geographic Traveller India team at Amar Chitra Katha, called Pigtail Pundits over to help them build their website. Till then, the NGTI site was a poorly cobbled together, pale shadow of the publication in html and css, comprising, mainly content from the offline magazine articles. It was formatted too plainly, and didn’t carry the richness of imagery, gloss and character that you’d associate with anything from the National Geographic stable. The Brief NGTI had an ambitious remit for the revamped website. It will contain the offline magazine, in full, with each issue richly illustrated with some 35 odd travel stories and encrusted with glorious pictures The past issues of the magazine, some 15 of them so far, would have to be imported into the new system gradually It will carry have articles written exclusively for the web, by a separate editorial team It must have the ability for accepting photos from amateur travel enthusiasts, every day It must showcase the images from National Geographic Traveller in all its glory through on-page galleries and sliders It must have a workflow for the editorial to schedule articles into the future It must be fitted with rich tags to describe/ cross-tag the articles, the ability for browsers to comment and search ability built into it What’s more, it must come close in feel and richness to the National Geographic mother site in the US. That site incidentally, was in Beta at that time, and used some really fancy, jaw dropping scripts and effects. We were wondering as to what technology it was built on. But, there were a lot of challenges to tackle before we even reached to the front-end effects. To Drupal, or to Processwire? The Million $$ choice. We took on the challenge of the revamp. Thinking through and rationalising the different and varying content types in the magazine was our first task. We noted 13 different types. The trick was to winnow this down to just one content type that could fit all types of articles. Then, in fitting this content type into the system, we had to take a few calls. We argued that the system must have the flexibility to allow editors to embellish their articles - with drop caps, pull quotes, captions, guides and other style ornamentation that was singular to the National Geographic Traveller. In order to do this effectively, we would have pre-styled codes in the system that could be invoked using short codes as the editors saw fit. This was a whole sight better and more flexible than putting text into pre-styled boxes that would constrain the editorial. Drupal CMS was our first choice in putting this system together. We had worked with Drupal for several years now and we knew a thing or two about customising it too. The only challenge was to get a young team at Pigtail Pundits behind Drupal. The learning curve for Drupal was always daunting and that was a concern. We started work on Drupal in early January 2014. We cobbled together an internal team that would work on the project. After about a month into Drupal, we had almost everything ready for a demo to the client, save for styling. In early February, we had a rethink. We were working on some projects and testing out Processwire, internally in parallel with the NatGeo project. We found PW to be a fast, flexible, efficient system, without either the bloat and the learning curve required of Drupal. We had to take a call. Drupal, for all its goodness, still made heavy weather of its modules. Drupal optimisation alone required a lot of modules at the application level. Plus a few on the server - memcache, ably supplemented with server processing speed and memory in fair, generous helpings. But optimisation itself was just one of the many things that troubled us about Drupal. There were a heap of other modules, each adding weight and extra lumber to the ponderous system. Besides there was image heavy content. We had serious doubts as to the conditions under which the site would run well with Drupal, both immediately, and in the long run. We had to take a call. Time for a few seditious thoughts Could we now change the NGTI project to Processwire from Drupal? What would be the implications? For us, for NGTI? We had to grapple with a whole bunch of fallouts of this. How do we come clean with the client on this? Would that decision to shift hurt us? What if the client were to say no to the shift? What about getting our internal team that was already on Drupal, come to grips with Processwire? How long would that take? The reasons to shift to Processwire were clear. Speed, flexibility and scalability given the volume of content that was going to be part of the magazine and web editorial, the features we required, and the potential traffic on the NGTI site. The decision had to be made now. We decided to make an early switch to PW. And in retrospect, it was probably the best decision we took. We had to instil confidence in the client that this switch to Processwire was the right thing to do. If we relayed the news too early, it could have worked against us. We had to prove that PW was a better decision. So we went ahead and simulated all that we’d done in Drupal into Processwire without asking the client, or giving them a whiff of what we were up to. We worked in parallel on both the systems. It took us about 15 days to get everything in Drupal into PW. Mercifully for us the client was hunting for a design team that would do justice to the Nat Geo design pedigree and that took some time. Along with the fact that the new web editorial team was still being formed. We used this lull effectively to make the switch. Remarkably, our Drupal team picked up PW twithout any issues. It took them a week to grasp it and get going. That was a record of sorts as we’d folks who struggled with Drupal even after 3 months on a project, still coming to grips with techniques and modules. But PW was a cinch. The Processwire Miracle We put together the first cut of the site in Processwire. Rationalized content types for magazine articles were in One magazine issue was fed in so that we could slap on some styling Hannah code was used generously to style the content within the editor, without getting in the way of content, or trapping this into pre-styled text-area boxes. Magazine captions, guides, block-quotes, drop caps were driven by Hannah to facilitate the editorial hoopla Gallery and slider scripts were quarried for the demo The demo date was decided in early April. We showed off the system, its speed, and ease of use, live to the client. It was only after the demo that we told them that the system was not Drupal, but Processwire. They were already sold by then. The real intensity on the NGTI project however started in June 2014 when the designer Matt Daniels was brought in by NGTI. We were privy to the early designs of the Home Page, Landing Pages and Detail Pages. But were anxious as to how things would play when the entire design was complete. After all the design was not in our control. Luckily, everything went off well. There were a few challenges, and these were taken up and resolved. Javascript for the galleries, sliders had to be rewritten from scratch to conform to the design requirements Editorial came up with a list of how they wanted articles to be featured on the Home Page in blocks and we had to program this accordingly. We managed to queue the articles and then lop the old off, when the new were published Destination page required maps by default and then of city/ country being searched. This was programmed using Google APIs. Marketing came up with the need for ads - leaderboard and sidebar and we had to fit these in An Events Calendar was programmed from ground up, as per the design for Events The import of prior issues was debated, captured into excel sheets, reviewed, and reviewed some more. Scripts were written for import. Scripts were written to test the integrity of the data input before import. And everything came together in August, 2014. 6 magazine issues were imported before the launch was announced on August 14. The NGTI team went in and styled these quickly using the tools we had built for them. The final build had 20 different templates. In retrospect, we could have rationalised these too to fewer. But these came in bit by bit for the build and there was little we could do there as we couldn’t see the whole, before it arrived. The NGTI team was trained on the backend operations as part of the build itself, so by the time we had completed the site, they were up and ready to input. The project is still in beta for a few days. Optimization using just compression of CSS & JS works fine for speed. The site works like a charm now. Thanks everyone Thanks are due to Processwire and the amazing system and set of modules that are in place. Thank you Ryan Cramer. We don’t have to tell you how much we enjoy working with this system, after coming from Drupal and WordPress. Thanks to all the lovely folks on the PW forum who had answers to niggling issues we had. Key Tools, Systems used: Processwire 2.4 CMS with Foundation 4.0 framework Hannah Code for short codes in the editor for style application Event Calendar was coded ground up Form Builder was used for front end forms CK Editor, for text area editing with Image extra for description and tags ProCache - for server level caching Video Embeds and Images used field uploads Image Captions & Tags using image extra fields Scheduler, for advanced date publishing AIOM - for compressing JS and CSS for speed improvements MailChimp Integration for Newsletter Disqus Integration for Comments Integration of Facebook, Instagram, Google Maps via API Integration and customisation of Google Search Integration of DoubleClick and Adsense for advertising1 point
-
AlternativeGridImages module for Processwire Details Add a slider directly proportional to the size of the images introduced in the input field image. Installation copy AlternativeGridImages folder to /site/modules/ Screenshot https://github.com/LuisSantiago/AlternativeGridImages Updated 1.0.6: - Renamed altGrid as AlternativeGridImages. (Thanks @adrian) - Changed styles. - The slider value is saved in a cookie. (Thanks @Martijn Geerts) Updated 1.0.7: - Limit the number of characters in the file name (all items have the same height) (Thanks @enricob)1 point
-
Hi, during work on some own modules (frontend content manager, frontend users) I noticed my need of a helper module. Template2Form (working title) is a module to build a form based on fields get from a page object or a template file (tmp fake page object). During build process each field could be hooked in to modify it. Also it's possible to modifiy form, submit button and form fields via function params. It's my first (basic / dev state) module I post here... If it will be useable I have to clean up and comment the code well... template2form class <?php /** * Processwire 'template2form' module * * template2form - generate form from page / template fields * * @author pwFoo * @since 2014-07-18 * * ProcessWire 2.x * Copyright (C) 2011 by Ryan Cramer * Licensed under GNU/GPL v2, see LICENSE.TXT * * http://www.processwire.com * http://www.ryancramer.com */ class Template2Form extends WireData implements Module { /** * @var object $form generated form object */ public $form; /** * @var array $option multidimensional array with options */ private $option; /** * getModuleInfo is a module required by all modules to tell ProcessWire about them * @return array */ public static function getModuleInfo() { return array( 'title' => 'Template2Form', 'summary' => 'Generate form from template fields', 'version' => '0.0.1', ); } /** * Default module and form options * @var array $defaultOptions static mutlidimensional array with default options */ public static $defaultOptions = array( 'page' => null, 'template' => null, 'prefillFormFields' => null, 'jquery' => null, 'form' => array('method' => 'post', 'action' => '', 'id' => 'login', 'name' => 'login'), 'formSubmit' => array('id' => 'submit', 'name' => 'submit', 'value' => 'Submit'), 'formFields' => null, ); public function init() { $this->addHookAfter('Template2Form::buildField', $this, 'hookingFormField', array('priority'=>20)); } /** * Set / merge module and form options * @param array $options Array with given options * @return null */ private function setOptions (array $options = null) { if($options != null && is_array($options)) { $this->option = array_replace_recursive(self::$defaultOptions, $options); // Use template instead of page if given if ($this->option['template] !== null) { $this->option['page'] = $this->fakePage($this->option['template']); } // No template or page? Use current page... elseif ($this->option['template'] === null) { $this->option['page'] = $this->page; } if ($this->option['jquery']) { $this->modules->get('JqueryCore'); } } else { $this->option = self::$defaultOptions; } } /** * Generate the form object * @param array $options Set of optional and needed settings * @return object Generated form */ public function getForm (array $options = null) { $this->setOptions($options); $this->form = $this->buildForm (); return $this->form; } /** * Generate the form object from given fields * @return object Generated form */ private function buildForm () { $form = $this->modules->get('InputfieldForm'); $form = $this->setFormAttr($form); // Get fields to build the form $fields = $this->templates->get($this->option['page']->template)->fields; foreach ($fields as $field) { $f = $this->buildField ($field); // Get Inputfield object if ($f !== NULL) $form->append($f); // Remove NULLed fields from from... } $form->append($this->addSubmitButton()); return $form; } /** * Set form attributes and return the object * @param object $form * @return object Form with added attributes */ protected function ___setFormAttr($form) { $form->id = $this->option['form']['id']; $form->name = $this->option['form']['name']; $form->action = $this->option['form']['action']; $form->method = $this->option['form']['method']; return $form; } /** * Generate Inputfield object from given field object * @param object $field Page field object * @return object */ protected function ___buildField ($field) { return $field->getInputfield($this->option['page']); } /** * Modify the current field object by hook in after buildField function * @param object $event */ protected function ___hookingFormField ($event) { $field = $event->return; $hook = $this->option['formFields'][$field->name]; // Remove selected field... if ($hook['remove'] == true) { $event->return = NULL; } // prefill form fields from page value... elseif ($this->option['prefillFormFields'] && $event->page->get($field->name)) { $hook['set']['value'] = $event->page->get($field->name); } if (!isset($hook)) return; // nothing to do with this field... // Set form field values... elseif (is_array($hook['set'])) { foreach ($hook['set'] as $key => $value) { $field->set($key, $value); } $event->return = $field; } } /** * Build the form submit button * @return object form submit Inputfield */ protected function ___addSubmitButton() { $btn = $this->modules->get('InputfieldSubmit'); $btn->attr('id', $this->option['formSubmit']['id']); $btn->attr('name', $this->option['formSubmit']['name']); $btn->attr('value', $this->option['formSubmit']['value']); return $btn; } /** * Rendering the current form * @return string Rendered form as html code */ public function ___formRender() { return $this->form->render(); } /** * Process form data if send * @return object Processed form data */ public function ___formProcess() { $submit = $this->option['formSubmit']['id']; if(!$this->input->post->$submit) return NULL; // form NOT submitted... $processedForm = $this->form->processInput($this->input->post); // form api process form values if(!$this->form->getErrors()) return $processedForm; // form processed: OK else return false; // form send with errors } /** * Make fake page and assign needed template * @param string $tpl Template to assign * @return object Generated fake page to work with */ private function fakePage($tpl) { $fakePage = new Page(); $fakePage->template = $tpl; return $fakePage; } /** * jsConfig settings needed by wysiwyg editor * @return string Basic JavaScript config */ public function ___jsConfig () { $jsConfig = $this->config->js(); $jsConfig['debug'] = $this->config->debug; $jsConfig['urls'] = array( 'root' => $this->config->urls->root, 'admin' => $this->config->urls->admin, 'modules' => $this->config->urls->modules, 'core' => $this->config->urls->core, 'files' => $this->config->urls->files, 'templates' => $this->config->urls->templates, 'adminTemplates' => $this->config->urls->adminTemplates, ); return '<script type="text/javascript">var config = ' . json_encode($jsConfig) . '</script>'; } } Usage examples $t2f = $modules->get('Template2Form'); // Remove field 'headline' and 'body' from form $hookFormFields['headline'] = array('remove' => true); $hookFormFields['body'] = array('remove' => true); // Set / Overwrite field attributes / values like you could do with form api $hookFormFields['title'] = array('set' => array('value' => 'CustomTitle...', 'type' => 'password')); $hookFormFields['summary'] = array('set' => array('value' => 'My overwritten summary...')); // Overwrite submit button attributes (default: id, name, value) $hookFormSubmit = array('value' => 'Speichern'); /* * Build the multidemensional array * page (object) or template (string) -- to build the form from * prefillFormFields -- prefill fields (for example to build a frontend edit page * jquery -- Load JqueryCore module (during getForm() call) * form -- set form attributes / values * formFields -- array to set field values / attributes, take a look at form api examples * formSubmit -- set form submit button attributes / values */ $formOptions = array('page' => $page, 'template' => null, 'prefillFormFields' => true, 'jquery' => true 'formFields' => $hookFormFields, 'formSubmit' => $hookFormSubmit); // Generate the form and set options above $t2f->getForm($formOptions); // process form and return processed form date $process = $t2f->formProcess(); if ($process === NULL) // form not sent elseif ($process === false) // form sent, but with errors elseif ($process == true) // form sent without errors // Render form... $form = $t2f->formRender(); echo '<html><head>'; // jsConfig needed by ckeditor echo $t2f->jsConfig() . "\n"; // outpunt needed scripts for inputfield modules, ... foreach ($config->scripts as $file) { echo "<script type='text/javascript' src='$file'></script>\n"; } foreach ($config->styles as $file) { echo "<link type='text/css' href='$file' rel='stylesheet' />\n"; } echo '</head><body>'; echo $form; // output form echo '</body></html>';1 point
-
1 point
-
1 point
-
on topic: your way seems fine off topic: maybe sanitize your input before using it $filter = $sanitizer->pageName($input->get->filter, true); $sort = $sanitizer->fieldName($input->get->sort);1 point
-
@adrian: You're right... forgot to upload it. I think I will spend some time this weekend on finishing processwire.tv1 point
-
Yup. I agree with Diogo. It's the best way to find the differences.1 point
-
1 point
-
How about http://modules.processwire.com/modules/page-references-tab/ If you reference one page with another (with a page field) why do you need to reference back? You can easily use the reference in both directions.1 point
-
Just Back from there... nice city.... If you read this, the 'El Born' quarter is nice... Boqueria [next to Rambla's] where you can taste nice things, Picasso museum [if you're into that], Park Güell, Montjuïc, Sagrade Famila, and as I saw somewhere here, for eating and drinking, pick the side streets, cheaper and [most of the time] better service... Certainly try 'patatas bravas'... Didn't have too much time and had to work, but I'd like to go back! Off Topic: is there a processwire.tv topic somewhere? Anyway, have fun!1 point
-
Your solution seems fine to me... or I don't understand what is the doubt (?) If your filters are simple you might want to use JS instead. If all you want is to hide things, why send it back to the server? You could easily do it with data attributes on each result.1 point
-
That's right. We're still in closed development. Apache just searches for the first active virtual host which is the PMA at the moment and redirects to it. PMA will be used if you ever need direct access to the database. I hope we can launch this weekend .. only one part of the backup script is not ready for prime time. This part is critical, because we don't want to lose your data. Otherwise we're testing the system and are fixing bugs. You can follow us on twitter for more information: https://twitter.com/lightningpw1 point
-
Maybe this? $selects = $pages->find("template=member-profile")->find($filter)->sort($sort);1 point
-
Looks great, but I get when I try to visit: http://pma.lightning.pw1 point
-
Sorry, I was on mobile and it came out a bit cryptic I meant two databases of course.1 point
-
Although I do see the value in being able to "see" the reference two-ways in the admin. Might be nice for a backend user to see it from either angle.1 point
-
That's exactly what I did now. In the relavent templates I just call this, to get the changed value. $page->get("link|url"); I used this to have a two way url structure for categorized content: "…/articles/articlename/" and "…/category/categoryname/articlename/". Thinking about writing a short tutorial for this.1 point
-
Hi John - thanks for your input here. Sorry, but I have removed the link you included for the moment as the OP was not looking for logo design services. Indeed you could just copy the PNG from the site's banner, but it is definitely nice to have an SVG/EPS or other vector version of the logo so that it can be resized.1 point
-
1 point
-
Thank you. It looks like renobird has got it to create new users by adding the title field to the user template https://processwire.com/talk/topic/383-module-import-pages-from-csv-file/page-4 I'll have a go at this later and get back to you.1 point
-
1 point
-
Just to add to the confusion. - You can make the title field not required in template context. - You can set a template to not include global fields (advanced settings) So you could remove title for that template but still have title global.1 point
-
Ivan, always happy to oblige:-) The backend is not customized. It uses the Modesta Theme which we felt was a tad better than the default. We were under tight time pressures to launch the site and decided to skip any backend customization. For the time being, permissions are just for backend admin - web, magazine editorial. There was an idea we had mooted with roles for users who submit photos, but because of the launch deadline, we have deferred that bit for Phase 2. I am appending a screenshot of the backend, just to show you what we have done. The Block-System that you see, is for organizing the Home Page content. It has 3 regions [left, middle, right], very similar to Drupal's regions, in the template. Within each region, post excerpts can be added by the admin for control of the Home Page content. Magazines and Web Editorial, are organized by month. Trust that answers your questions.1 point
-
new german updates for actual PW dev 2.4.18 (04 September 2014). Zip contains only updated/added files (in comparison to the default 2.4 lang pack). updated files: wire--modules--fieldtype--fieldtypecomments--fieldtypecomments-module.json wire--modules--inputfield--inputfieldpagetable--inputfieldpagetable-module.json wire--modules--languagesupport--languagetabs-module.json wire--modules--process--processtemplate--processtemplate-module.json pw-lang-de-dev-update.zip1 point
-
Thank you so much apesia, soma and adrian. @soma and @apeisa - I followed your advise. Thanks again now it is working fine (happy). @adrian - Yes adrian I put news-pager-index.php file under template directory. Just to recap: if we need use external template file other than the template name we have to use altFilename property. In the normal scenario we can use name property if the template file name and template name were same. Here is the working copy thanks to processwire and friendly community members. It might be helpful to newbies like me. class NewsPager extends WireData implements Module{ public static function getModuleInfo() { return array( 'title' => 'News pager', 'version' => 001, 'summary' => 'News pager template', 'singular' => true, 'autoload' => true, ); } public function init() { //todo add some listeners } /** * Install the module * */ public function ___install() { // new fieldgroup $fg = new Fieldgroup(); $fg->name = 'news-pager-index'; $fg->add($this->fields->get('title')); // needed title field $fg->add($this->fields->get('body')); // needed body field $fg->save(); // new template using the fieldgroup and a template $t = new Template(); $t->name = 'news-pager-index';//Used different name other than file name /* * altFilename property will accept file-name or file-name.php * or even $this->config->paths->templates . 'file-name.php' * Note: template file needs to be placed under * template directory */ $t->altFilename = 'news-pager-index-file';//name of the template file which is under tml dir. $t->fieldgroup = $fg; // add the field group $t->save(); } /** * Uninstall the module * */ public function ___uninstall() { $templateNeeded = $this->templates->get("news-pager-index"); $fgOld = $this->fieldgroups->get('news-pager-index'); if ($templateNeeded->getNumPages() > 0) { throw new WireException("Can't uninstall because template been used by some pages."); }else { wire('templates')->delete($templateNeeded); wire('fieldgroups')->delete($fgOld); } } }1 point
-
The 'roles' field is of type 'page' and isn't supported by ImportPagesCSV out of the box. If you want it to show up you need to add something to the modules fieldtype array: 'FieldtypePage', // add this line I haven't tried it myself but nik has, so courtesy nik. For more info you should read his comment in this thread: http://processwire.com/talk/topic/383-module-import-pages-from-csv-file/?p=21476 Also pay attention to his words on how to reference the roles in your csv file. In this case i think it would be best to look up the id's of the roles you've defined and put them in your csv (find and replace, you know the drill). In case you don't know: you can look up the page id's of the roles in a couple of ways but hovering the edit link and looking at the status bar of your browser is easiest;1 point
-
I found Janko's FormToWizard code to be one of the simplest ways to implement a multi-page/multi-slide form. Now with the Processwire this just got easier. I tweaked his script a wee bit to work with the API forms described in this thread. PWformToWizard.js bunching your fields into fieldsets just as Ryan described above, each fieldset will become a page/slide. Instead using the <legend> tag that Janko uses, the script now generates a legend based on the label, specifically anything that comes before a colon ':' first add the script: <script type="text/javascript" src="PWformToWizard.js"></script> then use this javascript to initiallize formToWizard: $("#SignupForm").formToWizard(); the default styles are: <style type="text/css"> body { font-family:Lucida Sans, Arial, Helvetica, Sans-Serif; font-size:13px; margin:20px;} #main { width:960px; margin: 0px auto; border:solid 1px #b2b3b5; -moz-border-radius:10px; padding:20px; background-color:#f6f6f6;} #header { text-align:center; border-bottom:solid 1px #b2b3b5; margin: 0 0 20px 0; } fieldset { border:none; width:320px;} legend { font-size:18px; margin:0px; padding:10px 0px; color:#b0232a; font-weight:bold;} label { display:block; margin:15px 0 5px;} input[type=text], input[type=password] { width:300px; padding:5px; border:solid 1px #000;} .prev, .next { background-color:#b0232a; padding:5px 10px; color:#fff; text-decoration:none;} .prev:hover, .next:hover { background-color:#000; text-decoration:none;} .prev { float:left;} .next { float:right;} #steps { list-style:none; width:100%; overflow:hidden; margin:0px; padding:0px;} #steps li {font-size:24px; float:left; padding:10px; color:#b0b1b3;} #steps li span {font-size:11px; display:block;} #steps li.current { color:#000;} #makeWizard { background-color:#b0232a; color:#fff; padding:5px 10px; text-decoration:none; font-size:18px;} #makeWizard:hover { background-color:#000;} </style> <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js"></script> <script type="text/javascript" src="formToWizard.js"></script> <script type="text/javascript"> $(document).ready(function(){ $("#SignupForm").formToWizard({ submitButton: 'SaveAccount' }) }); </script> see janko's page for more info~ Now, just to add some responsive jquery validation to each 'next' button...1 point
-
Great tutorial Soma! This is the best summary of using PW's Inputfields that I've seen. I noticed you did $field->attr('id+name', 'email') so just wanted to explain what that is for those that may be unsure of the syntax. That syntax is basically saying to set the 'id' and 'name' attribute to have the 'email'. While every field needs a 'name' attribute (like in HTML) the 'id' attribute is optional… if you don't assign an id attribute, PW will make one up. If you intend to custom style a field with CSS or target it from javascript, then it's best to assign your own 'id' attribute. Otherwise, it doesn't matter. // this… $field->attr('id+name', 'email'); // …is the same as: $field->attr('id', 'email'); $field->attr('name', 'email'); // …as is this (direct reference): $field->id = 'email'; $field->name = 'email'; The advantage of using the attr() function over direct reference is that attr() can't ever collide with other Inputfield properties that might have the same name as a field attribute. It's basically your way of saying "this should definitely be an HTML attribute and not anything else." For recognized attributes like 'name' or 'value' it doesn't matter what syntax you use because an Inputfield already knows 'name' and 'value' are standard HTML attributes. But if you needed to add a custom attribute like "data-something", well then you'd definitely want to use the attr() method of setting. That attr() method should only be used for things that would actually be HTML attributes of the <input>, because they will literally end up there. So if you do an $field->attr('label', 'Hello'); you'll end up with an <input label='Hello'> in the markup, which is obviously not something that you want. That's why you assign a non-attribute property like 'label' or 'description' directly, like: $field->label = 'Something'; Last note about $attr() is that it can be used for both setting and getting attributes: $field->attr('value', 'something'); echo "The field's value is: " . $field->attr('value'); // same as: $field->value = 'something'; echo "The field's value is $field->value"; To extend your example, lets say that you wanted the 'email' and 'password' fields in a fieldset titled "About You". You would create the fieldset, and then add/append the fields to the $fieldset rather than the $form. Then you'd add the $fieldset to the $form: $fieldset = $modules->get('InputfieldFieldset'); $fieldset->label = 'About You'; $field = $modules->get("InputfieldEmail"); $field->label = "E-Mail"; $field->attr('id+name','email'); $field->required = 1; $fieldset->append($field); // append the field $field = $modules->get("InputfieldPassword"); $field->label = "Password"; $field->attr("id+name","pass"); $field->required = 1; $fieldset->append($field); $form->append($fieldset); Or lets say that you wanted those 'email' and 'password' fields to be each in their own column so that are next to each other horizontally rather than vertically. You would assign the 'columnWidth' property to both the email and password fields. In this case, we'd give them both a value of 50 to say that we want them to be a 50% width column: $field->columnWidth = 50; To jump out of tutorial mode and into idea mode: lately I've been thinking that PW should have a YAML to Inputfields conversion tool in the core (something that would be pretty easy to build), so that one could define a form like this: And create it like this (where $yaml is the string above above): $form = $modules->get('InputfieldForm'); $form->load($yaml); echo $form->render();1 point
-
Ryan, Many thanks for this module, I just used it to add 436 users. There were a small handful of things that weren't initially clear, so I detailed them below for anyone else trying to import users. If you plan to import passwords, you need to open the module and add FieldTypePassword to $fieldtypes protected $fieldtypes = array( 'FieldtypePageTitle', 'FieldtypeText', 'FieldtypeTextarea', 'FieldtypeInteger', 'FieldtypeFloat', 'FieldtypeEmail', 'FieldtypeURL', 'FieldtypeCheckbox', 'FieldtypeFile', 'FieldtypePassword', // add this line ); Since users are pages and all pages require a title, your CSV will need to have a title column. In my case, I duplicated all the usernames into that column — so name and title are the same. In order for title to show as a connection option during your import, you need to add the title field to the user template file. To do this, go to: Setup > Templates (open the filters area at the top, and choose "show system templates". Select the user template and add the title field. One other thing to note, be sure to have a roles column in your CSV with roles for each user. I forgot that during my first test import and all the users were set to guest. You should be all set to import your users.1 point