bcartier Posted May 25, 2015 Share Posted May 25, 2015 I have a situation where I'm trying to persist some data across page visits, but want to allow people to bookmark those pages to retain that data, or share the url and have that data persist. That means I can't use only $session or localStorage. I want to use Segment1 for this data so that the site's pages can still be cached. Can I somehow append a value as Segment1 to all urls (like $page->url) using a module or _init.php? What about outputting url fields? My guess is that I will need to append the value throughout my templates, but wondered if anyone has had to do something like this? Any suggetions? Thanks! -Brent Link to comment Share on other sites More sharing options...
bernhard Posted May 25, 2015 Share Posted May 25, 2015 do you mean something like permalinks? maybe you could clone your page and save it as its own child on every pagesave? you would then have something like this: /your-article (= current version) /your-article/2015-05-01-01-01 /your-article/2015-05-25-16-44 just an idea... of course you would have some unnecessary extra data, but maybe that would be a good solution? Link to comment Share on other sites More sharing options...
bcartier Posted May 25, 2015 Author Share Posted May 25, 2015 Thanks Bernard. It's a good thought, but I only need a single id-based value... not the all the fields/power of a Page. Something like http://example.com/F-456/ http://example.com/subpage/F-456/ http://example.com/search/F-456/ etc. (I'd use a canonical tag to deal with duplicate urls to similar content and google etc) Link to comment Share on other sites More sharing options...
bernhard Posted May 25, 2015 Share Posted May 25, 2015 sorry then i think i don't get what you are trying to achieve - I'm sure others will jump in Link to comment Share on other sites More sharing options...
bcartier Posted May 26, 2015 Author Share Posted May 26, 2015 In case it's helpful to someone else, I ended up solving this by creating a module. With a bit of help from the minifyHTML example in this article, and using the DomDocument class, I was able to manipulate internal links when appropriate. Works great! Link to comment Share on other sites More sharing options...
bernhard Posted May 26, 2015 Share Posted May 26, 2015 would be great if you shared the code with us - i'm curious Link to comment Share on other sites More sharing options...
bcartier Posted May 26, 2015 Author Share Posted May 26, 2015 No problem. Here's the module I put together: <?php class SiteFilter 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' => 'Site Filter', // version number 'version' => 1, // summary is brief description of what this module is 'summary' => 'Add the current filter value as urlSegment1 for all internal links.', // 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 ); } /** * Initialization function. This is where we'll attach our hooks. * */ public function init() { // minify page markup automatically wire()->addHookAfter("Page::render", $this, "addSegment1"); } public function isExternal($url) { $components = parse_url($url); if ( empty($components['host']) ) return false; // we will treat url like '/relative.php' as relative if ( strcasecmp($components['host'], wire('config')) === 0 ) return false; // url host looks exactly like the local host return strrpos(strtolower($components['host']), '.' . wire('config')->httpHost) !== strlen($components['host']) - strlen('.' . wire('config')); // check if the url host is a subdomain } /** * addSegment1 * * We have a session variable we'd like to append to all internal urls to persist site filters when * bookmarking, and sharing urls. This also allows filtered pages to be cached. Each template needs * to have segments enabled, and we use a regex value for allowed segments to prevent a runaway * cache. * @param HookEvent $event */ public function addSegment1(HookEvent $event) { // let's not mess with the back-end urls $cur_page = $event->object; if($cur_page->template == "admin") return; // Let's not pollute the page with domDocument warnings libxml_use_internal_errors(true); // event return value contains rendered markup $markup = $event->return; $currentFilter = wire('session')->settings_filter; if ($currentFilter == "") return; // we don't want to attempt minifying markup unless it's actually HTML if (strpos($markup, "<html") === false) return; $dom = new domDocument; $dom->loadHTML($markup); $dom->preserveWhiteSpace = false; $links = $dom->getElementsByTagName('a'); foreach($links as $link){ $url = $link->getAttribute('href'); $external = $this->isExternal($url); if($external === false){ if(strpos($url, $currentFilter) === false){ $url .= $currentFilter . "/"; $link->setAttribute("href", $url); } } } $newMarkup = $dom->saveHTML(); $event->return = $newMarkup; } } Link to comment Share on other sites More sharing options...
bernhard Posted May 26, 2015 Share Posted May 26, 2015 ah, now i understand your intention! thanks for sharing the code. I'm wondering why you are hooking Page::render? Wouldn't it be possible to hook somewhere where all the urls are created, so that $page->url automatically returns the url with the filter-segment if it is an internal url? note i'm not an expert, so i'm sure there is a good reason for this. Link to comment Share on other sites More sharing options...
LostKobrakai Posted May 26, 2015 Share Posted May 26, 2015 There are ways to change the url (and therefore path) of a page, see here: https://github.com/apeisa/Multisite/blob/master/Multisite.module. It just could be less efficient, as this hook can easily hog resources as url is quite often called property. Link to comment Share on other sites More sharing options...
bcartier Posted May 26, 2015 Author Share Posted May 26, 2015 I decided on Page::render because this site has a lot of internal urls stored in fields and output via templates that also need to carry the segment. There's also a large, sitemap-style menu that uses the $cache feature, and I didn't want to cache every variation. This way I can cache the large menu aggressively, and use replacements when rendering. 1 Link to comment Share on other sites More sharing options...
bcartier Posted May 26, 2015 Author Share Posted May 26, 2015 Thanks LostKobrakai - I'll explore that option too and see what works best. Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now