Search the Community
Showing results for 'runtime'.
-
Easily insert any complex HTML, Javascript or PHP output in your ProcessWire content by creating your own Hanna code tags. This module is based loosely on the WordPress Hana Code Insert plugin. A Hanna code tag looks like [[hello_world]]. A Hanna code tag with attributes looks like [[hello_world foo=bar" bar="foo]] using HTML style attributes or [[hello_world foo=bar, bar=foo]] using ProcessWire selector style attributes. After installing the module, you define your Hanna codes in Setup > Hanna Code. These Hanna codes that you define can then be entered within your body copy (or other text where you allow) and they will be replaced with the values defined or generated by your Hanna code. A common use case is to embed scripts or other bits of HTML or codes that would usually be stripped out by an editor like TinyMCE. However, Hanna codes can be more than just static snippets--they can be dynamic PHP or Javascript that outputs different things according to the request. PHP-based Hanna codes have access to the entire ProcessWire API. Hanna code accepts named attributes in the tag that can be passed as variables to PHP and Javascript Hanna codes. These attributes can be specified either in HTML attribute format or ProcessWire selector format. In either case, quotes should be used around the attribute value when the value contains whitespace or a comma. How to install Place the module files in /site/modules/TextformatterHannaCode/ In your admin, click Modules > Check for new modules Click install for TextformatterHannaCode Now to go Setup > Fields and locate the Textarea field(s) that you want to use Hanna codes with ("body" for instance). When editing the field, click the details tab, and select "Hanna Code" as the Textformatter. Save. Now go to Setup > Hanna Code and start defining your Hanna Codes! You may want to use one of the examples from this document to get started. Tag format Below is a Hanna code tag named hello_world with no attributes. If you pasted this into your body copy, you would get whatever the replacement value is that you defined. [[hello_world]] Below is a Hanna code tag named hello_world being passed attributes of foo, bar and foobar. If this were a PHP-based Hanna code, it would receive the variables $foo, $bar and $foobar: [[hello_world foo="bar" bar="foo" foobar="foo bar"]] Below is the same Hanna code tag as above, but with attributes more like ProcessWire selectors. You can use whatever format you prefer. Just note that unlike regular ProcessWire selectors, quotes (single or double) are required around any value that has whitespace. [[hello_world, foo=bar, bar=foo, foobar="foo bar"]] How to use Please make sure that you have completed the How to install section first. Then in your admin, go to Setup > Hanna Codes. Each Hanna code that you add has a type of either: Text/HTML, Javascript or PHP. The Text/HTML type is literally self explanatory in that your [[custom-tag]] is replaced with exactly the text you paste in. Anywhere that you type your [[custom-tag]] in your body copy will be replaced with exactly the static text you defined. More power opens up with the Javascript and/or PHP types of codes. These codes execute at runtime and thus can contain specific logic to produce different results. In fact, PHP Hanna codes have access to the entire ProcessWire API and are executed in the same manner as template files. Your PHP-based Hanna code should simply "echo" or "print" the replacement value. PHP example Create a new Hanna code with the name "children". Select "PHP" as the type. Paste in the following for the code: foreach($page->children as $child) { echo "<p><a href='$child->url'>$child->title</a>"; } Now go and edit a page that has children. In the body copy, enter [[children]] in the place where you want the output to appear. View the page, and you should see the rendered list of links to children. PHP example, part 2 Now lets take the above example further... Go back and edit your "children" Hanna code, as we are going to modify it to respond to a "parent" attribute. Change the code to this: if(isset($parent)) { // If $parent is an ID or path, lets convert it to a Page $parent = $pages->get($parent); } else { // otherwise lets assume the current page is the parent $parent = $page; } foreach($parent->children as $child) { echo "<p><a href='$child->url'>$child->title</a>"; } Go back and edit the page where you previously inserted the [[children]] tag, and change it to: [[children, parent=1]] (specifying the homepage) or [[children, parent=/path/to/some/parent/]] if you want to try something else. View the page and you should now see it showing the children of the homepage (or of another parent you specified). Please see the Javascript and PHP usage notes on the Hanna code entry screen. Security There are major security implications with a tool that will let you enter unfiltered text and code from your web browser. As a result, Hanna codes are meant for definition only by superusers and we recommend keeping it that way. Download Download the Hanna Code module from the ProcessWire modules page or from GitHub.
-
I understand the convenience, but I don't think having separate core downloads for PW depending on language (or other factors) is sustainable from a version or security standpoint, so would rather avoid that by always having the core download be directly from our GitHub. But having clear additional download links for language pack, docs, etc., to accompany the main download link would be great. Longer term, we'll have an automated download function that can bundle modules and language packages automatically at runtime.
-
I often thought about the ability to provide an easy way to install themes like in e.g. Wordpress. Reading the docs about template files, an idea came to me, how this might be possible: Use another layer between template, template files und the connection to the fields. The workflow would be: Declare the use of fields in the template file with their type When creating the template in admin, the declared fields are read in and the user could connect it to his own fields ProcessWire must handle the cloning of the reusable fields on runtime Does this sound serious to anyone? Or do you think this is not possible, achievable or desirable? I know it adds kind of a templating language and another level of abstraction, but for the goal of easy templating this may be not a major drawback, thinking of small business websites or blogs. Using this for reusable template themes, would bring a lot more attention from less php-skilled user and help spread ProcessWire in general. Designers could built their themes and an average user could use that to built his own site.
-
Enhanced debug mode The dev branch also includes an enhanced debug mode in the admin. It's all been cleaned up to look better and provide more info. It also includes a new section that outlines all of the runtime attached hooks currently active in the system:
- 143 replies
-
- 11
-
-
You have to consider XSS anywhere that the [untrusted] user can enter content that will be saved and echoed back to other users. In a default ProcessWire installation with no 3rd party modules, there aren't many places to consider this. The admin is designed for trusted users only. The comments module is the only thing that accepts and stores untrusted user input. It won't store markup in comments. It filters by stripping markup before storing a comment, and by entity encoding output when displaying a comment. Also consider that ProcessWire is designed to let you do what you want to do. If you want to create a text/textarea field that lets you enter script tags, then ProcessWire won't stop you. There are plenty of legitimate uses for such things. There simply isn't anywhere that an untrusted user can enter markup. But HTMLPurifier might have a place in your individual installation. If you are dealing with untrusted user input and allowing markup (HTML) then HTMLPurifier is essential. We have an HTMLPurifier module, ready to use. Content is validated and sanitized server-side, not client side. Though on text-based fields entered in the admin, we make no assumptions about what you are using them for. Even scripts are a legitimate use case (consider video embedding, etc.). Some Inputfields may have client-side validation built-in to do one thing or another (TinyMCE is an example). Though ProcessWire doesn't care about client side validation. What sanitization/validation takes place depends entirely upon the Fieldtype. From the admin side, the text-based fieldtypes are designed to contain any text, including any kind of markup. This is one reason why ProcessWire's admin is focused on trusted users only. While I don't recommend using PW's admin with untrusted users, there may be situations where you have "mostly" trusted users. In such cases, you may want to avoid things like rich text fields and focus on LML-based text formatters (safe ones, like Textile Restricted or BBCode) or even HTML Purifier. Our new CKEditor module actually does use the HTML Purifier for inline mode, since inline mode markup is not entity-encoded when presented in the admin. This is a consideration for any text fields that you don't want to support markup. Such fields might include your 'title' and 'summary' fields, but would exclude something like your 'body' field, which is designed specifically to contain markup. ProcessWire uses a type of modules called Textformatters. For any field that you want to have runtime output formatting, you can add an HTML Entities (or other types) Textformatter from Setup > Fields > [your field] > Details. This is only applicable to text-based fields. For entity encoding output yourself, use $sanitizer->entities($str). Generally you wouldn't ever use this on your managed content stored in PW. Instead, you would use it when echoing back something that the user entered, like search query: $q = $input->get->q; if($q) { $results = $pages->find("body%=" . $sanitizer->selectorValue($q)); echo "<h2>You searched for: " . $sanitizer->entities($q) . "</h2>"; if(count($results)) echo $results->render(); else echo "<p>Sorry, no results were found.</p>"; } ProcessWire's API does not use SQL queries, unless you choose to use the $db variable. So if you want to execute SQL queries, then you should follow best practices towards avoiding SQL injection. However, there are very few scenarios where any of us use SQL in developing websites or apps in ProcessWire, so it's generally a non-issue. What you do have to consider instead is selector injection, even if it's not nearly as potentially dangerous as SQL injection. So that's why we have the $sanitizer->selectorValue(); function. Note the use of it in the code segment above. Yes, all ProcessWire forms are CSRF protected.
-
Since the password has to be retained to send to the service at runtime, there's not much point in trying to hash it. And if you encrypt it, who are you ultimately trying to prevent from seeing it? I suppose it depends on what the password is ultimately used for. But I don't think you should try to over think it too much because we're talking about one password for [presumably] a non-critical service… not a database of passwords for multiple users that are likely spread out over multiple services. The problems from storing passwords in plain text or loosely hashed become real when you are dealing with user accounts at some scale beyond yourself. But in your case, in order for someone to get to that single password, they will have had to already compromised the system and broken into the database. So long as you aren't building a banking application or something high security, I think it's reasonable to just store the single password in the module config? After all, the database password itself is ultimately in plain text on all web servers too. But it is secure enough for all of us to trust our sites to. If you find that the password you need to store really is something that needs more security than the database itself, let me know and I may be able to suggest a couple things. As for the inputfield, try using InputfieldText with ->attr('type', 'password'); rather than InputfieldPassword. InputfieldPassword assumes that the password is not reversible, so it doesn't attempt to re-populate the field with it.
-
I think that file/image/page URLs in textareas are the only place where the issue can occur. It happens just because editors like TinyMCE are storing ready-to-output HTML. Everywhere else in ProcessWire (except cache files), everything is stored as references, so it doesn't matter where the site is running. Our eventual built-in solution will just ensure that any local URLs in textareas are always saved as if the site were running from root (via the sleepValue function), and prepend any subdirs to root paths at runtime (via the wakeupValue function).
-
With just a little more work you could put that function into a module that runs on page save which would then be ideal for your needs For example, something like this: <?php class SortPageTitles 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' => 'Sort Page Titles', // version: major, minor, revision, i.e. 100 = 1.0.0 'version' => 100, // summary is brief description of what this module is 'summary' => 'Sorts pages by title by second word if first word is "a, the, an" etc.', // Optional URL to more information about the module 'href' => 'http://processwire.com/talk/topic/3306-sorting-by-page-title-with-some-complexity/', // 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 sort certain pages if necessary $this->pages->addHookAfter('save', $this, 'sorttitles'); } /** * Hooks into the pages->save method and sorts pages with a certain template based on certain criteria * */ public function sorttitles($event) { $page = $event->arguments[0]; // Only run if the page we just saved has the "item" template if ($page->template == 'item') { $items = wire('pages')->find('template=item'); foreach ($items as $item) { if ($item->sort_title=="") { $item->setOutputFormatting(false); $new_title = (preg_match( "/^(the|a|an)\s/i", $item->title)) ? substr(strstr($item->title," "), 1) : $item->title; $item->sort_title = $new_title; $item->save(); } } } } } I've not tested it, but it's based on the helloworld module, so if you download it (attached) and put it in your /site/modules folder it should work for you, and hopefully be a good example of how easy it is to write modules too SortPageTitles.module
-
"Template" inPW is like a db table with all its fields. If you change the structure of the table you loose data... Except for fields that are the same in the template you change to. Changing a template of a page is not something you do all the time and only to give this page a different content or meaning. It's all about data here and not presentation. "Template File" is more of what you think of in MODX I think, and it's linked to the Template by it's filename. But you don't have to create a file for a template unless you want or need to have it renderable or viewable. The Template name also can be changed, thus mapping it to a different template file. As WillyC pointed out you can also leave the name (which often is used in template code as indentifier and you don't want to change that, unless developing) and define a alternative name that will be used to map to a template file. You can even have all your template share the same template file simply by setting this. A page using a template to build it's data model also isn't locked in to a certain presentation. You can change your presentation template on runtime or have some MVC like approach even. You could even build a simple system to be able to select from different "presentation modes" on a page using page field to build a selection. You make it up. There's many possibilities with how Template and Template Files work together and it allows for some great flexibility in a simple manner. I even after some time working with PW I found ways I didn't see or knew it was possible before, so enjoy the ride. Not sure this is of any help. Always struggle a little explaining this stuff.
-
Is 'timestamp' a field in your system, or one that you are assigning purely for runtime use?
-
Repeater Items - How to filter "ready items" - Bug?
SiNNuT replied to Luke Solar's topic in API & Templates
I think i can at least shed some light on where status 3073 is coming from in the DB. If you take a a look at Page.php (in the wire/core folder) you see this: /* * The following constant flags are specific to a Page's 'status' field. A page can have 1 or more flags using bitwise logic. * Status levels 1024 and above are excluded from search by the core. Status levels 16384 and above are runtime only and not * stored in the DB unless for logging or page history. * * If the under 1024 status flags are expanded in the future, it must be ensured that the combined value of the searchable flags * never exceeds 1024, otherwise issues in Pages::find() will need to be considered. * * The status levels 16384 and above can safely be changed as needed as they are runtime only. * */ const statusOn = 1; // base status for all pages const statusLocked = 4; // page locked for changes. Not enforced by the core, but checked by Process modules. const statusSystemID = 8; // page is for the system and may not be deleted or have it's id changed (everything else, okay) const statusSystem = 16; // page is for the system and may not be deleted or have it's id, name, template or parent changed const statusHidden = 1024; // page is excluded selector methods like $pages->find() and $page->children() unless status is specified, like "status&1" const statusUnpublished = 2048; // page is not published and is not renderable. const statusTrash = 8192; // page is in the trash const statusDeleted = 16384; // page is deleted (runtime only) const statusSystemOverride = 32768; // page is in a state where system flags may be overridden const statusCorrupted = 131072; // page was corrupted at runtime and is NOT saveable: see setFieldValue() and $outputFormatting. (runtime) const statusMax = 9999999; // number to use for max status comparisons, runtime only So i think 3073 comes from the combined values of statusOn, statusHidden and statusUnpublished. One would assume that pages, like readypages, with a code > 1024 would be excluded by default in finding and listing repeater items. I have looked through the FieldtypeRepeater code to see what's going on but this is beyond my php skills and knowledge of the core system. Maybe Ryan can comment on this. For the moment i think your filter solution seems fine. I you want to read more on status stuff i suggest you do a 'find in files' for 'status'. Tools like Sublime Text then give a nice overview of the search results. Not really slick docs..but good for learning :) -
Moving PW is creating problems with TinyMCE images
ryan replied to dreerr's topic in General Support
Does it swap in the actual directory at runtime? Meaning, if you click the "HTML" button in TinyMCE, do you see the correct URL rather than the relative one? Ultimately though, if they are storing a directory that is a placeholder it's the same problem in that the content lacks portability. But it at least sounds more portable. Handling directories for files/images is one thing, because the URL has common elements for all of them. But handling URLs to other pages is another matter. -
Moving PW is creating problems with TinyMCE images
ryan replied to dreerr's topic in General Support
The only way I know to do it is: Replace the static URL in the HTML before it gets saved to DB with a placeholder that gets resolved at runtime, like "{root-url}site/assets/files/123/file.jpg", where the {root-url} portion gets replaced with $config->urls->root at runtime. This is essentially what PageLinkAbstractor does. The only problem with this is that it creates a dependency of the text/html on the Fieldtype. If someone converts it to another field, or exports/imports to another system, etc., then it'll be broken. Maybe that's okay, but not ideal. -
populate global field with content from other fields
Soma replied to dreerr's topic in Getting Started
Welcome. Well I can't sleep since two years because of PW There's a concencate module by Ryan that would allow to combine fields to a runtime value. You can open title field and make in unglobal and remove it from the template you don't need. PW requires only a "name" which is like an id. Have fun and sleep well! -
Easiest Way to Include Assets in a top-level directory
Wanze replied to ruzel's topic in Getting Started
Or: $config->urls->assets For other runtime config urls: http://processwire.com/api/variables/config/- 2 replies
-
- 1
-
-
- codeigniter
- structure
-
(and 3 more)
Tagged with:
-
But then how to get the dynamic description into the static HTML from TinyMCE? It would have to be done at runtime with some kind of variable replacement. That's something I've been trying to avoid with TinyMCE, though don't have good enough reasons. One of my problems with the default dialogs in TinyMCE (and most other editors, for that matter) is that they present every possible option and only a developer would understand the vast majority of them. For instance, the distinction between a description and a title is going to confuse the non web-developers. I tend to think we should just make the behavior a checkbox in the module's configuration rather than the image editor. Another thing to consider is that we'd be duplicating an 'alt' to a 'title' for the benefit of javascript. When faced with that, it's technically more efficient to duplicate the attribute in javascript rather than in the markup, i.e. $(document).ready(function() { $(".gallery a > img").each(function() { // copy image 'alt' attribute to a 'title' attribute $(this).parent('a').attr('title', $(this).attr('alt')); } }); Do you mean add attributes? Not possible at present, just because our JS-side of things needs to know what the attributes are ahead of time (though some re-coding could solve that). But since these tags only accept a limited number of attributes anyway, I'm not sure we need that scalability here.
-
It is supported if you allow it in your field's TinyMCE settings. Setup > Fields > body > input > Advanced TinyMCE settings. It's not recommended though, because being able to enter things like iframes or scripts directly in body copy are considered bad security. It's better to use a runtime module like the TextformatterVideoEmbed module. If you are finding that doesn't work in your case, then give more details -- what is the URL you are pasting in? The first thing we'd want to do is make sure it is in the expected format. Next we'd make sure it is in it's own paragraph (i.e. has 1 blank line above and below it, if placed among other copy).
-
Make a magazine style homepage for Blog profile?
ryan replied to siulynot's topic in Getting Started
This is in fact simple to do, but it does require knowing how to put it together without a CMS first. So I would suggest getting your layout up and running as a functional mockup, outside of ProcessWire or any CMS (just HTML and CSS). You could also get by with using an existing HTML page that already does these things. Lets say you've now got that in a file called home.html. With a fresh install of ProcessWire (using the included profile, not the blog one), you'd copy your home.html file to /site/templates/home.php. Now view the homepage on your site. You should see your page. If some things are broken, then that is because the links to the CSS files and other resources have changed. Typically we place our CSS files in /site/templates/styles/ and our javascript files in /site/templates/scripts/. But you can place them wherever you want. Wherever you place them, you'll want to update your /site/templates/home.php file to reference them directly. So if you had a line at the top that said this: <link rel='stylesheet' type='text/css' href='css/style.css' /> Then you'd copy everything from that old 'css' directory into /site/templates/styles/, and then update your code to say this: <link rel='stylesheet' type='text/css' href='/site/templates/styles/style.css' /> Better yet, make it say this, so that it will continue working no matter where you happen to move your site: <link rel='stylesheet' type='text/css' href='<?=$config->urls->templates?>styles/style.css?>' /> With that line above, we're asking ProcessWire's $config variable for the URL to the templates directory. Since it determines that at runtime, it'll work whether your site is running from root or a subdirectory. Once you've got your homepage looking the same as it did outside of ProcessWire, then you are good to move forward with the next step, which is to make it dynamic. This short tutorial will get you started and give you what you need to know to proceed with your magazine style blog homepage. There are also more tutorials in the Wiki that you may want to check out after covering the basics.- 3 replies
-
- 3
-
-
- blogprofile
- magazine
-
(and 2 more)
Tagged with:
-
I don't think there's a way to reliably change system paths after bootstrap has occurred. I also don't recommend trying it, just because it seems like there's potential to break things by doing that, and it may work in some cases and not others. Ultimately it wasn't designed for runtime changes to system paths. It probably works from $config.php just because all that happens before bootstrap. It is however designed for runtime changes to template paths via the $template->filename = '...'; syntax.
-
You should be able to do this during runtime: $page->template->filename = '/path/to/file.php'; or $t = $templates->get('some-template'); $t->filename = '/path/to/file.php'; Note that /path/to/file.php must be a full path and filename relative to the server's file system, but PW won't accept it unless the file ultimately lives somewhere under your web root where PW is installed. Meaning, you can't do this: $t->filename = '/etc/passwd';
-
Is there an idiomatic way to handle global variables using the API?
ryan replied to bytesource's topic in API & Templates
It should be fine to use $config so long as you aren't overwriting some property already in use. Though you might also look at using $page to store your runtime/temporary properties, as $page is more associated as a runtime variable. -
How to add children to an instance of Page using the API?
Soma replied to bytesource's topic in API & Templates
Ok I thought there maybe a way to construct PageArray's. You can't alter the children built in property I think as it is in fact a method to retrieve the children from the DB on runtime using selectors $page->children($selector), but you could add a custom value on runtime memory and make it another PageArray. Then add some children to it. Since you can't use "children" just have to name it different for example "mychildren" and it works. You can also then use all the PageArray methods on them as ususal. You will just have still the children() and parent(), siblings() etc available but they would be in the original context of where the page originally is and not in your pseudo PageArray. Here's a test script might useful for many others too. // note just simple test pseudo code // base array object $pa = new PageArray(); // get some pages to work with $category = $pages->get("/templates/"); $about = $pages->get("/about/"); $home = $pages->get("/"); // add new PageArray property "mychildren" $category->mychildren = new PageArray(); // add other pages in $category->mychildren->add($about); $category->mychildren->add($home); // you can sort them $category->mychildren->sort("-created"); // add the $category to the base array $pa->add($category); // output the nested PageArray using mychildren echo "<ul>"; foreach($pa as $p){ echo "<li><a href='$p->url'>$p->title</a>"; echo "<ul>"; foreach($p->mychildren as $child){ echo "<li><a href='$child->url'>$child->title</a></li>"; } echo "</ul>"; } echo "</li></ul>"; Gives a nested list: Templates About 2 Home -
Hi John, This is a basic contact form that I've used in the past. I might help. Cheers Marty <?php /** * basic-form.php - Example of a simple contact form in ProcessWire * */ // set this to the email address you want to send to (or pull from a PW field) $emailTo = 'email@site.com'; // or if not set, we'll just email the default superuser if(empty($emailTo)) $emailTo = $users->get($config->superUserPageID)->email; // set and sanitize our form field values $form = array( 'fullname' => $sanitizer->text($input->post->fullname), 'email' => $sanitizer->email($input->post->email), 'comments' => $sanitizer->textarea($input->post->comments), ); // initialize runtime vars $sent = false; $error = ''; // check if the form was submitted if($input->post->submit) { // determine if any fields were ommitted or didn't validate foreach($form as $key => $value) { if(empty($value)) $error = "<p class='form-error'>Please completed all fields.</p>"; } // if no errors, email the form results if(!$error) { $subject = "Message from your website contact form"; $message = ''; foreach($form as $key => $value) $message .= "$key: $value\n"; mail($emailTo, $subject, $message, "From: $form[email]"); $sent = true; } } if($sent) { echo "<p>Thank you, your message has been sent.</p>"; // or pull from a PW field } else { // encode values for placement in markup foreach($form as $key => $value) { $form[$key] = htmlentities($value, ENT_QUOTES, "UTF-8"); } // output the form echo <<< _OUT $error <form action="./" method="post"> <label for="fullname">Your name*</label> <input type="text" id="fullname" name="fullname" size="60" value="$form[fullname]" /> <label for="email">Your email*</label> <input type="email" name="email" id="email" size="60" value="$form[email]" /> <label for="comments">Message*</label> <textarea id="comments" name="comments" rows="5" cols="43">$form[comments]</textarea> <input type="submit" name="submit" value="Submit" /> <p class="form-required">* required fields</p> </form> _OUT; } ?>
-
Edit well if there not too many projects you could try and evaluate the dates and store them on runtime to sort by that value afterwards when you loop them out. $pa = $pages->find("template=project"); if(count($pa)){ foreach($pa as $p){ if(!$p->numChildren) continue; // no assignments // store a temporary value to the project page $p->tmp_date = $p->children("sort=-due_date")->first()->due_date; } // output the projects foreach($pa->sort("-tmp_date") as $p){ echo "<li>$p->title</li>"; if(!$p->numChildren) continue; foreach($p->children("sort=-due_date") as $a){ // output assignments } } } This will work well if you don't have thousands of pages. The module approach would be the more efficient and scaleable.
-
FieldtypeMapMarker doesn't implement a getMatchQuery method, which is required in order to support any operators that don't exist in MySQL. For instance, MySQL knows what "=" and ">" are, but it doesn't know what "%=" is. So I'm guessing you are getting a "Operator '%=' is not implemented in FieldtypeMapMarker" error message. The second issue is that there isn't actually a field named 'address' in the DB, as this fieldtype represents it with the default 'data' field. Meaning you would just refer to it as "map_marker" (or whatever you field name is) rather than "map_marker.address". But the truth is, since we're using 'address' as in this Fieldtype at runtime, we really should allow it for queries too. Try adding this to your FieldtypeMapMarker.module, which should solve both issues: public function getMatchQuery($query, $table, $subfield, $operator, $value) { if(!$subfield || $subfield == 'address') $subfield = 'data'; if($operator != '%=') return parent::getMatchQuery($query, $table, $subfield, $operator, $value); $ft = new DatabaseQuerySelectFulltext($query); $ft->match($table, $subfield, $operator, $value); return $query; } Let me know if that works out for you, and I'll add it to mine too. I'm also going to add a fulltext index to the 'data' field so that we can use other partial match operators.