Jump to content

Search the Community

Showing results for 'runtime'.

  • Search By Tags

    Type tags separated by commas.
  • Search By Author

Content Type


Forums

  • Welcome to ProcessWire
    • News & Announcements
    • Showcase
    • Wishlist & Roadmap
  • Community Support
    • Getting Started
    • Tutorials
    • FAQs
    • General Support
    • API & Templates
    • Modules/Plugins
    • Themes and Profiles
    • Multi-Language Support
    • Security
    • Jobs
  • Off Topic
    • Pub
    • Dev Talk

Product Groups

  • Form Builder
  • ProFields
  • ProCache
  • ProMailer
  • Login Register Pro
  • ProDrafts
  • ListerPro
  • ProDevTools
  • Likes
  • Custom Development

Find results in...

Find results that contain...


Date Created

  • Start

    End


Last Updated

  • Start

    End


Filter by number of...

Joined

  • Start

    End


Group


AIM


MSN


Website URL


ICQ


Yahoo


Jabber


Skype


Location


Interests

  1. In this case you are modifying content at runtime to change it before it's output. You could setup something in your header include (if you using one) to take care of all your fields at once. Or you could create a Textformatter module to do it for you. This one would be particularly simple: /site/modules/TextformatterResponsiveImages.module <?php class TextformatterResponsiveImages extends Textformatter { public static function getModuleInfo() { return array( 'title' => "Responsive Images", 'version' => 100, 'summary' => "Remove the width tags from images so they can be responsive." ); } public function format(&$str) { $str = preg_replace('/ (width|height)=.\d+./', '', $str); } } Place in /site/modules/, install it, and then select it for any of your fields where you want it to apply.
  2. Ryan, this is just great! I would be happy to beta-test it on my local server and maybe to begin translation if it's already possible. Everything is clear, but I didn't quite understand where the translation is taken from during runtime. Is it kept in memory as an object or is it parsed from JSON file every time translation is needed?
  3. I've been making good progress here on ProcessWire 2.2 which we're targeting for the end of the year. The main drive of this version is adding multi-language support to the admin. This multi language support is being sponsored by Avoine, thanks to Antti Peisa. I just wanted to outline the approach we're taking as well as get any feedback and suggestions you have. The direction taken with multi language support is based on conversations Antti and I had a few months ago as well as feedback from users in the forum. What ProcessWire 2.2 focuses on There are lots of components to supporting multiple languages in a CMS, and the area we're focused on with this version is supporting multiple languages for PW's admin, modules and 3rd party modules. This is so that your clients can make edits to their site without having to know English. While PW hasn't had specific multi-language tools for your front end, it can support multiple languages any number of ways there (as many users have done, with language trees, multiple fields, etc). But the back-end tools have always been in English without an obvious way around that. So the biggest need has been a way to support multiple languages for PW's admin tools, core modules, 3rd party modules, etc. Basically, the non-dynamic side. And that's what PW 2.2 tackles. The direction being used We originally looked at PHP's gettext tools (http://www.php.net/manual/en/book.gettext.php), as they've been successfully used to provide this capability for CMSs like WordPress and Drupal, and they are a ready-to-go solution that is built-in to PHP and adds multi language capability with little overhead. I like gettext() from the PHP side as it's a really easy solution (for coding at least), and it's really efficient from the PHP side. But I felt that it puts a lot of burden on the translators with a lot of technical jargon, file formats and other tools. I want the translation tools to have the same simplicity as the rest of PW, and it looked like that was going to be a hard sell with gettext. Instead, we're using a home-brewed solution that essentially does the same thing as gettext, but is a whole lot simpler for translation. It's simple enough that if you find something that needs translation, you can just go and edit it in PW like you would edit anything else. It also means that these tools will be very simple for 3rd party module developers to use. They will also have use in your own sites and templates for your non-dynamic content. The tradeoff is that it takes longer to code this way (for me) and that it can't possibly be as efficient as gettext (given that gettext is built-in to PHP). Translations take up memory. However, PW, doesn't have files with tens of thousands of lines of code and doesn't need to keep thousands of translations in memory at any given time. When it gets down to the needs of PW and the needs of those using it, I don't believe we'd ever benefit from the efficiency of gettext. So the home-brewed solution won out. The actual solution is coded as a module. So if you don't need anything other than English in the admin, then you'll just leave the 'Languages' module uninstalled. How it works from the admin side The Languages module will be provided with the core, ready for a 1-click install. As soon as you click 'install', a 'Languages' tool is added to your Setup menu, a 'language' template is added to your templates, and a 'language' field is added to your fields and appended to the 'user' template with the default language (English) selected. When you go to Setup > Languages, you'll see a list of languages that are installed. From here you can click to edit a language or click 'Add New' to add a new language. Each language is technically a page (just like with users), so you can add additional fields to the 'language' template should it suit your needs. By default, each language template has a name (ISO-639 code, i.e. 'en'), a title (i.e. 'English') and a 'translations' file field. Each file in this field contains translations for a file in ProcessWire (whether a module, core, template, etc.). These files are created by another module in ProcessWire (to be discussed below) but a files field is provided here so that you can easily share your translations with other people. Likewise, you'll be able to download new language packs from the ProcessWire site and just upload them here, ready to use. How to make a translation ProcessWire keeps track of language translations on a per-file basis. So if you want to translate a file in ProcessWire, you have to tell it which one. ProcessWire will then load the file into memory and look for function calls that indicate translatable text. Then it presents you with a screen of all the phrases it found for translation, along with inputs for providing a translation for each one. See the attached screenshot for an example of this. When you hit 'save', it saves those translations in a JSON file that PW's languages module uses for runtime translation. This JSON file can also be shared with others, distributed with a module you've created, or zipped up with others as part of a language pack. As soon as the English version native to the translated file changes, the translated versions are considered out of date. We don't want to make guesses about the scope of the text change. So your translation screen will show you any existing translations that are considered 'out of date' along with new entry fields to provide new translations. Any fields left blank on the translation screen are considered untranslated and thus the original language (English) is substituted for any untranslated phrases. How it works from the code side I mentioned earlier that I like how gettext works from the developer side, and ProcessWire works in a very similar manner in this regard. Meaning, indicating text as translatable involves a "_" function call followed by the text. ProcessWire also needs a context, so you call this function with '$this'. Here's an example: $value = $this->_('Add New Page Here'); So $this->_('text') identifies the text as translatable. You have to use $this->_('text') rather than the gettext format of _('text') for two reasons: first is that the _('...') function is native to PHP and actually calls gettext, so that's already taken! Second is that ProcessWire needs a context to the function call… it needs to know what class or file it was called from, otherwise all translations would be a global namespace. So ProcessWire figures that out behind the scenes with a context of the calling class and uses the Reflection API to determine the file. If you didn't understand that last sentence, then don't worry because you don't need to–ProcessWire is taking care of the technical details for you. In addition to the $this->_('text') you can use a function format that would most likely be more suitable for translations performed in your template files. In this case, because "_" is already taken by gettext, we use "__" like WordPress does. So you can do this: echo __('Submit Form'); ProcessWire figures out the context of that call automatically and groups the translation with others from your template file. This type of call can also be used in 3rd party modules, but you'll have to tell PW the context, i.e. <?php echo __($this, 'Submit Form'); // these two lines do exactly the same thing echo $this->_('Submit Form'); Best practices for pre-translated text Just like with gettext, when entering text that's ultimately going to be translated, you need to avoid putting in any dynamic things in it. For instance, a string like "Found $count products" is not good for translation because it contains a variable in it. Instead, you'd want to enter such a string as: sprintf("Found %d products", $count). For more details, see the 'Marking Strings for Translation' and 'Best Practices' sections in WordPress's i18n page. They use gettext, but the same applies to us: Marking strings for translation http://codex.wordpress.org/I18n_for_WordPress_Developers#Marking_Strings_for_Translation Best practices http://codex.wordpress.org/I18n_for_WordPress_Developers#Best_Practices New API variables The Languages module installs a new API variable called $languages. It's interface is identical to that of $users in that it can be iterated as a PageArray or you can use get() and find() calls to pull individual languages from it, i.e. <?php foreach($languages as $language) { echo $language->title . "<br />"; } …and… <?php $french = $languages->get('fr'); The Languages module also adds a $language variable to every $user. So you can check what the current language is like this: <?php if($user->language->name == 'es') echo "Hola!"; Of course, $language is just a Page object, so it will also contain any other fields you have added to your 'language' template. Because ProcessWire's native language is English, the language is assumed to be English by default. So if you want it to assume a different language by default for your site, then you would just edit the 'guest' user and select a different language. Next Steps So that's the current state of ProcessWire 2.2 and how it's multilanguage support works. But it's not the only part of it. Because ProcessWire's admin is itself a site developed in PW, and because PW's output is not all non-dynamic, we need multilanguage support in our dynamic fieldtypes and inputfields in order to be truly multilingual. This is what I'll be focusing on in November, so will have more updates on that side of it then. Of course, this side may also be useful for the front-end (your sites) too, though my feeling is that a multi-tree approach is better for accessibility and SEO even if you do have multilingual fields. But even with a multi-tree approach, having multilingual fields will no doubt be useful with shared assets and more. I'm also hoping to have a beta version ready for those that are interested in testing within a month (or in the next few days, if interested in testing before multilingual fields are in place). Please post your questions, suggestions, feedback, etc. This is a work in progress and nothing is set in stone. Edit: added 'New API variables' section.
  4. Thanks I got your PM. The only thing I see as a possible issue in your phpinfo is that safe_mode is ON. I can't say as though I've come across a hosting environment with this turned on before. But my understanding of it is that if a server has safe_mode on, then the PHP script can't move/copy files unless it is the owner of those files. PHP appears to be running as an apache module rather than as a CGI on your server. So there is going to be some variation in permissions between your account and that of Apache. Usually not a problem at all, except when combined with safe_mode, that creates some headaches and could definitely interfere with file uploads. The first thing I want you to try is to create this directory and make it writable to all. Later on, once you know it's working, it'd be better to make it just writable to PHP (if you know what user it's running as). But if this is a dedicated server or the accounts are well jailed, then not a big deal. But for now create this directory and make it 777 (rwxrwxrwx): /site/assets/cache/uploads/ Then add this to your /site/config.php at the bottom: ini_set('upload_tmp_dir', $config->paths->cache . 'uploads/'); See if that resolves it. If not, the next thing to try is to see if your web host lets you create your own php.ini, or modify the php settings for your account. Many web hosts let you do this, but you might have to search around in their support docs. You will want to disable safe_mode, which can't be done at runtime with ini_set(). Let me know if you get to this point and I can help you figure it out. If none of those are an option, then I'd be willing to experiment on the server to find a solution if you don't mind giving me access temporarily. Btw, the site you have running on that server is gorgeous–beautiful design.
  5. All image fields are technically multi-image fields. The single-image access (when a field is set to 1 image max) is a type of outputFormatting for convenience on the front-end. All pages on the front-end of your site have outputFormatting turned on by default. When outputFormatting is on, it means the page is in a presentation-mode as opposed to a saveable mode. In presentation (outputFormatting) mode, pages are setup for presentation convenience and safety. The distinction exists so that content can be modified at runtime with custom formatters and such, without worry of that runtime-info ending up saved back into the database. This is why ProcessWire throws an error if you try to save a page with outputFormatting on. outputFormatting is also what converts an images field with a 1-image max to a single image rather than an array of 1 image. That's because I thought people would find it confusing on the front end to have to use an array when all they are dealing with is 1 image. Whereas, when coding for administration of any image(s) field, it's more convenient to treat them all the same way. When you are in the admin, pages don't come with outputFormatting on by default. Since it sounds like you are presenting content in the admin kind of like how you would on the front end, you can either turn on outputFormatting for those pages you are presenting content from, or better yet: treat all image fields as multi-image fields. If you do that, just remember that all text-based content is in a raw state. For instance, if you want to output an <img> tag with an alt attribute: <?php foreach($page->images as $img) { $alt = htmlentities($img->description, ENT_QUOTES, "UTF-8"); echo "<img src='{$img->url}' alt='$alt' /> } When building admin stuff, it's generally actually always better to have outputFormatting off.
  6. ProcessWire RSS Feed Loader Given an RSS feed URL, this module will pull it, and let you foreach() it or render it. This module will also cache feeds that you retrieve with it. The module is designed for ProcessWire 2.1+, but may also work with 2.0 (haven't tried yet). This module is the opposite of the MarkupRSS module that comes with ProcessWire because that module creates RSS feeds. Whereas this module loads them and gives you easy access to the data to do whatever you want. For a simple live example of this module in use, see the processwire.com homepage (and many of the inside pages) for the "Latest Forum Post" section in the sidebar. Download at: https://github.com/r...n/MarkupLoadRSS REQUIREMENTS This module requires that your PHP installation have the 'allow_url_fopen' option enabled. By default, it is enabled in PHP. However, some hosts turn it off for security reasons. This module will prevent itself from being installed if your system doesn't have allow_url_fopen. If you run into this problem, let me know as we may be able to find some other way of making it work without too much trouble. INSTALLATION The MarkupLoadRSS module installs in the same way as all PW modules: 1. Copy the MarkupLoadRSS.module file to your /site/modules/ directory. 2. Login to ProcessWire admin, click 'Modules' and 'Check for New Modules'. 3. Click 'Install' next to the Markup Load RSS module. USAGE The MarkupLoadRSS module is used from your template files. Usage is described with these examples: Example #1: Cycling through a feed <?php $rss = $modules->get("MarkupLoadRSS"); $rss->load("http://www.di.net/articles/rss/"); foreach($rss as $item) { echo "<p>"; echo "<a href='{$item->url}'>{$item->title}</a> "; echo $item->date . "<br /> "; echo $item->description; echo "</p>"; } Example #2: Using the built-in rendering <?php $rss = $modules->get("MarkupLoadRSS"); echo $rss->render("http://www.di.net/articles/rss/"); Example #3: Specifying options and using channel titles <?php $rss = $modules->get("MarkupLoadRSS"); $rss->limit = 5; $rss->cache = 0; $rss->maxLength = 255; $rss->dateFormat = 'm/d/Y H:i:s'; $rss->load("http://www.di.net/articles/rss/"); echo "<h2>{$rss->title}</h2>"; echo "<p>{$rss->description}</p>"; echo "<ul>"; foreach($rss as $item) { echo "<li>" . $item->title . "</li>"; } echo "</ul>"; OPTIONS Options MUST be set before calling load() or render(). <?php // specify that you want to load up to 3 items (default = 10) $rss->limit = 3; // set the feed to cache for an hour (default = 120 seconds) // if you want to disable the cache, set it to 0. $rss->cache = 3600; // set the max length of any field, i.e. description (default = 2048) // field values longer than this will be truncated $rss->maxLength = 255; // tell it to strip out any HTML tags (default = true) $rss->stripTags = true; // tell it to encode any entities in the feed (default = true); $rss->encodeEntities = true; // set the date format used for output (use PHP date string) $rss->dateFormat = "Y-m-d g:i a"; See the $options array in the class for more options. You can also customize all output produced by the render() method, though it is probably easier just to foreach() the $rss yourself. But see the module class file and $options array near the top to see how to change the markup that render() produces. MORE DETAILS This module loads the given RSS feed and all data from it. It then populates that data into a WireArray of Page-like objects. All of the fields in the RSS <items> feed are accessible, so you use whatever the feed provides. The most common and expected field names in the RSS channel are: $rss->title $rss->pubDate (or $rss->date) $rss->description (or $rss->body) $rss->link (or $rss->url) $rss->created (unix timestamp of pubDate) The most common and expected field names for each RSS item are: $item->title $item->pubDate (or $item->date) $item->description (or $item->body) $item->link (or $item->url) $item->created (unix timestamp of pubDate) For convenience and consistency, ProcessWire translates some common RSS fields to the PW-equivalent naming style. You can choose to use either the ProcessWire-style name or the traditional RSS name, as shown above. HANDLING ERRORS If an error occurred when loading the feed, the $rss object will have 0 items in it: <?php $rss->load("..."); if(!count($rss)) { error } In addition, the $rss->error property always contains a detailed description of what error occurred: <?php if($rss->error) { echo "<p>{$rss->error}</p>"; } I recommend only checking for or reporting errors when you are developing and testing. On production sites you should skip error checking/testing, as blank output is a clear indication of an error. This module will not throw runtime exceptions so if an error occurs, it's not going to halt the site.
  7. PW doesn't handle page numbers internally. Like with regular URL segments, it's up to you to decide what to do with them. PW doesn't know or care what your bounds are for page numbers. The MarkupPagerNav module is not a dependency for handling page numbers, and may or may not be used (that's a runtime decision). So if you want to handle numbers that are out of bounds, you can throw a Wire404Exception when that occurs (like you would with an unknown URL segment), though I don't usually bother with it. I think a better thing to do is to leave no results (with the pagination intact) or send a session->redirect back to page 1 or the last page. That way, if there used to be a page number in bounds that no longer is, at least you are providing a way for for that traffic to get back in-bounds.
  8. PW will adapt wherever you put it, whether on a subdirectory, different domain, subdomain, etc. You don't have to tell it anything about where it's running because it figures it out at runtime. It's a little harder to design the CMS that way (which is why most CMSs don't do it), but I think it's well worth it. Likewise, it doesn't care whether it's being accessed by HTTPS or not unless you specify that you only want one or the other in your template settings. Because you are using a different domain for HTTPS, you'll want to skip using that template setting and instead do this: To detect if the request is coming from an HTTPS connection: <?php if($config->https) { // user is on an HTTPS connection } else { // regular HTTP } If you wanted to logged-in users to always redirect to the same page at a different domain, you'd do this: <?php if($user->isLoggedin && !$config->https) { // redirect to the same page at the alternate https domain $session->redirect("https://clientname-fi.pwire.fi" . $page->url); } else { // user is in the right place } You probably want to put that in some universal/header include file so that you don't have to code it in more than one spot.
  9. Wiping the entire cache on every page save is a good idea to at least provide. In a system like PW, a given page might pull from several others that are determined at runtime. So there's no way the CMS can know all the possible interrelationships ahead of time. As a result, expiring the cache on every page save is the only way to know for sure that the site is delivering fully up-to-date pages. On the other hand, it's rare that I actually need the entire cache to expire on every save... and if I really need it for some reason, I go to Modules > Page Render > Clear Cache. But caching can be a difficult concept for a client to really understand sometimes, so having the entire cache expire on every page save can reduce the support burden. So in one of these near-term commits, I'm going to go ahead and add an option to the Template editor that says: When I save a page: 1. Expire the cache for the saved page only. 2. Expire the cache for all pages. Being able to specify that at the template level will provide a lot of flexibility.
  10. The parentPrevious is only available until the page is saved, and it's a runtime thing, so it's not saved in the DB. Though a revisions module is underway that will be saving all previous states of pages, but we're a couple months away from that being ready. Of course, you can always save the previous parent info yourself if you need it. For runtime, you can set whatever you want to a page and it will act as a data container. It only saves data in the fields assigned to it, so there's no harm in setting some other random values to a page if you want to. So you could for instance set $page->parentPreviousPete = $page->parentPrevious and use it where you needed it. If you wanted it to save to the DB, then you would need to actually add a field to the page called parentPreviousPete.
  11. Just running into a bit of trouble saving my page content via this module. I've set it to only run the module if the page's parent is the news page and with xDegug turned on on my XAMPP server it says it's stuck in a loop (without xDebug on it just crashes Apache). Here's a very stripped-down version of my module with the issue: <?php /** * ProcessWire 'Hello world' demonstration module * * Demonstrates the Module interface and how to add hooks. * * ProcessWire 2.x * Copyright (C) 2010 by Ryan Cramer * Licensed under GNU/GPL v2, see LICENSE.TXT * * http://www.processwire.com * http://www.ryancramer.com * */ class Newstopic 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' => 'News Topic Create', // version: major, minor, revision, i.e. 100 = 1.0.0 'version' => 100, // summary is brief description of what this module is 'summary' => 'Creates a topic for each new news article that is saved. Checks none exists currently.', // Optional URL to more information about the module 'href' => 'http://www', // 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() { // add a hook after the $pages->save, to issue a notice every time a page is saved $this->pages->addHookAfter('save', $this, 'createNewsTopic'); // add a hook after each page is rendered and modify the output //$this->addHookAfter('Page::render', $this, 'example2'); // add a 'hello' method to every page that returns "Hello World" //$this->addHook('Page::hello', $this, 'example3'); // add a 'hello_world' property to every page that returns "Hello [user]" //$this->addHookProperty('Page::hello_world', $this, 'example4'); } /** * Example1 hooks into the pages->save method and displays a notice every time a page is saved * */ public function createNewsTopic($event) { $page = $event->arguments[0]; // Check it's a news article if ($page->parent_id == 5831) { // If the hidden news_topic field for this article is empty, then we'll create a topic if (empty($page->news_topic)) { echo "It's empty"; $page->news_topic = 123; } else { echo "It's got a value"; $page->news_topic = ''; $page->save(); } exit; //$this->message("Hello World! You saved {$page->path}."); } } } and here's the debug info from xDebug: ( ! ) Fatal error: Maximum function nesting level of '100' reached, aborting! in C:\xampp\htdocs\sc11\wire\core\Wire.php on line 229 Call Stack # Time Memory Function Location 1 0.0035 392416 {main}( ) ..\index.php:0 2 0.2985 7064064 ProcessPageView->execute( ) ..\index.php:170 3 0.2985 7064216 Wire->__call( ) ..\Wire.php:0 4 0.2985 7064216 Wire->runHooks( ) ..\Wire.php:229 5 0.2985 7065264 call_user_func_array ( ) ..\Wire.php:267 6 0.2985 7065400 ProcessPageView->___execute( ) ..\Wire.php:0 7 0.3080 7109160 Page->render( ) ..\ProcessPageView.module:73 8 0.3080 7109312 Wire->__call( ) ..\Wire.php:0 9 0.3080 7109312 Wire->runHooks( ) ..\Wire.php:229 10 0.3082 7112336 PageRender->renderPage( ) ..\Wire.php:289 11 0.3082 7112536 Wire->__call( ) ..\Wire.php:0 12 0.3082 7112536 Wire->runHooks( ) ..\Wire.php:229 13 0.3082 7113584 call_user_func_array ( ) ..\Wire.php:267 14 0.3082 7113768 PageRender->___renderPage( ) ..\Wire.php:0 15 0.3102 7157328 TemplateFile->render( ) ..\PageRender.module:194 16 0.3102 7157480 Wire->__call( ) ..\Wire.php:0 17 0.3102 7157480 Wire->runHooks( ) ..\Wire.php:229 18 0.3103 7158528 call_user_func_array ( ) ..\Wire.php:267 19 0.3103 7158664 TemplateFile->___render( ) ..\Wire.php:0 20 0.3117 7204976 require( 'C:\xampp\htdocs\sc11\site\templates\admin.php' ) ..\TemplateFile.php:88 21 0.3122 7206648 require( 'C:\xampp\htdocs\sc11\wire\templates-admin\controller.php' ) ..\admin.php:13 22 0.3130 7239504 require( 'C:\xampp\htdocs\sc11\wire\core\admin.php' ) ..\controller.php:13 23 0.3264 7437216 ProcessController->execute( ) ..\admin.php:42 24 0.3264 7437368 Wire->__call( ) ..\Wire.php:0 25 0.3264 7437368 Wire->runHooks( ) ..\Wire.php:229 26 0.3265 7438416 call_user_func_array ( ) ..\Wire.php:267 27 0.3265 7438552 ProcessController->___execute( ) ..\Wire.php:0 28 0.3436 8017272 ProcessPageEdit->execute( ) ..\ProcessController.php:194 29 0.3436 8017424 Wire->__call( ) ..\Wire.php:0 30 0.3437 8017424 Wire->runHooks( ) ..\Wire.php:229 31 0.3437 8018472 call_user_func_array ( ) ..\Wire.php:267 32 0.3437 8018608 ProcessPageEdit->___execute( ) ..\Wire.php:0 33 0.4291 9419280 ProcessPageEdit->processSave( ) ..\ProcessPageEdit.module:94 34 0.4475 9558616 Page->save( ) ..\ProcessPageEdit.module:160 35 0.4475 9558784 Pages->save( ) ..\Page.php:791 36 0.4475 9558984 Wire->__call( ) ..\Wire.php:0 37 0.4475 9558984 Wire->runHooks( ) ..\Wire.php:229 38 0.4509 9545040 Newstopic->createNewsTopic( ) ..\Wire.php:289 39 0.6296 23635104 Page->save( ) ..\Newstopic.module:103 40 0.6296 23635272 Pages->save( ) ..\Page.php:791 41 0.6296 23635472 Wire->__call( ) ..\Wire.php:0 42 0.6296 23635472 Wire->runHooks( ) ..\Wire.php:229 43 0.6352 23644064 Newstopic->createNewsTopic( ) ..\Wire.php:289 44 0.6370 23644512 Page->save( ) ..\Newstopic.module:103 45 0.6370 23644680 Pages->save( ) ..\Page.php:791 46 0.6370 23644880 Wire->__call( ) ..\Wire.php:0 47 0.6370 23644880 Wire->runHooks( ) ..\Wire.php:229 48 0.6392 23648016 Newstopic->createNewsTopic( ) ..\Wire.php:289 49 0.6400 23648136 Page->save( ) ..\Newstopic.module:103 50 0.6400 23648304 Pages->save( ) ..\Page.php:791 51 0.6400 23648504 Wire->__call( ) ..\Wire.php:0 52 0.6400 23648504 Wire->runHooks( ) ..\Wire.php:229 53 0.6425 23651408 Newstopic->createNewsTopic( ) ..\Wire.php:289 54 0.6441 23651856 Page->save( ) ..\Newstopic.module:103 55 0.6441 23652024 Pages->save( ) ..\Page.php:791 56 0.6441 23652224 Wire->__call( ) ..\Wire.php:0 57 0.6441 23652224 Wire->runHooks( ) ..\Wire.php:229 58 0.6461 23655296 Newstopic->createNewsTopic( ) ..\Wire.php:289 59 0.6468 23655416 Page->save( ) ..\Newstopic.module:103 60 0.6468 23655584 Pages->save( ) ..\Page.php:791 61 0.6468 23655784 Wire->__call( ) ..\Wire.php:0 62 0.6468 23655784 Wire->runHooks( ) ..\Wire.php:229 63 0.6487 23658696 Newstopic->createNewsTopic( ) ..\Wire.php:289 64 0.6502 23659144 Page->save( ) ..\Newstopic.module:103 65 0.6503 23659312 Pages->save( ) ..\Page.php:791 66 0.6503 23659512 Wire->__call( ) ..\Wire.php:0 67 0.6503 23659512 Wire->runHooks( ) ..\Wire.php:229 68 0.6522 23662584 Newstopic->createNewsTopic( ) ..\Wire.php:289 69 0.6530 23662704 Page->save( ) ..\Newstopic.module:103 70 0.6530 23662872 Pages->save( ) ..\Page.php:791 71 0.6530 23663072 Wire->__call( ) ..\Wire.php:0 72 0.6530 23663072 Wire->runHooks( ) ..\Wire.php:229 73 0.6551 23665984 Newstopic->createNewsTopic( ) ..\Wire.php:289 74 0.6567 23666432 Page->save( ) ..\Newstopic.module:103 75 0.6567 23666600 Pages->save( ) ..\Page.php:791 76 0.6567 23666800 Wire->__call( ) ..\Wire.php:0 77 0.6567 23666800 Wire->runHooks( ) ..\Wire.php:229 78 0.6586 23669872 Newstopic->createNewsTopic( ) ..\Wire.php:289 79 0.6593 23669992 Page->save( ) ..\Newstopic.module:103 80 0.6593 23670160 Pages->save( ) ..\Page.php:791 81 0.6593 23670360 Wire->__call( ) ..\Wire.php:0 82 0.6593 23670360 Wire->runHooks( ) ..\Wire.php:229 83 0.6593 23671432 call_user_func_array ( ) ..\Wire.php:267 84 0.6593 23671616 Pages->___save( ) ..\Wire.php:0 85 0.6604 23673256 FieldtypeInteger->savePageField( ) ..\Pages.php:421 86 0.6604 23673504 Wire->__call( ) ..\Wire.php:0 87 0.6604 23673504 Wire->runHooks( ) ..\Wire.php:229 88 0.6604 23674560 call_user_func_array ( ) ..\Wire.php:267 89 0.6604 23674792 Fieldtype->___savePageField( ) ..\Wire.php:0 90 0.6605 23674952 FieldtypeInteger->deletePageField( ) ..\Fieldtype.php:504 91 0.6605 23675200 Wire->__call( ) ..\Wire.php:0 92 0.6605 23675200 Wire->runHooks( ) ..\Wire.php:229 93 0.6605 23676256 call_user_func_array ( ) ..\Wire.php:267 94 0.6606 23676488 Fieldtype->___deletePageField( ) ..\Wire.php:0 95 0.6606 23676520 WireData->__unset( ) ..\Data.php:0 96 0.6606 23676520 WireData->remove( ) ..\Data.php:169 97 0.6606 23676480 Wire->trackChange( ) ..\Data.php:133 98 0.6606 23676632 Page->changed( ) ..\Wire.php:504 99 0.6606 23676832 Wire->__call( ) ..\Wire.php:0 This error message was shown because the site is in DEBUG mode. Any ideas why it might be going crazy nesting functions like that?
  12. If the page in question actually has a field called 'process', then checking $page->process is going to return the value of that field. But $this->process [or wire('process')] is a runtime property that is made available to the system and represents the process that is currently running. My guess is that you probably don't want to be looking at the $page->process.
  13. Page Link Abstractor module for ProcessWire 2 Plugin module that lets you move pages in your site without worry of ever breaking static links on other pages. Download at: https://github.com/ryancramerdesign/PW2-PageLinkAbstractor What it does Converts links in textarea/rich-text fields to an abstract format for storage, and converts them back at runtime. This means that if you move a page and another page is linking to it, the link won't be broken. It also means you can move your site from subdirectory to root (or the opposite) and not break links you may have created in your textarea fields. This applies to any kind of links: pages, files, images, etc. This module will also notify you when you edit a page that has a link to a page that doesn't exist or is in the trash. This module has been tested with ProcessWire 2.1 but should also work with 2.0. Since this module has not yet had a lot of testing, it should be considered "beta" and use is at your own risk. Please let me know of any issues or bugs you run into. How to install 1. Download the PageLinkAbstractor.module file from https://github.com/ryancramerdesign/PW2-PageLinkAbstractor and place it in: /site/modules/ 2. In the admin control panel, go to Modules. At the bottom of the screen, click the "Check for New Modules" button. 3. Now scroll to the PageLinkAbstractor module and click "Install". 4. Edit any of your textarea fields in Setup > Fields. You'll see a new configuration option to enable this module for that field. How it works This is a technical explanation for how this module works for those that are interested. Reading this is not required in order to use this module, but it may help you to use it more effectively. When you save a page that has a textarea field with this module enabled, it will look for URLs in HTML attributes by looking for an equals sign followed by a URL. It replaces instances of your site's root URL with a special tag: {~root_url} Next it checks to see if any of the URLs it found can be loaded as pages in your site. If so, it replaces those URLs with this special tag: {~page_123_url} where "123" is the Page's ID. When the page is loaded, ProcessWire does the opposite and converts those special tags back to their URLs. Because the URLs were abstracted to tags that are generated at runtime, when a page (or a site) is moved, no links are broken. Note that this module only converts URLs to tags when you save a page, so it only affects pages saved after the module is installed. Where to use it This would be most useful on your main 'body' field that uses a rich text editor (like TinyMCE). Where not to use it There is some overhead in using this module that will be insignificant if you use it carefully. Here are a few instances to avoid using it: Avoid use on fields that have the 'autojoin' option on, unless your site doesn't load lots of pages in a given request. Don't use on textarea fields that can contain anonymous (guest) user input. Avoid use on fields that aren't likely to contain links to local site pages in HTML markup. No need to have this module parsing things unnecessarily. Avoid use on fields where you think you might disable it later. Once disabled, the abstract tags representing the URLs will still be in place. If the module is disabled, those tags will no longer be converted to URLs are runtime. You would have to correct them manually by editing the page. Side benefit The tags that this module abstracts to are intentionally fulltext indexable, so you can perform searches for these tags. This means that you can find all pages linking to another by searching for it (minus the brackets and "~"). For example: $links = $pages->find("body~=page_123_url"); That would return all [viewable and visible] pages linking to page ID 123. Please note In order to convert URLs for pages, this module needs to load those pages in order to obtain their URL. If you are linking to a hundred pages in your 'body' field, you should expect that it may slow down the page 'load' and page 'save' time for pages containing lots of links. This module doesn't yet abstract local URLs that have a schema/protocol and domain in it. It just works with path-type links like /path/to/page/ and not http://domain.com/path/to/page/. This module hasn't yet been tested with migrating a site from subdirectory to root, but I will be testing this soon.
  14. Ok, this helped a lot. &modal=1 is added by AdminBar (line 280): <?php /** * Hook to take place right before a redirect occurs * * We intercept the redirect URL and modify it to add 'modal=1' to the query string * */ public function sessionRedirect($event) { if(!$this->page || $this->page->template != 'admin') return; if(!$this->input->get->modal) return; $url = $event->arguments(0); if(preg_match('/[?&]modal=/', $url)) return; $url .= (count($this->input->get) ? '&' : '?') . "modal=1"; $event->arguments(0, $url); } If I comment $url .=... line out, then it redirects to admin page, but there is "you are logged in" notification in place. Same happens if I go directly to /processwire/adminbar/ab-sitemap/. But if I go to setup -> templates and set that "adminbar" template manages it's access and set it to go 404 page when there is no access, then I go to 404 page. So this is definitely some kind of access problem. Maybe in page create? <?php // create /adminbar/ page under admin $abPage = new Page(); $abPage->template = $abTemplate; $abPage->parent = $this->pages->get($this->config->adminRootPageID); $abPage->name = $abName; $abPage->status = 1031; // hidden & locked $abPage->save(); // after that create /adminbar/sitemap/ $abSitemapPage = new Page(); $abSitemapPage->template = $abTemplate; $abSitemapPage->parent = $abPage; $abSitemapPage->name = 'ab-sitemap'; $abSitemapPage->status = 1031; return $abSitemapPage->save(); There is no view button on adminbar pages when browsing page tree, but this must be because there is no actual template file (we set that at runtime): <?php // We change the filepath of adminbar template file public function beforePageRender($event) { $page = $event->object; if($page->template == 'adminbar') { $page->template->filename = $this->config->paths->AdminBar . "templates/sitemap.php"; } } And I get this working when I copy /site/modules/AdminBar/templates/sitemap.php to /site/templates/sitemap.php and after that edit template "adminbar" and "advanced" tab, and set it to use sitemap.php template. So this is pretty minor issue, but not sure if I understand where the real problem lies?
  15. Thanks for your post. What you are doing looks right, except that you can skip creating the Pageimages field. PW would rather do that internally. So this is the entirety of what you should do (after you have your $page object): <?php $page->images->add("path or URL to image"); $page->save(); If you are doing this from a template file (as opposed to a shell script or admin module), you have to turn the output formatting off first, as you saw. This is to ensure that you don't accidentally add runtime-formatted content to a page and save it. By "runtime-formatted", I mean entity encoded, markdown, etc. This example might better explain it: <?php $mypage = $pages->get(123); echo $mypage->title; // value is "Products & Services" $mypage->setOutputFormatting(false); echo $mypage->title; // value is "Products & Services" Now lets say that you did this instead: <?php $mypage = $pages->get(123); $mypage->title = "Great " . $mypage->title; $mypage->save(); If ProcessWire let you save that page, the 'title' field would now have this value the next time you viewed it: Great Products && Services Basically, PW only wants to save content in an unformatted "clean" state. It throws that error asking you to set output formatting OFF in order to protect against you corrupting your content. So to follow up from the first example, this is what you should do if you are doing this import from a template file: <?php $page->setOutputFormatting(false); $page->images->add("path or URL to image"); $page->save();
  16. This is one of the potential problems with using the WireSaveableItems, because the default behavior is that they load an entire table and all it's rows in memory at runtime. This is desirable for things like templates and fields because we need all this stuff in memory to build pages, and don't necessarily know what we'll need ahead of time. But for large inventories of information, there might be memory or speed issues as the number of items increases. To account for this, you can specify a selector to the load() function to tell it what you want with a selector string: $this->load($this->videosArray, "limit=10, sort=id"); That selector string can have both "start" and "limit" and "sort" options for pagination. You can also have it match any given field name in your table. For operators, you are limited to: =, <, >, !=. With those limitations in mind, they work like selectors on pages in all other respects. I also want to mention that ProcessWire does not currently use this feature of the WireSaveableItems class, so if you use it, you are the first to test it. Let me know if you run into any issues and we'll get them fixed. That's correct, but that pagination is only specific to pages. You can certainly use pagination with your module, but you'll need to specify the "start" and "limit" options to your load function manually. (When it comes to paginating actual pages, ProcessWire takes care of the "start" part for you.) When working in a database client (like PHPMyAdmin) it's true that your view of the data will be in a traditional single-table format, unlike pages where fields occupy their own table. But within ProcessWire, the view is just a manner of how you use the API code. The way you work with items coming from a WireSaveableItems class and items coming from pages is going to be the same. For example, in this part of your code: <?php $table = $this->modules->get("MarkupVideoDataTable"); $table->headerRow(array( 'Volume', 'Name', 'Description', 'Event Date', 'Price', )); foreach($videos as $video) { $volume = 'Vol. '.$video->volume; $table->row(array( $volume => "edit?id={$video->id}", $video->name, $video->description, $video->eventDate, $video->price, )); } ...$videos could just as easily be a PageArray (like from $pages->find(...) or $page->children(...), etc.), and it could be substituted without any changes. So while there is a difference in the view at the database table level, there isn't any difference at the ProcessWire API level. I don't want to talk you out of the approach you are taking, because I like what you are doing and am thrilled to see some of these classes get used outside the core -- so stick with it, and I'll be here to help. But I also want to make sure I communicate that the data you are working with is exactly what pages were designed for. Pages are data containers of a defined type (template) with defined fields... they may or may not represent an actual page on your web site, that's up to you. But pages are really useful for building huge inventories of data and making it easy to view, search and manipulate, and even change it's structure without changing your code. Think of pages like you would a node in Drupal... they may represent a page on your site, but their intended use is much more abstract than that. You can! Lets say that Users were pages. Here is how you would load an filter them by role at the same time: <?php $users = $this->pages->find("template=user, role=superuser"); foreach($users as $user) { ... } // output them in the same manner as ProcessUser.module This approach has an advantage over what's being done in ProcessUser.module right now, because it only loads the users that match the filter. The way ProcessUser works right now is that it iterates through all the users and skips the iteration if the filter doesn't match. Here's another example more specific to your case, filtering by volume number: <?php $videos = $this->pages->find("template=video, volume=123"); forech($videos as $video { ... } ...or... <?php $videos = $this->pages->get("/path/to/videos/")->children("volume=123"); foreach($video as $video) { ... } Of course, ProcessWire does this filtering at the database level (not in memory). That makes sense, and there are very good reasons for having something completely separate from a storage standpoint. From an organization standpoint, the main difference would be that the videos don't appear anywhere in the page structure. But I think your ProcessVideo.module would be equally useful whether videos are pages or WireSaveableItems (and the code behind it would likely be very much the same). Each page is assigned a template that defines it's data structure, and optionally provides a file where you can produce output for the page's URL. But that part is totally optional. If you choose to display them in some other way, the manner in which you do it should be the same. I built pages for this purpose, so that's the approach I would take myself. But I also think you have good reasons for the approach you've taken and there's nothing wrong with it. There are both tradeoffs and benefits which only you can evaluate what is best for your needs. If I'm understanding it all correctly, here are a few of the pros for your approach: 1) it can be more efficient if you are careful about how much data you load at once; 2) the data relates directly to a table, making it a simpler matter if you like to work directly in SQL; 3) it's compartmentalized, not relying upon prerequisite fieldtypes or templates (which may make for simpler portability if you distribute the module). I think in your case it is a good approach because you have PHP knowledge and know your way around code, and I am glad to see you doing it ... it also helps me to make a better product when people push the utility of these core classes. Thanks, Ryan
  17. In your /site/config.php there is a setting in there called: $config->loginPageID = 23; Change 23 to the ID of the page you want to be the login page. If you want to use a given login page only in some instances, I believe you can also change that $config item at runtime. For example, you might put this in some main template for your site: $config->loginPageID = $pages->get("/tools/login/")->id; I haven't tried this, so let me know if it doesn't work and I can find another way to do it or make it part of the template config as you suggested.
  18. Welcome to the forums Queryeee. I'm glad to see you experimenting with Fieldtypes. Your formatValue() function looks correct. Though you are using it in a different way than I've seen before. So I wanted to pass along some info that I thought might help in the context you are using it. First off, I would suggest that you post your entire Fieldtypetest class, because I want to make sure the other prerequisites are accounted for. Fieldtypes define database schema for a type of field, they identify an Inputfield to handle input, they sleep and wake values for going to/from the database, and they handle sanitization and formatting of their type of values for pages. I want to make sure that your Fieldtype is covering these areas, because it may not work otherwise. When you create a new Fieldtype, you should capitalize the "test" part, like FieldtypeTest rather than Fieldtypetest. When you've successfully created a new Fieldtype module, you have to install it in Admin > Modules. Then you have to create a new field in Admin > Setup > Fields, and choose "test" as your fieldtype. Then you'll add that field to one or more templates, making it apply to any pages using those templates. I'm going to assume you already know all this, but I wanted to mention it just in case. Fieldtypes can optionally specify a formatValue() function to handle runtime formatting. Most fields don't use it, but some do. Examples of fields that use it are text fields where you've added markdown or entity encoding formatters to it. And date fields also use outputFormatting to show formatted dates when it's ON and unix timestamps when it's OFF. The formatValue function is triggered every time you call $page->testField (or any field) and $page->outputFormatting == true. By default, $page->outputFormatting is always TRUE in your web site, so you don't have to think about it unless you need an unformatted value. However, if you are using the API from admin modules or command line scripts, then $page->outputFormatting is FALSE by default. For fields where it matters, you want outputFormatting to be TRUE when you are outputting values for presentation to a web site, but you want it to be FALSE when you are manipulating those values and saving pages. So for those fields, if you try to modify their value on a page when outputFormatting is TRUE, and then try to save the page ($page->save), ProcessWire will throw a fatal error to prevent you from corrupting the data. Why? If it didn't, then you might end up saving values to your page that have runtime formatters applied to them... so the next time you view that page, you'd have double-formatted values, i.e. two <div> tags rather than one, in your case. Luckily, ProcessWire prevents you from doing that. You can set whether outputFormatting is on or off for any page by calling: $page->setOutputFormatting(true or false); If you aren't seeing your <div>...</div> in your $page->testValue, then I'm guessing that $page->outputFormatting is FALSE in the place where you are using it. If you want to confirm, you can do this: echo $page->outputFormatting ? "ON" : "OFF"; However, if you are doing this from one of your site templates, it is going to be ON unless you've specifically turned it off. So if that is the context you are in, then I'm also confused why you aren't seeing your value with the <div></div> between it... and why I think it may be a good idea to post the class file here (or email to me if you prefer). Next, lets look at: $this->config->scripts->add(...) ProcessWire admin uses that a lot so that markup generating modules (Inputfield and Process) can tell it what scripts to load in the admin template. If you look at /wire/templates-admin/default.php, you'll see something like this in the <head> section: <?php foreach($config->styles->unique() as $file) echo "\n\t<link type='text/css' href='$file' rel='stylesheet' />"; foreach($config->scripts->unique() as $file) echo "\n\t<script type='text/javascript' src='$file'></script>"; ?> ProcessWire can do this because it's for it's own use, in the admin panel. But it won't make any assumptions about your own templates. It doesn't know or care what you are doing with your own templates, so it's not going to output <script> tags. As a result, if you want to use $config->scripts or $config->styles, then your template will have to do something like the above. And it's perfectly fine to use $config->scripts and $config->styles, that's what they are there for. If you want that script included without your template having to account for it, then I would suggest doing it inline. So your formatValue function would include the <script src='...'></script> tag directly in the returned value, after the </div>. I know that inline scripts are not a best practice in regular markup, but that is in lieu of other factors. if you are trying to build a self-contained Fieldtype that needs to output markup, and you don't want to have to add markup anywhere else, then it would be acceptable to output the <script> tag as part of your value.
  19. If anyone wants to take the lead on building this functionality, I'll be glad to collaborate with you on making it a ProcessWire module. Based on what Deandre212 posted, I am thinking it might involve a Page::render hook that looks for certain tags and adds attributes to them. Or, [possibly better] it might involve creating a new RDFa runtime TextFormatter module that you can assign to text fields like text, textarea and textarea-tinymce. For an example of an existing runtime text formatter, see any of the modules in here: /wire/modules/Textformatter/. While I know how the ProcessWire side would work, I don't really know how the RDFa side would work...
  20. Just noticed the recent GitHub commit: and looks intriguing... Any chance of some sample code to illustrate how/where this might be used? Thanks in advance
  21. I think it might be better to just override the template rather than putting one in the /templates/ dir (unless you want to encourage them to edit it). I've modified the Template class so that you can change the target filename at runtime, so you'll want to grab the latest commit. https://github.com/ryancramerdesign/ProcessWire/commit/0c8dc7d8e62c9a6a110791e00111c463ff00b01c Next, move that template to the same directory as your module (/site/modules/AdminBar/adminbar.php). Then in your AdminBar.module, add a new "before" page render hook. It will check to see if the page template is "adminbar", and if it is, it'll change the template filename to the one in your /site/modules/AdminBar/ dir. <?php public function beforePageRender($event) { $page = $event->object; if($page->template == 'adminbar') { $page->template->filename = $this->config->paths->AdminBar . "adminbar.php"; } } Also, add this to your init() function in AdminBar.module: $this->addHookBefore('Page::render', $this, 'beforePageRender'); If you do decide you want it to check if the file is in your /site/templates/ first, then just add that check to your beforePageRender method. Now it should work exactly the same as before, except that it'll use the template file in your /site/modules/AdminBar/ dir rather than expecting one to be in /site/templates/.
  22. I'll be happy to get you started with a "blank" module that you can build it on top of. What I recommend is that we hook into the Page::render method, grab it's output, and insert your js and css markup file links right before a page's closing </head> tag. That way, when someone installs the module, it'll just start working without them having to do anything on their own. Of course there will be those that want to control the placement of those things, so I'll show you how to make that configurable. The PHP code that is in your .inc will become the module code. Let me know if this sounds like a good plan to you, and I'll follow up with posts showing you how. There are definitely merits to inline editing, depending on the site. I view the needs of page viewing and page editing as fundamentally different, and prefer to have an interface that is designed for one or the other (though the 'overlay', like in Drupal, and in your example, is a nice compromise). But there are many cases where it is really handy to be able to edit inline, if the site design supports it. As an example, I like to make moderated comment approval inline, so that I can just click "approve" or "spam" while viewing the comments (though Akismet mostly does that for me now). There are plenty of other cases, and I'm betting that Aloha Editor will provide some good opportunities. I think you'll find ProcessWire works well when you want something to be editable inline. On the front end, you would just need to make sure that the page is editable before including the inline editors, i.e. if($page->editable()) { ... }. Then you'll need for your template, include or module to look for when they've clicked 'save', i.e. <?php if($input->post->submit_save && $page->editable()) { // turn off runtime formatters (like entities, markdown, date formats, etc). $page->setOutputFormatting(false); // go through all the submitted fields and set those that are applicable foreach($input->post as $field => $value) { if($page->fields->has($field)) $page->set($field, $value); } // if the above resulted in a change, then save the page if($page->isChanged()) $page->save(); // turn output formatting back on so it's in the proper state for viewing $page->setOutputFormatting(true); } Note that if the "save" button is just attached to individual fields, and you'll only be saving one field at a time (possibly ajax driven), then you may want to just save the field rather than the whole page, i.e. $page->save('field name');
  23. I will add this to the roadmap as a module (most likely a Fieldtype). But also wanted to follow up with the strategy that I use, and the reason why the need for a publish/unpublish by date has not come up before. It's because this is so easily accomplished with the API. It also gives you more control over how you want to react to such dates. Here's how: Lets say I added a datetime field for publish date and/or expire date to the page's template. That template checks it's dates before it outputs anything. For example, lets assume we added a datetime field to the job_advert template called "expire_date". When we edited a job advert, we selected an expire_date of February 1, 2011. The job_advert template might have code like this: <?php if(time() > $page->getUnformatted('expire_date')) { throw new PageNotFoundException(); // or print "sorry this posting has expired" if you don't want a 404 } // print the job advert Note that the getUnformatted() function above is necessary because ProcessWire will return a formatted date according to the format you specified when you created the field, "January 21, 2011" as an example. So using getUnformatted() is a way to ensure it returns a timestamp that you can use for comparison with other timestamps (like that returned by PHP's time() function). (Btw, that getUnformatted() function works with any field, returning text fields without entities or runtime markup, etc.) Lets say that you also wanted to move the job advert to the trash since we now know it's expired: <?php if(time() > $page->getUnformatted('expire_date')) { $pages->trash($page); // move it to the trash throw new PageNotFoundException(); } // print the job advert Next lets assume that you didn't move the page to the trash, but you are just leaving it where it is and not disabling it or anything. If that's the case, you'll want to check that it's not expired when you links to your job adverts. So here's what your list_job_adverts template might look like: <?php $now = time(); $jobs = $page->children("expire_date>$now"); foreach($jobs as $job) { // print the job listing, being confident that it's not expired } If you had both expire_date and publish_date fields, then you'd find those jobs with something like this: <?php $now = time(); $jobs = $page->children("expire_date>$now, publish_date<=$now");
  24. Good question. You can use the built-in append() and/or prepend() functions, i.e. $menu_items->prepend($home); I believe the unshift syntax will also work: $menu_items->unshift($home); You don't have to worry about modifying the site tree because you would have to actually save a $page in order to modify the site tree. In addition, none of what you are trying to do here is modifying any pages, so even if you did save a page, it wouldn't modify anything. PageArrays are runtime dynamic arrays, and aren't saved anywhere unless they are attached to something like the result of a Page reference Fieldtype. See /wire/core/Array.php and /wire/core/PageArray.php for all the traversal and modification methods (there are a lot). For the most part, they are patterned after jQuery traversal methods, but I included alternate names like unshift() and shift() for people that prefer PHP function names. Just for fun, here's your example all bundled on one line. foreach($pages->find("parent=/navigation/")->prepend($pages->get('/')) as $item) { ... Or even shorter: foreach($pages->find("parent=0|/navigation/") as $item) { ... The selector above is saying to find all pages that have no parent (i.e. "0") or have a parent called /navigation/. Both examples above return the same result. That won't work because the function only accepts one param (a selector). But because all the pages you are selecting there have the same parent, this would work: $pages->find("parent=/, name=navigation|page|item2");
×
×
  • Create New...