Search the Community
Showing results for 'runtime'.
-
Hello! I'm trying to add an additional field "Categories". Created field "shopcats" in Admin> Setup> Fields. Created 2 templates (shopcat.php and shopcats.php), similarity of templates (architect.php and architects.php). In menu i created page "Categories of stores" with template shopcats.php. And also created a category pages with template shopcat.php (Clothes, Furniture, Household appliances, ...). In template "skyscraper" I added a field "shopcats". As a result, displays only the category ID. How to display the category name? How to add a search by category in a search engine? <?php /*************************************************************************************** * SHARED SKYSCRAPER FUNCTIONS * * The following functions find and render skyscrapers and are defined here so that * they can be used by multiple template files. * */ /** * Returns an array of valid skyscraper sort properties * * The keys for the array are the field names * The values for the array are the printable labels * * @return array * */ function getValidSkyscraperSorts() { return array( // field => label 'images' => 'Images', 'title' => 'Title', 'parent' => 'City', 'shopcats' => 'Category', 'height' => 'Height', 'floors' => 'Floors', 'year' => 'Year', ); } /** * Find Skyscraper pages using criteria from the given selector string. * * Serves as a front-end to $pages->find(), filling in some of the redundant * functionality used by multiple template files. * * @param string $selector * @return PageArray * */ function findSkyscrapers($selector) { $validSorts = getValidSkyscraperSorts(); // check if there is a valid 'sort' var in the GET variables $sort = wire('sanitizer')->name(wire('input')->get->sort); // if no valid sort, then use 'title' as a default if(!$sort || !isset($validSorts[ltrim($sort, '-')])) $sort = 'title'; // whitelist the sort value so that it is retained in pagination if($sort != 'title') wire('input')->whitelist('sort', $sort); // expand on the provided selector to limit it to 10 sorted skyscrapers $selector = "template=skyscraper, limit=10, " . trim($selector, ", "); // check if there are any keyword searches in the selector by looking for the presence of // ~= operator. if present, then omit the 'sort' param, since ProcessWire sorts by // relevance when no sort specified. if(strpos($selector, "~=") === false) $selector .= ", sort=$sort"; // now call upon ProcessWire to find the skyscrapers for us $skyscrapers = wire('pages')->find($selector); // save skyscrapers for possible display in a map mapSkyscrapers($skyscrapers); // set this runtime variable to the page so we can show the user what selector was used // to find the skyscrapers. the renderSkyscraperList function looks for it. wire('page')->set('skyscraper_selector', $selector); return $skyscrapers; } /** * Serves as a place to store and retrieve loaded skyscrapers that will be displayed in a google map. * * To add skyscrapers, pass in a PageArray of them. * To retrieve skyscreapers, pass in nothing and retrieve the returned value. * * @param null|PageArray $items Skyscraper pages to store * @return PageArray All Skyscraper pages stored so far * */ function mapSkyscrapers($items = null) { static $skyscrapers = null; if(is_null($skyscrapers)) $skyscrapers = new PageArray(); if(!is_null($items) && $items instanceof PageArray) $skyscrapers->add($items); return $skyscrapers; } /** * Render the <thead> portion of a Skyscraper list table * * @internal * */ function renderSkyscraperListHeader($showCity = true) { // get the 'sort' property, if it's been used $sort = wire('input')->whitelist('sort'); if(!$sort) $sort = 'title'; // query string that will be used to retain GET variables in table header sort links $queryString = ''; // make a query string from variables that have been stuffed into $input->whitelist // to use with the table header sort links foreach(wire('input')->whitelist as $key => $value) { if($key == 'sort') continue; $queryString .= "&$key=" . urlencode($value); } $out = "\n\t<thead>\n\t<tr>"; // build the table header with sort links foreach(getValidSkyscraperSorts() as $key => $value) { // don't show a city header if we're already in a city if($value == 'City' && !$showCity) continue; // check if they want to reverse the sort if($key == $sort) { $key = "-$sort"; $value = "<strong>$value »</strong>"; } else if("-$key" == $sort) { $key = ltrim($sort, '-'); $value = "<strong>$value «</strong>"; } $out .= "<th><a href='./?sort=$key$queryString'>$value</a></th>"; } $out .= "\n\t</tr>\n\t</thead>"; return $out; } /** * Render a table/list of the given $skyscrapers * * @param PageArray $skyscrapers Skyscrapers to render * @param bool $showHeader Should the <thead> with sort links be displayed? default=true * @return string The rendered markup * */ function renderSkyscraperList(PageArray $skyscrapers, $showHeader = true) { if(!count($skyscrapers)) return "<h3>No skyscrapers found.</h3>"; // we don't show the city if they are already on a city page $showCity = wire('page')->template != 'city'; // get the markup for any pagination links // note: these are provided by the MarkupPagerNav and MarkupPageArray modules, // modules that are already installed by default. $pagerLinks = $showHeader ? $skyscrapers->renderPager() : ''; $out = $pagerLinks . "\n<table class='list_skyscrapers'>"; if($showHeader) $out .= renderSkyscraperListHeader($showCity); $out .= "\n\t<tbody>"; // build the table body foreach($skyscrapers as $skyscraper) { $out .= renderSkyscraperItem($skyscraper, $showCity); } $out .= "\n\t</tbody>" . "\n</table>" . $pagerLinks; // if we stuffed a variable called skyscraper_selector into the page, // tell them what the selector was, for demonstration purposes $selector = wire('page')->skyscraper_selector; if($selector) { $out .= "\n\n<p class='selector_note'>The selector used to find the pages shown above is:<br />" . "<code>" . makePrettySelector($selector) . "</code></p>\n"; } return $out; } /** * Generate the markup for a single skyscraper item in a skyscraper list * * This is primarily used by the render() method. * * @param Page $skyscraper The Skyscraper to render * @param bool $showCity Should the city name be shown? * @return string * */ function renderSkyscraperItem(Page $skyscraper, $showCity = true) { // we keep track of the number of items we've already rendered // so that we can alternate placeholder images from row to row static $cnt = 0; $cnt++; // make a thumbnail if the first skyscraper image if(count($skyscraper->images)) { // our thumbnail is 100px wide with proportional height $thumb = $skyscraper->images->first()->width(100); $img = "<img src='{$thumb->url}' alt='{$skyscraper->title} photo' />"; } else { // skyscraper has no images, so we'll show a placeholder instead $class = 'placeholder'; if($cnt % 2 == 0) $class .= " placeholder2"; // for alternate version of placeholder image $img = "<span class='$class'>Image Not Available</span>"; } // make a truncated version of the bodycopy with max 500 characters if($skyscraper->body) { $summary = strip_tags($skyscraper->body); if(strlen($summary) > 500) { $summary = substr($summary, 0, 500); // display no more than 500 chars $summary = substr($summary, 0, strrpos($summary, ". ")+1); // and truncate to last sentence } $summary = trim($summary); } else $summary = ''; // what we show when a field is blank $na = "<span class='na'>N/A</span>"; // start a table row for the output markup $out = "\n\t<tr class='skyscraper_details'>" . "\n\t\t<td rowspan='2' class='skyscraper_image'><a href='{$skyscraper->url}'>$img</a></td>" . "\n\t\t<td><a href='{$skyscraper->url}'>{$skyscraper->title}</a></td>"; if($showCity) { // display the city's abbreviation, or title if there is no abbreviation $out .= "\n\t\t<td>" . $skyscraper->parent->get("abbreviation|title") . "</td>" . "\n\t\t<td>" . $skyscraper->get("abbreviation|shopcats") . "</td>" ; } // finish the table row of output markup $out .= "\n\t\t<td>" . ($skyscraper->height ? number_format($skyscraper->height) . " ft." : $na) . "</td>" . "\n\t\t<td>" . ($skyscraper->floors ? $skyscraper->floors : $na) . "</td>" . "\n\t\t<td>" . ($skyscraper->year ? $skyscraper->year : $na) . "</td>" . "\n\t</tr>" . "\n\t<tr class='skyscraper_summary'>" . "\n\t\t<td colspan='6'><p>$summary</p></td>" . "\n\t</tr>"; return $out; } /** * Make the selector better for display readability * * Since we're displaying the selector to screen for demonstration purposes, this method optimizes the * selector is the most readable fashion and removes any parts that aren't necessary * * This is not something you would bother with on a site that wasn't demonstrating a CMS. * * @param string $selector * @return string * */ function makePrettySelector($selector) { if(preg_match('/(architects|parent)=(\d+)/', $selector, $matches)) { if($page = wire('pages')->get($matches[2])) $selector = str_replace($matches[0], "$matches[1]={$page->path}", $selector); if($matches[1] == 'parent') $selector = str_replace("template=skyscraper, ", "", $selector); // template not necessary here } return $selector; }
-
I have found myself dealing with similiar problem. In my case it was because of ProcessWire Config module installed. It seems like it replaces config options on runtime (does not add them). So If you use that module you have to add HTTP hosts to the whitelist via the module.
- 13 replies
-
- Unrecognized HTTP host:
- error
-
(and 1 more)
Tagged with:
-
saving user fields with added properties
LostKobrakai replied to bmacnaughton's topic in Getting Started
I think you didn't add those fields to the user template? If so you can still add variables like above, but these are runtime only and won't be save, as there are no columns in the database for these fields. You can add fields to the user template like you'd do it with every other template. It's just hidden by default so you need to enable "show system templates" on top of the templates-list. -
how to styling of the output content of pagnation
Soma replied to adrianmak's topic in General Support
This helper render method on PageArray's is usually meant for a convenient tool when developing like scaffolding (although you can't CRUD). Although it is there to use if you want, I also always use the renderPager() method. If you want to output a summary but haven't got a summary field $page->summary. Since you can't modify the module, one could add the property to page object via property hook. Which means to add a property on runtime. You can see an example in the HelloWorld.module. Something like this will give you a $page->summary $pa = $pages->find("template=basic-page, limit=4"); wire()->addHookProperty("Page::summary", null, function($event){ $page = $event->object; $event->return = $page->headline; // return something for "summary" }); $content .= $pa->render(array('itemMarkup'=>"\n\t<li><a href='{url}'>{title}<br><small>{summary}</small></a></li>")); But what's wrong with creating your own foreach? $pa = $pages->find("template=basic-page, limit=4"); if($pa->count) { $list = ""; foreach($pa as $p){ $summary = limitWords($page->body); // your function to limit words maybe $list .= "<li><a href='{$page->url}'>{$page->title}<br><small>{$summary}</small></a></li>"; } $content .= "<ul>$list</ul>"; $content .= $pa->renderPager(); } else { $content .= "Nothing found"; } -
Actually they can place the images anywhere they want to in the text. They aren't limited to just placing it at the top. Of course, when you find where you want to place the image in the text, then at that point you have to specify whether its an image that should be left aligned, right aligned, or centered. On the front-end, you can choose how you want to handle that. While most of the time the text floats around it, sometimes I'll take an alignment and make it pull into a blank left/right column. Images for predefined placement in a layout shouldn't go in the text at all. You'd want to have a dedicated field or tag for those images. If there are more than a couple predefined placements, I might use tags so that an image with the tag "hero" automatically goes to your dedicated hero spot, etc. I usually treat galleries as predefined placements (like appearing above or below the main content). Rarely does the need arise where galleries need to be part of the actual copy, but others may have a different need/experience, so I think that's a good example. While I like having a consistent placement for a major feature like that, it's really more about having markup that is generated dynamically when the page is viewed. But if you wanted the ability to place galleries of images in-between blocks of copy, then I agree that's a good use case for a block editor. Whether it's worth the compromise would depend on the need I suppose. Perhaps that's a great case for a hybrid editor that is primarily RTE but provides certain blocks you can work with. CKEditor does actually provide something called Widgets that allow insertion of more complex predefined markup elements, but I don't think it's quite there enough to where I'd want to use it for a gallery. That's because it's something I'd want to generate on the front-end rather than directly in the RTE-generated markup. I don't like RTE's generating anything other than basic markup because it's just not as portable... once you start using CKE widgets, you can't really switch to another RTE without losing those widgets. Probably what would be ideal is CKEditor with a block-editor style select input at the bottom that lets you add certain types of elements like galleries, paginations, or other things (but not simple markup elements like headlines), and then lets you continue the text content underneath in another CKE instance. That would let the RTE do what it's good at, and let blocks handle the things that would benefit from having their markup generated at runtime (like a gallery).
-
If the field your settings a value for is not reserved or found in the templates fields it's just added to the object as runtime property. $page->notAAssingedField = "Hello"; echo $page->notAAssingedField; // outputs: Hello If you'd need more specific additions you could also use hooks to extend the page object or even make a own object, extending the existing page object. This new object can then be assinged to specific templates in the backend. Edit: As you've said you'll export it to JSON: A page object has lots of properties, which I don't know if you need all of them. So I would suggest taking a look at the json so it's not bloated with stuff you're not using, especially if it's for something like ajax.
-
I moved a site from my local machine to a staging server over the weekend. The site (front end) displays fine but the backend gives error of I checked the files on the site under /wire/modules/System/SystemNotifications/ and can confirm SystemsNotifications.module exists. Opening this file up and looking at line 346 ... // convert runtime Notices to Notifications and bundle into array if($this->placement == SystemNotificationsConfig::placementCombined) { The SystemNotificationsConfig mentioned above is a PHP file which also exists and has the same permissions as the working version on my test site.
- 1 reply
-
- Notifcations
- Errors
-
(and 1 more)
Tagged with:
-
MarkupSEO - The all-in-one SEO solution for ProcessWire.
Nico Knoll replied to Nico Knoll's topic in Modules/Plugins
Version 0.7.0: Hey, I added the https option you asked for: $config->https will be set to true in runtime I guess if the template is set to use https, too. So all of the fallbacks should be covered. And I added the fix by @peterfoeng. -
I think it's a good idea too. ProcessWire currently has one of the best multi language support I've seen, but there is room for improvement that I'd like to see too. For example: I've submit a feature request/proposition to support UTF8MB4 in the database by default (would add support for emoticons). There is already some support for this, but by default the SQL loaded to create the basic pages needs to be changed manually. One other thing that might be nice, is instead of letting language name be free-form, we could stick to BCP47 (validator — registry). As an added bonus, we could package language packs for modules or else in a /lang/xx[-xx] format, instead of having to constantly install them manually. It would also make it possible for PW to set setlocale() by itself, without having to add it manually. Default could have a way to set an alias, so that at runtime the language functions would recognize "en" and "default" as the same, for example. This would also be necessary for the second proposition. What are your thoughts on this guys/gals? I think Ryan would probably be glad to receive a patch for this if it's of good enough quality, this could be a community effort. Should we open a new topic to discuss all that?
-
Okay, I am not in a position to test anything at the moment as I don't have the right environment, but I have used the URL rewrite module to do a conversion and the only problem seems to be on line 72 which seems to refer to: # If any conditions above match, isssue a 403 forbidden RewriteRule ^.*$ - [F,L] Anyone know how this effects things? <rewrite> <!--This directive was not converted because it is not supported by IIS: RewriteBase /.--> <!--This directive was not converted because it is not supported by IIS: RewriteBase /pw/.--> <!--This directive was not converted because it is not supported by IIS: RewriteBase /~user/.--> <rules> <!--#################################################################################################--> <!--# START PROCESSWIRE HTACCESS DIRECTIVES--> <!--# @version 2.5--> <!--# @indexVersion 250--> <!--#################################################################################################--> <!--# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> <!--# Don't show directory indexes, but do follow symbolic links --> <!--# 500 NOTE: Some cloud hosting companies don't allow +FollowSymLinks. --> <!--# Uncomment +SymLinksifOwnerMatch and comment +FollowSymLinks if you have 500 errors. --> <!--# If that doesn't resolve the error, then set it back to +FollowSymLinks. --> <!--# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> <!--# Options +FollowSymLinks--> <!--# Options +SymLinksifOwnerMatch--> <!--# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> <!--# Let ProcessWire handle 404s--> <!--# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> <!--# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> <!--# Handle request for missing favicon.ico/robots.txt files (no ending quote for Apache 1.3)--> <!--# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> <!--# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> <!--# Protect from XSS with Apache headers--> <!--# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> <!--# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> <!--# Protect ProcessWire system files (part 1A) for Apache versions older than 2.4:--> <!--# APACHE 2.4+ NOTE: Comment out this section and uncomment second 1B below it.--> <!--# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> <!--# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> <!--# Protect ProcessWire system files (part 1B) for Apache versions 2.4 and newer: --> <!--# APACHE 2.4+ NOTE: Uncomment this section and remove or comment out section 1A above. --> <!--# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> <!--# <FilesMatch "\.(inc|info|info\.json|module|sh|sql)$|^(\..*)$">--> <!--# Require all denied --> <!--# </FilesMatch>--> <!--# <Files .htaccess>--> <!--# Require all denied--> <!--# </Files>--> <!--# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> <!--# Override a few PHP settings that can't be changed at runtime (not required)--> <!--# 500 NOTE: Try commenting out this entire section below if getting Apache 500 errors.--> <!--# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> <!--# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> <!--# Set default directory index files--> <!--# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> <!--# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> <!--# ProcessWire requires mod_rewrite--> <!--# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - --> <rule name="Imported Rule 1"> <match url=""(^|/)\."" ignoreCase="false" /> <action type="CustomResponse" statusCode="403" statusReason="Forbidden" statusDescription="Forbidden" /> </rule> <rule name="Imported Rule 2" stopProcessing="true"> <match url="^" ignoreCase="false" /> <conditions> <add input="{HTTP_HOST}" pattern="^www\." negate="true" /> </conditions> <action type="Redirect" redirectType="Permanent" url="http://www.{HTTP_HOST}{URL}" /> </rule> <rule name="Imported Rule 3" stopProcessing="true"> <match url="^(.*)$" ignoreCase="false" /> <conditions> <add input="{URL}" pattern=""[^-_.a-zA-Z0-9/~]"" ignoreCase="false" /> <add input="{REQUEST_FILENAME}" matchType="IsFile" ignoreCase="false" negate="true" /> <add input="{REQUEST_FILENAME}" matchType="IsDirectory" ignoreCase="false" negate="true" /> </conditions> <action type="Rewrite" url="index.php?it=/http404/" appendQueryString="true" /> </rule> <!--This rule was not converted because only some of the conditions are using the OR flag.--> <rule name="Imported Rule 5" stopProcessing="true"> <match url="^(.*)$" ignoreCase="false" /> <conditions> <add input="{URL}" pattern=""^/~?[-_.a-zA-Z0-9/]*$"" ignoreCase="false" /> <add input="{REQUEST_FILENAME}" matchType="IsFile" ignoreCase="false" negate="true" /> <add input="{REQUEST_FILENAME}" matchType="IsDirectory" ignoreCase="false" negate="true" /> <add input="{REQUEST_FILENAME}" pattern="(favicon\.ico|robots\.txt)" ignoreCase="false" negate="true" /> <add input="{REQUEST_FILENAME}" pattern="\.(jpg|jpeg|gif|png|ico)$" negate="true" /> <add input="{REQUEST_FILENAME}" pattern="(^|/)site/assets/" ignoreCase="false" negate="true" /> </conditions> <action type="Rewrite" url="index.php?it={R:1}" appendQueryString="true" /> </rule> <rule name="Imported Rule 6" stopProcessing="true"> <match url="^(.*)$" ignoreCase="false" /> <action type="Rewrite" url="/index.php?it={R:1}" appendQueryString="true" /> </rule> </rules> </rewrite> a
-
New to Hooks, trying to wrap my head around the syntax
creativejay replied to creativejay's topic in Getting Started
"Swatches" is the correct page title that's associated with that field. I swear I had $p->blog_categories->title == 'Swatches' a couple revisions ago (then I changed it to $p->blog_categories == '1040' and must have changed it back without adding the fieldname back). Anyhow, it's working now! Thank you EVERYONE! I would be proud, but you guys seriously did most of the work. I really appreciate it! Below is the final content of the module file (which is installed ). I'm posting the entire thing in case someone else is in need of help with the entire context situation. I'll mark this one as solved though really it's the culmination of the entire thread. Thanks, everyone, for bearing with me. <?php /** * ProcessWire 'Rename Swatches' module by forum user creativejay * * Checks to see if a page uses the template "blog-post" and has a $p->blog_categories->title value of "Swatches" then redefines the value of $p->title and $p->name * * * ProcessWire 2.x * Copyright (C) 2014 by Ryan Cramer * Licensed under GNU/GPL v2, see LICENSE.TXT * * http://processwire.com * */ class RenameSwatches extends WireData implements Module { /** * getModuleInfo is a module required by all modules to tell ProcessWire about them * * @return array * */ public static function getModuleInfo() { return array( // The module's title, typically a little more descriptive than the class name 'title' => 'Rename Swatches', // version number 'version' => 4, // summary is brief description of what this module is 'summary' => 'Checks to see if a page uses the template blog-post and has a blog_categories->title value of Swatches then redefines the value of title and name', // Optional URL to more information about the module 'href' => 'https://processwire.com/talk/topic/8863-new-to-hooks-trying-to-wrap-my-head-around-the-syntax/', // singular=true: indicates that only one instance of the module is allowed. // This is usually what you want for modules that attach hooks. 'singular' => true, // autoload=true:indicates the module should be started with ProcessWire. // This is necessary for any modules that attach runtime hooks, otherwise those // hooks won't get attached unless some other code calls the module on it's own. // Note that autoload modules are almost always also 'singular' (seen above). 'autoload' => true, // Optional font-awesome icon name, minus the 'fa-' part 'icon' => 'eraser', ); } public function init() { $this->addHookAfter('Pages::saveReady', $this, 'renameBeforeSave'); } public function renameBeforeSave(HookEvent $event) { $p = $event->arguments[0]; if($p->template->name === "blog-post" && $p->blog_categories->title == 'Swatches'){ $concatenatedName = $p->createdUser->name; $concatenatedName .= '-' . $p->blog_brand->title; $concatenatedName .= '-' . $p->blog_name; $concatenatedTitle = $p->blog_brand->title; $concatenatedTitle .= ' ' . $p->blog_name; $p->title = $concatenatedTitle; $p->name = $this->sanitizer->pageName($concatenatedName, true); $this->message("Changed title according to the new module."); } } } -
New to Hooks, trying to wrap my head around the syntax
adrian replied to creativejay's topic in Getting Started
Try this: <?php /** * ProcessWire 'Rename Page' module by forum user creativejay * * Checks to see if a page uses the template "blog-post" and has a $p->blog_categories value of "Swatch" then redefines the value of $p->title and $p->name * * * ProcessWire 2.x * Copyright (C) 2014 by Ryan Cramer * Licensed under GNU/GPL v2, see LICENSE.TXT * * http://processwire.com * */ class RenamePage extends WireData implements Module { /** * getModuleInfo is a module required by all modules to tell ProcessWire about them * * @return array * */ public static function getModuleInfo() { return array( // The module's title, typically a little more descriptive than the class name 'title' => 'Rename Page', // version number 'version' => 3, // summary is brief description of what this module is 'summary' => 'Checks to see if a page uses the template blog-post and has a blog_categories value of Swatch then redefines the value of title and name', // Optional URL to more information about the module 'href' => 'https://processwire.com/talk/topic/8863-new-to-hooks-trying-to-wrap-my-head-around-the-syntax/', // singular=true: indicates that only one instance of the module is allowed. // This is usually what you want for modules that attach hooks. 'singular' => true, // autoload=true:indicates the module should be started with ProcessWire. // This is necessary for any modules that attach runtime hooks, otherwise those // hooks won't get attached unless some other code calls the module on it's own. // Note that autoload modules are almost always also 'singular' (seen above). 'autoload' => true, // Optional font-awesome icon name, minus the 'fa-' part 'icon' => 'eraser', ); } public function init() { $this->addHookAfter('Pages::saveReady', $this, 'renameBeforeSave'); } public function renameBeforeSave(HookEvent $event) { $p = $event->arguments[0]; if($p->template->name === "blog_post" && $p->blog_categories == "Swatches"){ $concatenatedName = $p->blog_date; $concatenatedName .= '-' . $p->createdUser; $concatenatedName .= '-' . $p->blog_brand; $concatenatedName .= '-' . $p->blog_name; $concatenatedTitle = $p->blog_brand; $concatenatedTitle .= ' ' . $p->blog_name; $p->title = $concatenatedTitle; $p->name = $sanitizer->pageName($concatenatedName, true); } } } -
New to Hooks, trying to wrap my head around the syntax
creativejay replied to creativejay's topic in Getting Started
@adrian here's the module I made from your code. I'm getting a unexpected T_VARIABLE, expecting T_FUNCTION (line 55) - that would be on "public function renameBeforeSave(HookEvent $event) {" <?php /** * ProcessWire 'Rename Page' module by forum user creativejay * * Checks to see if a page uses the template "blog-post" and has a $page->blog_categories value of "Swatch" then redefines the value of $page->title and $page->name * * * ProcessWire 2.x * Copyright (C) 2014 by Ryan Cramer * Licensed under GNU/GPL v2, see LICENSE.TXT * * http://processwire.com * */ class RenamePage extends WireData implements Module { /** * getModuleInfo is a module required by all modules to tell ProcessWire about them * * @return array * */ public static function getModuleInfo() { return array( // The module's title, typically a little more descriptive than the class name 'title' => 'Rename Page', // version number 'version' => 3, // summary is brief description of what this module is 'summary' => 'Checks to see if a page uses the template blog-post and has a blog_categories value of Swatch then redefines the value of title and name', // Optional URL to more information about the module 'href' => 'https://processwire.com/talk/topic/8863-new-to-hooks-trying-to-wrap-my-head-around-the-syntax/', // singular=true: indicates that only one instance of the module is allowed. // This is usually what you want for modules that attach hooks. 'singular' => true, // autoload=true: indicates the module should be started with ProcessWire. // This is necessary for any modules that attach runtime hooks, otherwise those // hooks won't get attached unless some other code calls the module on it's own. // Note that autoload modules are almost always also 'singular' (seen above). 'autoload' => true, // Optional font-awesome icon name, minus the 'fa-' part 'icon' => 'eraser', ); } $this->addHookAfter('Pages::saveReady', $this, 'renameBeforeSave'); public function renameBeforeSave(HookEvent $event) { if($page->template->name === "blog_post" && $page->blog_categories == "Swatches"){ $concatenatedName = $page->blog_date; $concatenatedName .= '-' . $page->createdUser; $concatenatedName .= '-' . $page->blog_brand; $concatenatedName .= '-' . $page->blog_name; $concatenatedTitle = $page->blog_brand; $concatenatedTitle .= ' ' . $page->blog_name; $page->title = $concatenatedTitle; $page->name = $sanitizer->pageName($concatenatedName); } $event->arguments[0] = $page; } Can you spot what I've done wrong? -
I think kongondo is close You can build top level entries using a PageArray. Only top level items are supported, once MSN got a PageArray it will recursively parse the tree from those top level entries. You could do this $items = new PageArray(); // add pages to PageArray $home = $pages->get("/"); $items->add($home); $events = $pages->get("/events/"); $items->add($events); $photos = $pages->get("/photos/"); $items->add($photos); $options = array( "selector_field" => "nav_selector" ); $nav->render($options, null, $items); but now make use of the "selector_field" option https://github.com/somatonic/MarkupSimpleNavigation#added-support-for-nav_selector-propertyfield-and-selector_leveln-new-in-121 default it is "nav_selector". When MSN finds a page with this property (either field or added at runtime) it will take that value as a selector to find/filter the children (if it has any). So if you want to have a custom selector on the "/events/" page it would look like this: $items = new PageArray(); // add pages to PageArray $home = $pages->get("/"); $items->add($home); $events = $pages->get("/events/"); $events->nav_selector = "limit=5, sort=-eventdatefield"; // define a selector $items->add($events); $photos = $pages->get("/photos/"); $items->add($photos); $options = array( "selector_field" => "nav_selector" ); $nav->render($options, null, $items); Now adding a additional item at the end is something I would add using JS (jquery). And also let the "Events" top menu entry link to the full list anyway. To get something to target the JS script you could use "inner_tpl" with a placeholder to add name or id to ul's and add that to the options array: $options = array( 'selector_field' => 'nav_selector', 'outer_tpl' => '<ul id="nav">||</ul>', 'inner_tpl' => '<ul id="{name}">||</ul>', ); Then do something like this with JS $("#nav ul#events").append($("<li><a href='/events/'>more</a></li>"));
-
If you'll put the ajax stuff in a template you can use this: http://cheatsheet.processwire.com/config/runtime-configuration/config-ajax/ Otherwise have a look at this: http://processwire.com/api/include/ The recommended way would be the first one.
-
Not tested and quickly put together here based on the HelloWorld.module demo. This should give you an starting point. Hook before the page saves (I think this is possible?), then write the other field based on the source_url field. <?php /** * ProcessWire 'Hello world' demonstration module * * Demonstrates the Module interface and how to add hooks. * * See README file for further links regarding module development. * * ProcessWire 2.x * Copyright (C) 2014 by Ryan Cramer * Licensed under GNU/GPL v2, see LICENSE.TXT * * http://processwire.com * */ class Helloworld extends WireData implements Module { /** * getModuleInfo is a module required by all modules to tell ProcessWire about them * * @return array * */ public static function getModuleInfo() { return array( // The module'ss title, typically a little more descriptive than the class name 'title' => Rewrite field after save', // version number 'version' => 1, // summary is brief description of what this module is 'summary' => 'An example module used for demonstration purposes. See the /site/modules/Helloworld.module file for details.', // Optional URL to more information about the module 'href' => 'http://processwire.com', // singular=true: indicates that only one instance of the module is allowed. // This is usually what you want for modules that attach hooks. 'singular' => true, // autoload=true: indicates the module should be started with ProcessWire. // This is necessary for any modules that attach runtime hooks, otherwise those // hooks won't get attached unless some other code calls the module on it's own. // Note that autoload modules are almost always also 'singular' (seen above). 'autoload' => true, // Optional font-awesome icon name, minus the 'fa-' part 'icon' => 'smile-o', ); } /** * Initialize the module * * ProcessWire calls this when the module is loaded. For 'autoload' modules, this will be called * when ProcessWire's API is ready. As a result, this is a good place to attach hooks. * */ public function init() { // add a hook before the $pages->save, to issue a notice every time a page is saved $this->pages->addHookBefore('save', $this, 'saveShortUrl'); } /** * Save as another field. * */ public function saveShortUrl($event) { $page = $event->arguments[0]; //#todo Rename to your field names. $page->domain = parse_url($page->source_url,PHP_URL_HOST); //#todo Maybe some more error handling. $this->message("Save the domain {$page->domain}."); } } But maybe the experts on this topic hand help you with any further questions
-
Yep, I agree with Joss here. If you wanted to manipulate the value at runtime, here's an example based on Joss PHP date thingy... $myDate = date('F Y', $pages->get(5108)->getUnformatted('blog_date')); echo $myDate; //Outputs August 2014, for example.
-
Hi Ryan, I know it's has been a while but is there any potential cause for this issue? I am having the same issue with 2.5.7, I setup a module with lazycron hook couple days ago and it works perfectly but after several days it stops working and I just couldn't identify why. No errors being logged which tells me lazycron is not being triggered at all. Here's my module if that helps: <?php /** * ProcessWire 'Hello world' demonstration module * * Demonstrates the Module interface and how to add hooks. * * See README file for further links regarding module development. * * ProcessWire 2.x * Copyright (C) 2014 by Ryan Cramer * Licensed under GNU/GPL v2, see LICENSE.TXT * * http://processwire.com * */ class Helloworld extends WireData implements Module { /** * getModuleInfo is a module required by all modules to tell ProcessWire about them * * @return array * */ public static function getModuleInfo() { return array( // The module'ss title, typically a little more descriptive than the class name 'title' => 'Hello World', // version number 'version' => 2, // summary is brief description of what this module is 'summary' => 'An example module used for demonstration purposes. See the /site/modules/Helloworld.module file for details.', // Optional URL to more information about the module 'href' => 'http://processwire.com', // singular=true: indicates that only one instance of the module is allowed. // This is usually what you want for modules that attach hooks. 'singular' => true, // autoload=true: indicates the module should be started with ProcessWire. // This is necessary for any modules that attach runtime hooks, otherwise those // hooks won't get attached unless some other code calls the module on it's own. // Note that autoload modules are almost always also 'singular' (seen above). 'autoload' => true, // Optional font-awesome icon name, minus the 'fa-' part 'icon' => 'smile-o', ); } /** * Initialize the module * * ProcessWire calls this when the module is loaded. For 'autoload' modules, this will be called * when ProcessWire's API is ready. As a result, this is a good place to attach hooks. * */ public function init() { $this->addHook('LazyCron::every30seconds', $this, 'fetch'); } /** * Example1 hooks into the pages->save method and displays a notice every time a page is saved * */ public function fetch($interval = null) { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, 'https://api.instagram.com/v1/users/1334465068/media/recent/?client_id=xxx'); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_TIMEOUT, 20); $result = curl_exec($ch); curl_close($ch); $result = json_decode($result); $urls = ""; foreach ($result->data as $post) { $urls .= $post->images->standard_resolution->url . ","; } if (strlen($urls) > 0) { $p = wire('pages')->get(1018); $p->setOutputFormatting(false); $p->instagram_urls = trim($urls, ","); $p->save('instagram_urls'); $p->setOutputFormatting(true); } } } Any help to know what's the issue was, is much appreciated! Thanks
-
It is cause filter is runtime memory while find is db query.
-
Hi sforsman, actually that's the very reason I made the plugin for: fields. It's useful to format the fields values, because you don't always need the same exact value coming from the database. For instance the Select fields: since the keys get stored, you could retrieve their corresponding labels by using a filter. Will FieldType::formatValue be attached to any field? That gave me an idea... public function init() { $this->addHookAfter("FieldType::formatValue", function(HookEvent $e) { $page = $e->arguments(0); $field = $e->arguments(1); $value = $e->arguments(2); // Apply filter for any field $value = applyFilter('formatValue', $value); // Apply filter for a specific field type $value = applyFilter('formatValue_'.$field->type, $value); // Example: formatValue_FieldtypeText // Apply filter for a specific field name $value = applyFilter('formatValue_'.$field->name, $value); // Example: formatValue_myfield // Finally return the value $e->return = $value; }); } I'm just thinking if that's flexible enough. Surely you can remove the hook at runtime if it's not needed or there could be 2 more methods in the plugin to remove/get the filters. So – to disable the filters temporarily – you could: store the current filters, remove them, do whatever needs to go "unfiltered", and add them back if necessary. If you think the Filter plugin is useful I'll definitely expand it, and thanks for the feedback!
-
The title function renderRepeaterLabel is hookable. Here's a generic example, which applies to all Repeater fieldtypes: class RepeaterTitle extends WireData implements Module { /** * getModuleInfo is a module required by all modules to tell ProcessWire about them * * @return array * */ public static function getModuleInfo() { return array( // The module'ss title, typically a little more descriptive than the class name 'title' => 'Repeater Title', // version number 'version' => 0.1, // summary is brief description of what this module is 'summary' => 'An example module used for demonstration purposes.', // Optional URL to more information about the module 'href' => 'http://processwire.com', // singular=true: indicates that only one instance of the module is allowed. // This is usually what you want for modules that attach hooks. 'singular' => true, // autoload=true: indicates the module should be started with ProcessWire. // This is necessary for any modules that attach runtime hooks, otherwise those // hooks won't get attached unless some other code calls the module on it's own. // Note that autoload modules are almost always also 'singular' (seen above). 'autoload' => true ); } /** * Initialize the module * * ProcessWire calls this when the module is loaded. For 'autoload' modules, this will be called * when ProcessWire's API is ready. As a result, this is a good place to attach hooks. * */ public function init() { $this->addHookBefore('InputfieldRepeater::renderRepeaterLabel', $this, 'repeaterLabel'); } public function repeaterLabel($event) { // Replace function $event->replace = true; // Arguments: $label, $cnt, Page $page $page = $event->arguments(2); // Show repeater page body instead $event->return = $page->body; } } Not sure what the best way is to replace the title per specific instance of a Repeater field -- I'm still learning my way around hooks. But I'm sure someone else knows!
-
Where to set image resizing quality and how to re-resize images
horst replied to Adam Kiss's topic in General Support
@Ivan: I appreciate your contributions / tipps. But, - 1) the script was hacked together last night in under 30 minutes including testing. It comes from that source (a proof of concept) 2) there is a very big black hole whith this: The script iterates over imagefields and than over single images, calling getVariations() bzw. removeVariations(). That's all. This leads into that all images used by RTE-Fields on the same page could not be identified as those. So the script simply deletes them too There may be a possibilty to detect some of the embedded images in RTE-fields, those using an HTML <img tag, but there are a lot of known and unknown possibilties how images can be embedded into RTEs. Think of HannaCodes, Markdown, BBCode, other Tools/Modules that store (generic) code into RTE's to later on runtime build a proper URL or img tag from it. All those get dropped and cannot recreated automatically, like those from imagefields. Also CropImage-fields will lost there individual CropAreas and fall back to automaticlly created ones. Therefore this is a very pour solution, only offered to some people here who do know about that risc and who are able to handle that right (during development only). (hopefully) As long as there is no solution that can cover the above noted cases, I do not release it elsewhere. Finally I'm glad that it can be of help in a small use case. -
Nico, is the upload taking longer than the max runtime of PHP scripts?
-
max image dimensions - "not a recognized image" [bug?]
horst replied to bernhard's topic in General Support
This is by design. and everyone can replicate it by simply setting the amount of memory way to small for such large images on his server. So, the error message in the first example isn't that lucky because you see the error from the derivative image (admin thumbnail 0x100) what could not be created from the way to large original image that should be scaled down to a max-size. If you have a look into the original image (open it in a simple plain text editor!) you will see that it contains something like: whereas the 0x100 thumb contains: @Ryan: Maybe we need to display the error from original image too so that it is more clear what was going on? So, but in your second example you can already read it by yourself: not enough memory to load/resize Imagerendering with the GD-lib needs minimum ram memory 2 - 2.5 times of the uncompressed image! If you load to large images into memory GD/PHP crashes with a not catchable fatal error. PW since version 2.5 does look ahead to available memory at runtime before loading images into memory. This way it saves you from crashes! I like how it works. Great job @Ryan! Simple calculation example with your image: width x height x colorchannels = memory bytes 4.608 x 3.456 x 3 = 47.775.744 - just to load one of those images into memory (togehther with rest of PW) you need 60MB ram! - and if you want to manipulate / resize it you need 47.775.774 x 2.3 = 109.884.211. Do you have a minimum of 128MB memory available for PHP? No, you need to bump it up. I recommend setting it higher in available server configuration panels, php.ini file or in the .htaccess: <IfModule mod_php5.c> php_value memory_limit 256M </IfModule> But you should not transmit images 4 times larger than the largest needed display size. (Denk an unsere Umwelt und an unsere Kinder die diese auch noch brauchen!) g-translate: (Remember our environment and our children also need this yet)