Jump to content
peterb

$pages->get from a Custom Process module

Recommended Posts

Hey,

I am working on making an XML generator module, and duplicated the ProcessField module as a starting point. I need to loop threw the pages of the site.

Unfortunately, I can't seem to use "get" (to get pages and loop threw children pages) from within my new module:

$homepage = $pages->get("PAGE-NAME");

$sections = $homepage->children;

foreach($sections as $section) {

Do I need to include something in my module? Or is the syntax different when working in the core?

Thanks, Peter

Call to a member function get() on a non-object (line 85 of /deploy/pw/wire/modules/Process/ProcessXml/ProcessXml.module)

Share this post


Link to post
Share on other sites

looks interesting...maybe you can share your module..  ;D

For making this i'm using a template with the code inside, but everytime i update the site i need to call that page for generating sitemap or other xml feed.

Share this post


Link to post
Share on other sites

I just have 1 other issue moving the code into a module.. imagefield->url gives a path on a template page, but not in the module???

foreach($sections as $section) {

$section->imagefield->url;

$section->imagefield returns: Pageimages(1)

actually, I wonder if this is a bug, as it provides the path & file name in the templated version, but in the module version, only the path, not file name?

Once i have this sorted, I will post

Share this post


Link to post
Share on other sites

The reason it's not working is because a page's output formatting is usually only turned on for template use, and off elsewhere. Technically, all image fields can contain multiple images, but ProcessWire automatically reduces them for templates when you want them to be just one (likewise for Page references). It doesn't do this for the rest of the API just so that the same bits of code can always be used regardless of the image settings. Whereas in your templates, it lets you choose.

Here's a couple of options to make it work in your instance:

$url = $section->imagefield->first()->url;

Or

$section->setOutputFormatting(true);
$url = $section->imagefield->url;
$section->setOutputFormatting(false); 

Share this post


Link to post
Share on other sites

So here is a basic xml generator. It references fields specific to my site, but you can easily change the field references to generate the type of xml you want.

Ryan, if you give me some pointers on looping threw all the fields in a template, and checking there type, I could probably make this more generic to any structure. In the mean time here is what I did to get it working quickly.

1. place "ProcessXml" folder in the "modules->process" folder

2. go to modules and install the module

3. create a page of type "admin" as a child of the Admin page

4. select "ProcessXml" from the Process pull down.

As a child of Admin, The page appears in the upper right navigation.

That's it... again, you will need to edit the fields in this version to reference your own.

- Peter

ProcessXml.zip

Share this post


Link to post
Share on other sites

Hi Peter,

I'm glad to see you extended a Process module and used it in the Admin. I think you are the first to do this. To iterate the fields in a template, you would do:

<?php
foreach($template->fields as $field) {
    echo "<li>{$field->name} is a field of type {$field->type}</li>";
}

In the top of your .module file, I recommend adding one or more lines indicating that you are the author and any related contact info (website, etc.).

Likewise, in your getModuleInfo() function, I recommend changing it to:

public static function getModuleInfo() {
    return array(
        'title' => 'Export XML for Flash',
        'version' => 100,
        'summary' => 'A module to export XML for flash by PeterB',
        );
}

There is still a lot of stuff left in your module from the one you adapted it from, so you can remove lots of unnecessary code, which I'll cover below.

Remove your init() function, you don't need it or anything that's in it.

You don't need the code that is in your execute() function. You can change your execute() function to be just:

public function ___execute() {
    return "<p><a href='./export'>Export XML for Flash</a></p>"; 
}

In your executeExport function: It's not safe to assume that the assets dir is "../assets/". Instead, you should set your filename like this:

$myFile = $this->config->paths->assets . "website.xml";

In general purpose situations, it's probably not safe to find your homepage with a selector like $pages->get("title=Home"). That's because it's feasible that other pages could have that title. I would instead suggest using the homepage's path, like $pages->get("/");  There are also other instances where you are retrieving a page with it's title field. If that's something that you need to do, I would suggest instead using the page's path/url or ID, as those are the only two things guaranteed to be unique about any given page. For pages with the same parent, you can also assume that it's "name" will be unique among it's siblings.

On this line (119):

$subpage = $this->pages->get("title=$section->title"); 
$stories = $subpage->children;

Is that necessary? On briefly looking at the code, it looks to me like this would achieve the same thing: (?)

$stories = $section->children; 

In your code, you are referring to a field called "page_type". Since this is essentially what a template is, you may want to see if using a Template for a page type would suite your needs (it's possible it may not).

At the end of your executeExport function, you have the following:

$out = $this->showListFilters || $this->config->advanced ? $this->renderListFilters() : '';
$table = $this->modules->get("MarkupAdminDataTable");
$table->action(array('Export XML for Flash' => './export'));
$table->message("Exported!"); 
return $out . $table->render();

I believe you can delete all of that and replace it with:

$this->message("Exported!");
return $this->execute();

Also, you can delete everything after your executeExport() function, as they are functions specific to the Fields module, and ConfigurableModule interface, and they aren't used here.

Lastly, go back to the beginning of the file and change your class definition to be just:

class ProcessExportFlashXml extends Process {

You want to make sure you remove the "implements ConfigurableModule" since it will throw an error if you don't (since I told you to remove everything below your executeExport function.

Share this post


Link to post
Share on other sites

Wow, Thank you Ryan for your comments... I will incorporate  & re-post. (please excuse my crude coding) This might also be a good underpinning for a search engine xml sitemap generator....

Peter

Share this post


Link to post
Share on other sites

attached is a cleaner version of a generic XML generator. It only goes 1 level deep beyond root, and does not break out elements that have multiple's items (like pages, or images).

That said, it is fairly clean, and extend-able for anyone interested.

I'm sure there is a cleaner way to recursively go indefinitely threw all the children pages... but I can't get my mind around it right now....

ProcessXmlGeneric.zip

Share this post


Link to post
Share on other sites

PeterB,

Looks great!

If you want, you can also delete this part at the top of the class, since those don't appear to be variables that you are using:

protected $form; 
protected $field;
protected $id; 

If you want to make it traverse all levels, making it recursive is easier than you might think. Here's a site map example, which would probably be the same approach you'd want (at least from the recursion aspect):

http://processwire.com/api/include/

Also, I wanted to inquire about the context of your individual use. Since it exports data for a Flash site, it seems like you would need to run this Process every time you made an update that you wanted reflected in the flash site? If you wanted it to be dynamic, you could take the contents of your executeExport function and put it into a template and have it echo to the screen (rather than writing to a file). Everything you've written still applies in this case. You would create a new page that uses that template, and name it website.xml. Also, you may want to turn off the trailing URL slash in your template settings, so that it doesn't convert it to yoursite.com/website.xml/".

Start your template with a header function like this, so that the client reads it as XML:

<?php
header("Content-Type: text/xml");
// followed by the contents of your executeExport function

This is just an idea on how to expand the utility of the code you've created, but it may or may not be applicable in your case.

Share this post


Link to post
Share on other sites

cool! with that I will  try to improve the generic module further...

I am purposely generating the xml to a file, as it will be pretty big, and I figured it would load faster that way. Here is a link to the dev site, although the images have yet to be populated (there will be many):

http://s118962.gridserver.com

There is also and ipad/jquery mobile version of the site, and that does grab output dynamically with ajax calls. As it just pulls one section at a time, I'm guessing won't take too long.

Share this post


Link to post
Share on other sites

Wow, awesome site!! Please let me know when this is "officially" online so that I can add it to the "sites powered by ProcessWire" page (if you don't mind -- I would be proud to link to this).

You are right that it will load faster directly from a flat XML file. But if you create the XML output as a template, and turn on template caching then the difference would be negligible in the majority of cases.

Where you'll have an advantage with your current approach is if the size of the XML output becomes so large that it can't all be held in memory at once... then you would have to write it to a file as you are doing now. However, I think you'd have to be in the thousands of pages before that would become the case. But if you don't mind recreating the XML from the admin every time you need to update the site, then it doesn't matter which approach you use. And your current approach does give you a potential nice workflow where you can make several changes before actually publishing them.

Share this post


Link to post
Share on other sites

thanks, and I certainly shall let you know. the template caching thing sounds interesting, I will check it out.

Share this post


Link to post
Share on other sites

If you turn on template caching (Setup > Templates > Your Template > Advanced > Caching), I would set it to at least 1 hour (3600), and up to 1 day (86400). Just note that template caching is always turned off for you (only) when you are logged in, so you won't observe the effect of template caching unless you logout, or try from another browser/computer that isn't logged in.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...