Leaderboard
Popular Content
Showing content with the highest reputation on 07/22/2017 in all areas
-
This week we've got more to tell (and show) you about our upcoming page export/import feature, along with several screenshots of the progress: https://processwire.com/blog/posts/processwire-3.0.68-and-more-on-page-export-import/3 points
-
Hey @bernhard - I spent quite a bit of time looking into this the other day with no success. It turns out it's not just hooks inside ready.php - it seems like ready.php is never called at all from the Tracy console panel. I will investigate further, but so far a bit of a mystery. I thought perhaps it was an issue with ajax calls (which the console panel uses), but a normal ajax call results in ready.php being called, so really not sure at the moment. I'll see what I can figure out. Cheers, Adrian2 points
-
You could also just do this. By using "first()" you avoid the need for the foreach loop. $cart->renderPriceAndCurrency($release->children("limit=1, sort=pad_price")->first()->pad_price);2 points
-
$index is the key of the array item, which in the case of a PageArray like this is the zero-based index of the item in the array. So it starts at 0 and goes up with each subsequent item. The "</div><div class='col-6'>" portion is where we end the first column and start the second column. There was an error in my code which I have corrected now - we only want this inserted once, when $index matches half the number of items in $testimonials rounded up to the nearest whole number.2 points
-
Nice tutorial, thanks! You could simplify the methods a little by making sure you always get the Images field as a Pageimages array, e.g. $wire->addHookMethod('Page::siteFeaturedImage', function($event) { $page = $event->object; if ($page->template != "article") { throw new WireException("Page::siteFeaturedImage() only works on 'Pages of article template', Page ID=$page is not such!"); } $article_featured = $page->getUnformatted('article_featured'); // always a Pageimages array if (count($article_featured)) { $img_url = $article_featured->first()->url; } else { $img_url = urls()->templates . "assets/img/missing-article_image.jpg"; //we show this when image is not available } $event->return = $img_url; });2 points
-
Nice one. Just another way to skin the cat... <?php $testimonials = $page->testimonials; $testimonials->shuffle(); $firstTestimonial = $testimonials->shift(); ?> <div class="jumbotron jumbotron-fluid bg-color"> <div class="container"> <h2><?= $firstTestimonial->title; ?></h2> <p><?= $firstTestimonial->testimonialBody; ?> - <i><?= $firstTestimonial->testimonialReviewee; ?></i></p> </div> </div> <div class='container'> <div class='row'> <div class='col-6'> <?php foreach($testimonials as $index => $testimonial): ?> <?php if($index == ceil(count($testimonials) / 2)): ?> </div> <div class='col-6'> <?php endif; ?> <h2 class='py-3'><?= $testimonial->title; ?></h2> <p><?= $testimonial->testimonialBody; ?></p> <p class="font-weight-bold text-muted">- <i><?= $testimonial->testimonialReviewee; ?></i></p> <?php endforeach; ?> </div> </div> </div>2 points
-
@ryan thanks a lot! I had a little use case where I couldn't resist to use the new feature. It was only for pages with text fieldtypes. I used two little bootstrap scripts to export & import some pages. export.php import.php2 points
-
Hi PW fanatics In this post I share two of my addHookMethods for those interested. As you surely already know (if not, time to take a look at it) the Wire::addHookMethod() and the Wire::addHookProperty() API methods can be used to "breath some extra OOP" into your projects. Using addHookMethods and addHookProperty are alternatives to "Using custom page types in ProcessWire". The methods I want to share: basically the idea here is to get the URL pointing to images uploaded in the admin without writing much code in the template files. With methods like these below, it does not matter what Formatted value is set to the images, because some predefined defaults are used in all circumstances. #1 Example template file code: <?php $img_src = $latest_article->siteFeaturedImage(); ?> <img src="<?= $img_src ?>" alt="<?= $page->title ?>"> addHookMethod goes into /site/init.php <?php /* Returns URL of the original Pageimage of Article. * Image field's value can be either null (default missing image), Pageimage or Pageimages. * * @return string */ $wire->addHookMethod('Page::siteFeaturedImage', function($event) { $page = $event->object; if ($page->template != "article") { throw new WireException("Page::siteFeaturedImage() only works on 'Pages of article template', Page ID=$page is not such!"); } $article_featured = $page->getUnformatted('article_featured'); //always a Pageimages array if (count($article_featured)) { $img_url = $article_featured->first()->url; } else { $img_url = urls()->templates . "assets/img/missing-article_image.jpg"; //we show this when image is not available } $event->return = $img_url; }); ?> #2 Example template file code: <?php $img600_src = $page->siteProductImageMaxSize(600, 600, ['rotate' => 180]); ?> <img src="<?= $img600_src ?>" alt="<?= $page->title ?>"> addHookMethod goes into /site/init.php <?php /* Generates image variations for Product images. Returns URL of Pageimage. * Image field's value can be either null (default missing image), Pageimage or Pageimages. * * @param int arguments[0] Max allowed width * @param int arguments[1] Max allowed height * @param array arguments[2] See `Pageimage::size()` method for options * @return string */ $wire->addHookMethod('Page::siteProductImageMaxSize', function($event) { $page = $event->object; if ($page->template != "product") { throw new WireException("Page::siteProductImageMaxSize() only works on 'Pages of product template', Page ID=$page is not such!"); } $width = isset($event->arguments[0]) ? $event->arguments[0] : 48; //default width $height = isset($event->arguments[1]) ? $event->arguments[1] : 48; //default height $options = isset($event->arguments[2]) ? $event->arguments[2] : $options = array(); //default empty options $product_image = $page->getUnformatted('product_image'); //always a Pageimages array if (count($product_image)) { $img_url = $product_image->first()->maxSize($width, $height, $options)->url; } else { $img_url = urls()->templates . "assets/img/product-missing-image.jpg"; //we show this when image is not available } $event->return = $img_url; }); ?> BTW, you can find more examples here: How can I add a new method via a hook? Working with custom utility hooks Adding array_chunk support to WireArray addHookProperty() versus addHookMethod() Have a nice weekend!1 point
-
Since you guys asked for it, I'll take a stab at a case study on the development process. Most of the development was done in about a week and a half. I started with the basic profile, but it ended up being something somewhat similar to the Blog profile in terms of how it's structured. Below I'll cover some details on the biggest parts of the project, which included data conversion, the template structure, the front-end development and anything else I can think of. Data Conversion from WordPress to ProcessWire One of the larger parts of the project was converting all of the data over from WordPress to ProcessWire. I wrote a conversion script so that we could re-import as many times as needed since new stories get added to cmscritic.com almost daily. In order to get the data out of WordPress, I queried the WordPress database directly (my local copy of it anyway) to extract what we needed from the tables wp_posts for the blog posts and pages, and then wp_terms, wp_term_relationships, and wp_term_taxonomy for the topics and tags. WordPress stores its TinyMCE text in a state that is something in between text and HTML, with the most obvious thing being that there are no <p> tags present in the wp_posts database. Rather than trying to figure out the full methodology behind that, I just included WP's wp-formatting.php file and ran the wpautop() function on the body text before inserting into ProcessWire. I know a lot of people have bad things to say about WordPress's architecture, but I must admit that the fact that I can just include a single file from WordPress's core without worrying about any other dependencies was a nice situation, at least in this case. In order to keep track of the WordPress pages imported into ProcessWire through repeat imports, I kept a "wpid" field in ProcessWire. That just held the WordPress post ID from the wp_posts table. That way, when importing, I could very easily tell if we needed to create a new page or modify an existing one. Another factor that had to be considered during import was that the site used a lot of "Hana code", which looked like [hana-code-insert name="something" /]. I solved this by making our own version of the Hanna code module, which was posted earlier this week. Here's an abbreviated look at how to import posts from WordPress to ProcessWire: $wpdb = new PDO("mysql:dbname=wp_cmscritic;host=localhost", "root", "root", array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'UTF8'")); $posts = wire('pages')->get('/posts/'); $sql = " SELECT * FROM wp_posts WHERE post_type='post' AND post_status='publish' ORDER BY post_date "; $query = $wpdb->prepare($sql); $query->execute(); while($row = $query->fetch(PDO::FETCH_ASSOC)) { $post = $posts->child("wpid=$row[ID]"); // do we already have this post? if(!$post->id) { // create a new post $post = new Page(); $post->template = 'post'; $post->parent = $posts; echo "Creating new post...\n"; } $post->of(false); $post->name = wire('sanitizer')->pageName($row['post_name']); $post->title = $row['post_title']; $post->date = $row['post_date']; $post->summary = $row['post_excerpt']; $post->wpid = $row['ID']; // assign the bodycopy after adding <p> tags // the wpautop() function is from WordPress /wp-includes/wp-formatting.php $post->body = wpautop($row['post_content']); $post->save(); echo "Saved post: $post->path\n"; } What I've left out here is the importing of images, topics, tags, and setting the correct authors for each post. If anyone is interested, I'll be happy to go more in depth on that, but didn't want to overwhelm this message with code. Template File Structure This site makes use of the $config->prependTemplateFile to automatically include the file _init.php before rendering a template file, and $config->appendTemplateFile to automatically include the file _main.php after. So the /site/config.php has this: $config->prependTemplateFile = '_init.php'; $config->appendTemplateFile = '_main.php'; You may recognize this as being the same setup from the Skyscrapers profile. The _init.php includes files containing functions we want to be available to all of our templates, and set default values for the regions we populate: /site/templates/_init.php /** * Include function and hook definition files * */ require_once("./includes/render.php"); require_once("./includes/hooks.php"); /** * Initialize variables populated by templates that get output in _main.php * */ $browserTitle = $page->get('browser_title|title'); $body = "<h1>" . $page->get('headline|title') . "</h1>" . $page->body; $side = ''; $renderMain = true; // whether to include the _main.php file The includes/render.php file that is included above includes several functions for generating markup of navigation and post summaries, or any other shared markup generation functions. Examples are renderPost(), renderNav(), renderTags(). This is similar to the blog.inc file from the Blog profile except that I'm letting these functions generate and return their own markup rather than splitting them into separate view files. I personally find this easier to maintain even if it's not as MVC. The includes/hooks.php sets up any hooks I want to be present for all of my templates. I could have also done this with an autoload module, but found this to just be a little simpler since my hooks were only needed on the front-end. The main hook of interest is one that makes all posts look like they live off the root "/" level rather than "/posts/" (where they actually live). This was in order to keep consistency with the URLs as they were in WordPress, so that the new site would have all the same URL as the old site, without the need for 301 redirects. /site/templates/includes/hooks.php /** * This hook modifies the default behavior of the Page::path function (and thereby Page::url) * * The primary purpose is to redefine blog posts to be accessed at a URL off the root level * rather than under /posts/ (where they actually live). * */ wire()->addHookBefore('Page::path', function($event) { $page = $event->object; if($page->template == 'post') { // ensure that pages with template 'post' live off the root rather than '/posts/' $event->replace = true; $event->return = "/$page->name/"; } }); Our /site/templates/_main.php contains the entire markup for the overall template used site wide, from <html> to </html>. It outputs those variables we defined in _init.php in the right places. For example, $body gets output in the <div id='bodycopy'>, $side gets output in the right <aside>, and $browserTitle gets output in the <title> tag. /site/templates/_main.php <?php if($renderMain): ?> <html> <head> <title><?=$browserTitle?></title> </head> <body> <div id='masthead'> // ... </div> <div id='content'> <div id='bodycopy'><?=$body?></div> <aside id='sidebar'><?=$side?></aside> </div> <footer> // ... </footer> </body> </html> <?php endif; ?> We use the rest of the site's template files to simply populate those $body, $side and $browserTitle variables with the contents of the page. As an example, this is an abbreviated version of the /site/templates/post.php template: /site/templates/post.php // functions from /site/templates/includes/render.php $meta = renderMeta($page); $tags = renderTags($page); $authorBox = renderAuthor($page->createdUser); $comments = renderComments($page); $body = " <article class='post post-full'> <header> <h1>$page->title</h1> $meta </header> $page->body $tags $authorBox $comments </article> "; if(count($page->related)) { $side = "<h4>Related Stories</h4>" . renderNav($page->related); } What might also be of interest is the homepage template, as it handles the other part of routing of post URLs since they are living off the root rather than in /posts/. That means the homepage is what is triggering the render of each post: /site/templates/home.php if(strlen($input->urlSegment2)) { // we only accept 1 URL segment here, so 404 if there are any more throw new Wire404Exception(); } else if(strlen($input->urlSegment1)) { // render the blog post named in urlSegment1 $name = $sanitizer->pageName($input->urlSegment1); $post = $pages->get("/posts/")->child("name=$name"); if($post->id) echo $post->render(); else throw new Wire404Exception(); // tell _main.php not to include itself after this $renderMain = false; } else { // regular homepage output $limit = 7; // number of posts to render per page $posts = $pages->find("parent=/posts/, limit=$limit, sort=-date"); $body = renderPosts($posts); } The rest of the site's template files were handled in the same way. Though most were a little simpler than this. Several were simply blank, since the default values populated in _init.php were all that some needed. Front-end development using Foundation 4 The front-end was developed with the Foundation 4 CSS framework. I started with the Foundation blog template and then tweaked the markup and css till I had something that I thought was workable. Then Mike and I sent the _main.php template file back and forth a few times, tweaking and changing it further. There was no formal design process here. It was kind of a photoshop tennis (but in markup and CSS) where we collaborated on it equally, but all under Mike's direction. After a day or two of collaboration, I think we both felt like we had something that was very good for the reader, even if it didn't originate from a design in Photoshop or some other tool like that. I think it helps a lot that Foundation provides a great starting point and lends itself well to fine tuning it the way you want it. I also felt that the mobile-first methodology worked particularly well here. Comments System using Disqus We converted the comments system over to Disqus while the site was still running WordPress. This was done for a few reasons: Disqus comments provide one of the best experiences for the user, in my opinion. They also are platform agnostic, in that we could convert the whole site from WP to PW and not have to change a thing about the comments… no data conversion or importing necessary. Lastly, ProcessWire's built-in comments system is not quite as powerful as WordPress's yet, so I wanted cmscritic.com to get an upgrade in that area rather than anything else, and Disqus is definitely an upgrade from WP's comments. In order to ensure that Disqus could recognize the relations of comment threads to posts, we again made use of that $page->wpid variable that keeps the original WordPress ID, and also relates to the ID used by the Disqus comments. This is only for posts that originated in WordPress, as new posts use a ProcessWire-specific ID.1 point
-
Restrict Repeater Matrix Allows restrictions and limits to be placed on Repeater Matrix fields. Requires ProcessWire >= v3.0.0 and FieldtypeRepeaterMatrix >= v0.0.5. For any matrix type in a Repeater Matrix field you have the option to: Disable settings for items (cannot change matrix type) Prevent drag-sorting of items Prevent cloning of items Prevent toggling of the published state of items Prevent trashing of items Limit the number of items that may be added to the inputfield. When the limit is reached the "Add new" button for the matrix type will be removed and the matrix type will not be available for selection in the "Type" dropdown of other matrix items. Hide the clone button when the limit for a matrix type has been reached. Note that in PW >= 3.0.187 this also means that the copy/paste feature will become unavailable for the matrix type. Please note that restrictions and limits are applied with CSS/JS so should not be considered tamper-proof. Usage Install the Restrict Repeater Matrix module. For each matrix type created in the Repeater Matrix field settings, a "Restrictions" fieldset is added at the bottom of the matrix type settings: For newly added matrix types, the settings must be saved first in order for the Restrictions fieldset to appear. Set restrictions for each matrix type as needed. A limit of zero means that no items of that matrix type may be added to the inputfield. Setting restrictions via a hook Besides setting restrictions in the field settings, you can also apply or modify restrictions by hooking RestrictRepeaterMatrix::checkRestrictions. This allows for more focused restrictions, for example, applying restrictions depending on the template of the page being edited or depending on the role of the user. The checkRestrictions() method receives the following arguments: $field This Repeater Matrix field $inputfield This Repeater Matrix inputfield $matrix_types An array of matrix types for this field. Each key is the matrix type name and the value is the matrix type integer. $page The page that is open in ProcessPageEdit The method returns a multi-dimensional array of matrix types and restrictions for each of those types. An example of a returned array: Example hooks Prevent the matrix type "images_block" from being added to "my_matrix_field" in a page with the "basic-page" template: $wire->addHookAfter('RestrictRepeaterMatrix::checkRestrictions', function(HookEvent $event) { $field = $event->arguments('field'); $page = $event->arguments('page'); $type_restrictions = $event->return; if($field->name === 'my_matrix_field' && $page->template->name === 'basic-page') { $type_restrictions['images_block']['limit'] = 0; } $event->return = $type_restrictions; }); Prevent non-superusers from trashing any Repeater Matrix items in "my_matrix_field": $wire->addHookAfter('RestrictRepeaterMatrix::checkRestrictions', function(HookEvent $event) { $field = $event->arguments('field'); $type_restrictions = $event->return; if($field->name === 'my_matrix_field' && !$this->user->isSuperuser()) { foreach($type_restrictions as $key => $value) { $type_restrictions[$key]['notrash'] = true; } } $event->return = $type_restrictions; }); http://modules.processwire.com/modules/restrict-repeater-matrix/ https://github.com/Toutouwai/RestrictRepeaterMatrix1 point
-
hi everybody, i have a weird problem regarding hooks. there was some unintended results so i started to make it really simple and see what's happening. this is what i came up with: i have this simple hook inside /site/ready.php $this->addHookAfter("Pages::saved", function($event) { $this->log->save('debug', 'saved hook'); }); when i save any page in the admin i get a new log-entry. so far, so good... when i put this inside my home.php template and visit my frontpage: home.php <?php $page->of(false); $page->title = 'set by template'; $page->save(); ...it changes the page title and runs the hook (i get a new log entry). but when i use @adrian s console of tracydebugger with this code: $p = $pages->get(1); $p->of(false); $p->title = 'set by API'; d($p->save()); ...it returns TRUE, it saves the page, but it DOES NOT call the hook. it does not save a new log-entry. I wasted more than an hour now to find out what's going on here. please could anybody of you bring light into that weird problem? in the example it is only a log-entry, but i have several saveReady or added hooks that seemed to work but actually didnt for example it does NOT activate languages for pages that i created from the API (https://processwire.com/talk/topic/4383-how-to-set-language-active-via-api/?do=findComment&comment=147564). that's really critical problems. am i totally misunderstanding anything? thanks for your time!1 point
-
I'm building a testimonials page, and currently have this (one review will always be at the top, the first one, whichever that may be after shuffling): // views/testimonials.php <?php namespace ProcessWire; ?> <?php $arr = $page->testimonials; $arr->shuffle(); $firstTestimonial = $arr->first(); $otherTestimonials = $arr->not("$firstTestimonial"); ?> <div class="jumbotron jumbotron-fluid bg-color"> <div class="container"> <h2><?= $firstTestimonial->title; ?></h2> <p><?= $firstTestimonial->testimonialBody; ?> - <i><?= $firstTestimonial->testimonialReviewee; ?></i></p> </div> </div> <div class='container'> <div class='row py-6'> <?php foreach($otherTestimonials as $testimonial): ?> <div class='col-sm-12 col-md-6 py-3 px-lg-5'> <h2 class='py-3'><?= $testimonial->title; ?></h2> <p><?= $testimonial->testimonialBody; ?></p> <p class="font-weight-bold text-muted">- <i><?= $testimonial->testimonialReviewee; ?></i></p> </div> <?php endforeach; ?> </div> </div> ... the problem I have is from a design perspective. Using a flexbox grid means columns are equal height. Each row contains three columns on desktop. Now, if one column has shorter content than the next one, there is large white space under it because it doesn't fill the column vertically (but the longer ones do). You end up with this: ------------------------------------------------------------------------------ Title Title Title ngjkagas ndjskagdasj njgksgnjsk gdjkgasjk gdjskgbjksa gdasjgkads gndjaskgnjdasnjg ds gbdjskgbdjkab dgasnjk jgfksjgfds jgdksajkgds njdkajda njdasxlhs gf jkdgjsagjdajdasdga fdjakfdbjak fhdjkahf fdbjabfdj fdjsjkakjka ------------------------------------------------------------------------------ Title Title Title ngjkagas ndjskagdasj njgksgnjsk gdjkgasjk gdjskgbjksa gdasjgkads gndjaskgnjdasnjg ds gbdjskgbdjkab dgasnjk jgfksjgfds jgdksajkgds njdkajda njdasxlhs gf jkdgjsagjdajdasdga fdjakfdbjak fhdjkahf fdbjabfdj fdjsjkakjka fnfsjsjs dhhdsjsjds fdnsjkfdjs fdhj dhksd ------------------------------------------------------------------------------ So I thought I'd get the original PageArray, split it into two equal parts, then just loop the two new arrays into two columns. to get this: -------------------------------- -------------------------------- Title Title ngjkagas ndjskagdasj gdjskgbjksa gdasjgkads gndjaskgnjdasnjg ds gbdjskgbdjkab dgasnjk njdkajda njdasxlhs gf jgfksjgfds jgdksajkgds jkdgjsagjdajdasdga fdjakfdbjak fhdjkahf Title fdbjabfdj fdjsjkakjka jfdksahfjka hfdjkasfhjdafalk fnfsjsjs dhhdsjsjds ndjskagjka hdsk hjkdsahjkgd fdnsjkfdjs fdhj dhksd jgdskgksa hgdjskahgjdashgkdas Title Title ngjkagas ndjskagdasj gdjskgbjksa gdasjgkads gndjaskgnjdasnjg ds gbdjskgbdjkab dgasnjk njdkajda njdasxlhs gf jgfksjgfds jgdksajkgds jkdgjsagjdajdasdga fdjakfdbjak fhdjkahf Title fdbjabfdj fdjsjkakjka jfdksahfjka hfdjkasfhjdafalk fnfsjsjs dhhdsjsjds ndjskagjka hdsk hjkdsahjkgd fdnsjkfdjs fdhj dhksd jgdskgksa hgdjskahgjdashgkdas -------------------------------- -------------------------------- So my new code is sketchy and I could do with some help to possibly refactor and also to fill in the gaps where my knowledge fails. Here it is so far: <?php namespace ProcessWire; ?> <?php // get PageArray of all testimonials (which is a repeater: title, testimonialReviewee, testimonialReviewee) $arr = $page->testimonials; // shuffle them $arr->shuffle(); // grab the first one $firstTestimonial = $arr->first(); // grab the others $otherTestimonials = $arr->not("$firstTestimonial"); // get total items in array $numberOfItems = count($otherTestimonials); // return new PageArray (half of $otherTestimonials) $firstHalfArr = $otherTestimonials->slice(0, ($numberOfItems / 2)); // return new PageArray (half + 1) to end $secondHalfArr = $otherTestimonials->slice(($numberOfItems / 2) + 1, $numberOfItems); ?> <div class="jumbotron jumbotron-fluid bg-color"> <div class="container"> <h2><?= $firstTestimonial->title; ?></h2> <p><?= $firstTestimonial->testimonialBody; ?> - <i><?= $firstTestimonial->testimonialReviewee; ?></i></p> </div> </div> <div class='container'> <div class='row'> <div class='col-6'> <?php foreach($firstHalfArr as $testimonial): ?> <h2 class='py-3'><?= $testimonial->title; ?></h2> <p><?= $testimonial->testimonialBody; ?></p> <p class="font-weight-bold text-muted">- <i><?= $testimonial->testimonialReviewee; ?></i></p> <?php endforeach; ?> </div> <div class='col-6'> <?php foreach($secondHalfArr as $testimonial): ?> <h2 class='py-3'><?= $testimonial->title; ?></h2> <p><?= $testimonial->testimonialBody; ?></p> <p class="font-weight-bold text-muted">- <i><?= $testimonial->testimonialReviewee; ?></i></p> <?php endforeach; ?> </div> </div> </div> Sure you guys don't need the comments but it helps me as I go along to build the logic. The obvious problem is what happens when the PageArray contains an odd number of items. Is there a round method or something? If I round incorrectly though, I think maybe one testimonial item would be missed i.e. [0,1,2,3] and [5,6,7,8]. Anyway, the problem I'm having right now in PHP and JS as I learn is thinking like a programmer. I'm getting better at reading technical docs and using methods from instructions etc. but the thinking like a programmer bit (logic included) eludes me somewhat. I'll get there in the end. Any advice is appreciated as always. Thanks. (p.s. I am aware of CSS3 column-count)1 point
-
@adrian do you think you can have a look why the hooks inside ready.php are not applied when executed from the tracy console? i had an issue again today... i wanted to test a simple property hook and got an error. i think that's quite a big issue because imho the panel code should just execute as if it were executed inside a template or module. and i guess testing hooks, functions, creating pages via the console etc. is a VERY common usecase for tracy-users... // get group of given fbrole $wire->addHookProperty('Page::group', function($event) { d('test'); $page = $event->object; if($page->template != 'fbrole') return; $event->return = $this->pages->get(1634); }); log (first from ready.php, then from init.php):1 point
-
I'm having a bit of trouble understanding, but you can automate pretty much anything in PW - nothing has be done manually. Suppose you go with a Page Reference field for your options (which is usually the most flexible approach) - you can create new options (i.e. pages) on-the-fly as you import your data if you need to. But from what you say in the first post, it sounds like you already know the the options ahead of time and that is how you are able to set up the Table field with those options on the Home page. Instead of the Table field, create one page per option under some special branch of the page tree that is dedicated to that purpose. Set up a "Homepage Listung" Page Reference field that uses those pages as options. When you import the data you don't have to know the ID of the option (page) - you can find the option by title (e.g. "Bestätigt") or value (e.g. "JA1") and then set that option (page) for the "Homepage Listung" field.1 point
-
Aha, yes! Thank you! I keep forgetting that we have unformatted values too. I updated both methods in my original post. Cheers,1 point
-
Hi Ryan, This will be great and handy in many cases I guess, thank you Some questions that come to my mind: Will it be possible to choose a subset to import? That could be great for doing backups and having granular control over what to restore. Not sure about this, that's why I'm asking: what do you think about adding the possibility to include modules to the export? It could be taken as some kind of "site profiles", but much more flexible. For example you could build a master site profile, install a new sandbox site, import your profile and during the import you could choose which pages and which modules to import. Hmm.. thinking about it it would also be nice to have the same feature for templates as a next step. Maybe that goes too far, but maybe that's already your plan for the long run? Would be interested to hearing your opinion Have a nice weekend everybody!1 point
-
Hi @szabesz I think that if import/export functionality will be possible from API side, we will be able to easily build custom process modules with some predefined patterns for import or export. Hope that multilanguage support will be introduced as multilanguage type of setup currently is default for me ))1 point
-
Thanks I was thinking of a way avoid repeating that block twice when only the array differs between the two. Not 100% on what these lines do though, using a key=>value instead of the way I did it: What's the value of $index here for each loop? This code confuses me somewhat with the div placement. Nice and short though, I like it! I also extended it now to include a page ref field in the repeater: ...so you can choose which site the review came from (with the site title and URL stored in a different template)... ...works quite well, and having the reviews out of the standard 3 across grid looks so much better to me. Glad to be back using PW. Paid job this one.1 point
-
Nice! Do you have to change your module version from 1.2.1 to 1.2.2 to appear on ProcessWire Upgrades?1 point
-
1 point
-
This will make a great update, thanks! Is multilanguage support planned?1 point
-
1 point
-
@Robin S Thanks for your work! I will gladly merge a pull request to make this module PW3 compatible1 point
-
Maybe related: https://github.com/processwire/processwire-issues/issues/319 There seems to be some mayor issue with setAndSave().1 point
-
thank you adrian, i can confirm this behaviour! it turned out that my problem was a combination of two 1) like you mentioned the hook does not get called when called from the tracy console - that's weird and i think that's somewhat critical as it could lead to problems (not doing things that you would expect, doing things that you would not expect; and hard to see sometimes!). 2) even in the init my language hook didn't work. turned out that this works: // set all languages active automatically $wire->addHookAfter('Pages::added', function($event) { $page = $event->arguments(0); foreach ($this->wire->languages as $lang) $page->set("status$lang", 1); $page->save(); }); while this does NOT: // set all languages active automatically $wire->addHookAfter('Pages::added', function($event) { $page = $event->arguments(0); foreach ($this->wire->languages as $lang) $page->setAndSave("status$lang", 1); }); no idea what could be the reason for this #2 is somewhat offtopic. but what do you think about the tracy hook problem? do you think this problem is more related to tracy? my init.php bd('init.php'); // test tracy $wire->addHookAfter('Pages::saveReady', function($event) { $page = $event->arguments(0); bd('saveReady in init.php'); bd($page->id); }); my ready.php bd('ready.php'); // test tracy $wire->addHookAfter('Pages::saveReady', function($event) { $page = $event->arguments(0); bd('saveReady in ready.php'); bd($page->id); }); after loading: after executing the code inside the console:1 point
-
I thought about mediumtext but don't know what "unwanted" effect it may have on other PW functions. I went the even more simple way and import now to a single import page, and then move the imported pages with your great AdminActions to their destination parents. This way I don't have to configure all parent pages with my fieldpairings. BTW... thank you very much for AdminActions. Without Move and Search and Replace this project wouldn't be possible.1 point
-
Thanks for letting me know. I have updated the module to set a minimum version requirement for FieldtypeRepeaterMatrix.1 point
-
The latest update of the module was on 1 April 2014. My above simple request to add a missing icon hasn't fulfilled yet! Maybe @Wanze isn't available. I'm using the module on both PW2 & PW3 with https and it's working fine. You can install a module with 3 methods: 1. Add Module From Directory 2. Add Module From URL 3. Add Module From Upload Go to Admin > Modules and click on the tab "New" to check all the methods.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
-
If you have lots of repeater items, this will be more efficient: $pages->get("/testimonials/)->testimonials_repeater->find("limit=4, sort=random");1 point