Jump to content
Stikki

Pages2JSON

Recommended Posts

Where do i get?

From here: https://github.com/IDT-media/Pages2JSON (thanks to LostKobrakai for "bug" report)

What does this do?

Simply adds method toJSON() to Page and PageArray elements, is capable to converting image and file arrays to URL containers, travels recursively all objects before outputs actual JSON.

How to use?

Simply install this module, configure data you want it to export in JSON result (similar to Ryan's ServicePages, thanks btw used some of ur code here). in templates or anywhere you need JSON output, call: $page->toJSON(); or $pages->toJSON();

Live example with template: search.php

/*****************************************************************
 Do search
*****************************************************************/

$term = $sanitizer->text($input->term);
$results = array();

if($term) {

    $input->whitelist('term', $term);

    $term = $sanitizer->selectorValue($term);
    
    $limit = (int)$input->limit;
    $limit = $limit ? $limit : 50;
    $limit = $sanitizer->selectorValue($limit);     
    
    $selector = "title|categories|content*=$term, limit=$limit, template=default|product";

    // Prevent admin pages.
    if($user->isLoggedin()) $selector .= ", has_parent!=2";

    // Find pages that match the selector
    $results = $pages->find($selector);
}

/*****************************************************************
 Output
*****************************************************************/

header("Content-type: application/json");
echo $results->toJSON();
exit();

Customizing values:

if(wire('config')->ajax) {
    wire()->addHookAfter('Pages2JSON::getValue', function($event) {

        $value = $event->arguments(0);
    
        if(!is_object($value))
            return;
        
        $page = wire('page');
        if($page->template == 'thumbs' && $value->className == 'Pageimage')
            $event->return = $value->size(28,28)->url;
        
    });
}

Here i swap URL of all Pageimage objects in JSON response to match thumbs. Simple hu?

Edited by Nico Knoll
Added the "module" tag and removed it from title.
  • Like 10

Share this post


Link to post
Share on other sites

A link to your module would make it easier for people to use it :)

Heyyy, awesome IDEA!

Share this post


Link to post
Share on other sites

Hi. thx for a module :), i wonder is there a way to include translation fields as well. Textarea (default) + other languages, and so on.

Share this post


Link to post
Share on other sites

Hi. thx for a module :), i wonder is there a way to include translation fields as well. Textarea (default) + other languages, and so on.

Well, it just reads attached fields and outputs data as fields provide it in that context, i didn't test with MLE fields, but i would assume output is in language that is currently in use as this is purely just JSON parser, it doesn't change data anyhow by default. If this behavior ain't correct in your opinion, please open ticket to Github and i'll take a look.

Share this post


Link to post
Share on other sites

Hello Stikki.

   Is there a way to get the title of images or files?

By the way, thank you for the fantastic module.

Share this post


Link to post
Share on other sites

You can try override default behavior:

wire()->addHookAfter('Pages2JSON::getValue', function($event) {

	$value = $event->arguments(0);

	if(!is_object($value))
		return;
	
	if($value->className == 'Pageimage') {
	
		$obj = new stdClass;
		$obj->url 		= $value->url;
		$obj->description 	= $value->description;

		$event->return = $obj;		
	}	
});

Didn't test this btw, you could let ppl know if it works, thanks.

  • Like 1

Share this post


Link to post
Share on other sites

I added in line 138 of the module those lines to get lat, lng, zoom, address and descriptions of images and files

protected function ___getValue($value)
{
if(!is_object($value))
return $value;

switch($value->className) {

case 'Page':
return $this->toPage($value);

case 'Pageimage':
case 'Pagefile':
return array("url"=>$value->url, "description"=>$value->description);

case 'Pagefiles':
case 'Pageimages':
case 'PageArray':
case 'WireArray':
return $this->toArray($value);
case 'MapMarker':
return array("lat"=>$value->lat, "lng"=>$value->lng, "zoom"=>$value->zoom, "address"=>$value->address);
}

return null;
}

Share this post


Link to post
Share on other sites

I added in line 138 of the module those lines to get lat, lng, zoom  and address

case 'MapMarker':
  return array("lat"=>$value->lat, "lng"=>$value->lng, "zoom"=>$value->zoom, "address"=>$value->address);

Was MapMarker currently core module? If so i'll add it then.

Share this post


Link to post
Share on other sites

Okey, i'll consider it but since it's not currently core module use own custom version of this or alter it by hooking, if more people vote for MapMarker it gets in more likely, thanks for awesome documentation tho.

However i'll change file and image files to support description by default just like you suggested.

Those who already use this module, notice that this will break your JSON streams when it comes to files and images.

  • Like 1

Share this post


Link to post
Share on other sites

New version out (0.0.2)

  • Allows user define global data output in module options + individual data based on template.
  • Added forum user Manol's feature request regarding PageImage and PageFile fields.
  • Like 2

Share this post


Link to post
Share on other sites

I just installed your module in the latest 3.0.7 dev. It works as expected when accessing a page as guest, but when I'm logged in as admin, I get JSON output from richtext-fields like this:

summary: "<div id=pw-edit-2 class='pw-edit pw-edit-InputfieldTextarea' data-name=summary data-page=1001 style='position:relative'><div class=pw-edit-orig>This is a placeholder page with two child pages to serve as an example. </div><div class=pw-edit-copy id=pw-editor-summary-1001 style='display:none;-webkit-user-select:text;user-select:text;' contenteditable>This is a placeholder page with two child pages to serve as an example. </div></div>",

I don't remember this module doing this in 2.x versions... if you get the chance, could you find out what's causing this?

Oh, and also: fieldtype Matrix Repeater is completely ignored. Is that fieldtype too complex to render as JSON?

Share this post


Link to post
Share on other sites

Howdy dragan,

Will look into this matter when i start testing with 3.x series, haven't touched that yet.

And what comes to Matrix repeater, it only works with standard fields currently, special fields would require own checkpoint, and since haven't used Matrix repeater myself yet, there is no check for that. You can always hook to getValue() method and implement you own check without hacking module.

Share this post


Link to post
Share on other sites

The markup seems to be by the frontend editing feature, which explains why it's only for logged in users. The internals of matrix repeaters are quite complex and will probably need a special implementation, because it's using a single template for all the different types of data (which doesn't make sense in my mind, but so be it).

Share this post


Link to post
Share on other sites

OK, turns out the Front-End Page Editor module is injecting PW-backend specific stuff (all over the place) - in the HTML source too, not just when doing echo $page->body etc.

For now (for 3.x tests) I'll use something like this, when I need JSON output:

if($input->urlSegment1 === 'json') {
	header("Content-type: application/json");

	$ar['title'] 		= $page->title;
	$ar['body'] 		= $page->body;
	$ar['summary'] 		= $page->summary;
	$ar['created'] 		= $page->created;
	$ar['modified'] 	= $page->modified;

        // new way how to render fields (optional) - with "baby" templates for each field
	$ar['matrix_test'] 	= $page->render('matrix_test');

	$output = json_encode($ar);
	echo $output;
	exit();
}

  • Like 1

Share this post


Link to post
Share on other sites

So this is turning another Drupal? Shame.

https://processwire.com/blog/posts/front-end-editing-now-in-processwire-3.0-alpha-4/

"All of the front-end editing features are provided by a module included with the ProcessWire 3.0 core called PageFrontEdit. Once this module is installed, you can use any of the above options. The module is not installed by default."

So it is not turning Drupal.

  • Like 2

Share this post


Link to post
Share on other sites

Great module! It came in handy and saved me a lot of work from building my own JSON. Thanks!

I do need to modify the output and I am struggling to understand how to do so.  By default, the http host is not appended to any url and I need that for this particular project. I figured this would be a simple fix, but can't find where to alter that particular value. If you reference the json below, you will see the file node with the url displayed. There are two other nodes that I need to alter the same. Images and video. Any tips are appreciated.

//original code
$items = $pages->findMany("template=item"); 
echo $items->toJSON();
{
        "pages": [
            {
                "id": 1033,
                "title": "Page 1"
            },
            {
                "id": 1116,
                "title": "Page 2"
            }
        ],
        "categories": [
            {
                "id": 1031,
                "title": "Brochures"
            },
            {
                "id": 1036,
                "title": "Photos"
            }
        ],
        "file": {
            "description": "File 1",
            "url": "/site/assets/files/1039/file1.pdf"
        },
        "id": 1039,
        "images": [],
        "modified": 1490728945,
        "title": "Test Document 1",
        "type": {
            "name": "file"
        }
    },

 

Share this post


Link to post
Share on other sites

So I figured it out and here is my complete code if it would help anyone else. 

//get the pages you want
$items = $pages->findMany("template=item"); 

wire()->addHookAfter('Pages2JSON::getValue', function($event) {
	//get the host
   	$host = wire('config')->httpHost;
    $value = $event->arguments(0);
    if(!is_object($value))
        return;
	//check if field is an image, images or file type
    if($value->className == 'Pageimage' || $value->className == 'Pagefile') {
		//append the host to those values
       $urls = array("url" => $host . $value->url, "description" => $value->description);
       $event->return = $urls;
    }
        
});

header('Access-Control-Allow-Origin: *');
header('Content-Type: application/json');
echo $items->toJSON();
exit();

Thanks again for the great plugin.

Edited by RyanJ
Updated code to retain key values and description.
  • Like 2

Share this post


Link to post
Share on other sites

I am trying to get this to work with Kongondo's Media Manager Module. Unfortunately I can't get the url/description to return. I have modified the plugin with no luck, It still returns null.  Anyone had any luck with these two?

Share this post


Link to post
Share on other sites

I'm trying out this module as well. I was able to add support for SelectableOption and SelectableOptionArray.

Then I ran into an infinite loop. 

I'm using @Robin S's ConnectPages to connect some of my templates, and it would go on until it reaches max exec time. For example:

Jane (Page)
	- Progenitors (Page Multiple)
		- John (Page)

John (Page)
	- Progeny (Page Multiple)
		- Jane (Page)

 

So when it's iterating over Jane's fields, it would come into it's progenitor field which is a multi page field, and would start listing John's fields. In there it would come into John's progeny field and would start listing Jane's data again, and would find John... and so on..

Would anyone have an idea on how to stop the loop from going over and over, or a way to stop the recursion from going too deep? I'd appreciate any help. Thanks.

 

Share this post


Link to post
Share on other sites
2 hours ago, Alxndre' said:

Would anyone have an idea on how to stop the loop from going over and over, or a way to stop the recursion from going too deep?

When looping over the pages in a Page field, set some property to the Page object to serve as an indicator that the page has been processed. Then put your code that processes the pages inside an if() condition that checks that the property has not already been set. So something like:

if(!$page->processed) {
    // do your processing here
    // ...
    $page->processed = true;
}

 

  • Like 1

Share this post


Link to post
Share on other sites

Thanks Robin. I was able to make it work with some modifications by just returning the ids (instead of the whole page) for pagefields.

Another concern I have is that the json response that I get has [] brackets at the end.

Sample:

{
  "id":1058,
  "firstname":"Julie Ann Mae",
  "sex":[1],
  "birthdate":768931200,
  "nationality":[93],
  "guardians":[1059,1060]
}[]

Is this normal behavior? I can't figure out where it gets inserted. It's been returning that from the beginning.

 

EDIT: I got it. It was totally my fault. :) Thanks

Share this post


Link to post
Share on other sites

I am trying to make this module work, but I am stuck with this message:

Uncaught ArgumentCountError: Too few arguments to function Pages2JSON::___getFields(), 0 passed in …/site/modules/Pages2JSON/Pages2JSON.module on line 182

What did I make wrong?

  $term = "update";
  $results = array();
  $limit = 3;
  $selector = "title*=$term, limit=$limit, template=entry";
  $results = $pages->find($selector);

  header("Content-type: application/json");
  echo $results->toJSON();
  exit();

 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By bernhard
      --- Please use RockFinder3 ---
    • By MoritzLost
      Cacheable Placeholders
      This module allows you to have pieces of dynamic content inside cached output. This aims to solve the common problem of having a mostly cacheable site, but with pieces of dynamic output here and there.  Consider this simple example, where you want to output a custom greeting to the current user:
      <h1>Good morning, <?= ucfirst($user->name) ?></h1> This snippet means you can't use the template cache (at least for logged-in users), because each user has a different name. Even if 99% of your output is static, you can only cache the pieces that you know won't include this personal greeting. A more common example would be CSRF tokens for HTML forms - those need to be unique by definition, so you can't cache the form wholesale.
      This module solves this problem by introducing cacheable placeholders - small placeholder tokens that get replaced during every request. The replacement is done inside a Page::render hook so it runs during every request, even if the response is served from the template cache. So you can use something like this:
      <h1>Good morning, {{{greeting}}}</h1> Replacement tokens are defined with a callback function that produces the appropriate output and added to the module through a simple hook:
      // site/ready.php wire()->addHookAfter('CachePlaceholders::getTokens', function (HookEvent $e) { $tokens = $e->return; $tokens['greeting'] = [ 'callback' => function (array $tokenData) { return ucfirst(wire('user')->name); } ]; $e->return = $tokens; }); Tokens can also include parameters that are parsed and passed to the callback function. There are more fully annotated examples and step-by-step instructions in the README on Github!
      Features
      A simple and fast token parser that calls the appropriate callback and runs automatically. Tokens may include multiple named or positional parameters, as well as multi-value parameters. A manual mode that allows you to replace tokens in custom pieces of cached content (useful if you're using the $cache API). Some built-in tokens for common use-cases: CSRF-Tokens, replacing values from superglobals and producing random hexadecimal strings. The token format is completely customizable, all delimiters can be changed to avoid collisions with existing tag parsers or template languages. Links
      Github Repository & documentation Module directory (pending approval) If you are interested in learning more, the README is very extensive, with more usage examples, code samples and usage instructions!
    • By Craig
      I've been using Fathom Analytics for a while now and on a growing number of sites, so thought it was about time there was a PW module for it.
      WayFathomAnalytics
      WayFathomAnalytics is a group of modules which will allow you to view your Fathom Analytics dashboard in the PW admin panel and (optionally) automatically add and configure the tracking code on front-end pages.
      Links
      GitHub Readme & documentation Download Zip Modules directory Module settings screenshot What is Fathom Analytics?
      Fathom Analytics is a simple, privacy-focused website analytics tool for bloggers and businesses.

      Stop scrolling through pages of reports and collecting gobs of personal data about your visitors, both of which you probably don't need. Fathom is a simple and private website analytics platform that lets you focus on what's important: your business.
      Privacy focused Fast-loading dashboards, all data is on a single screen Easy to get what you need, no training required Unlimited email reports Private or public dashboard sharing Cookie notices not required (it doesn't use cookies or collect personal data) Displays: top content, top referrers, top goals and more
    • By daniels
      This is a lightweight alternative to other newsletter & newsletter-subscription modules.
      You can find the Module in the Modules directory and on Github
      It can subscribe, update, unsubscribe & delete a user in a list in Mailchimp with MailChimp API 3.0. It does not provide any forms or validation, so you can feel free to use your own. To protect your users, it does not save any user data in logs or sends them to an admin.
      This module fits your needs if you...
      ...use Mailchimp as your newsletter / email-automation tool ...want to let users subscribe to your newsletter on your website ...want to use your own form, validation and messages (with or without the wire forms) ...don't want any personal user data saved in any way in your ProcessWire environment (cf. EU data regulation terms) ...like to subscribe, update, unsubscribe or delete users to/from different lists ...like the Mailchimp UI for creating / sending / reviewing email campaigns *I have only tested it with PHP 7.x so far, so use on owners risk
      EDIT:
      Since 0.0.4, instructions and changelog can be found in the README only. You can find it here  🙂
      If you have questions or like to contribute, just post a reply or create an issue or pr on github, thanks!
    • By MoritzLost
      Sorry for the convoluted title. I have a problem with Process modules that define a custom page using the page key through getModuleInfo (as demonstrated in this excellent tutorial by @bernhard). Those pages are created automatically when the module is installed. The problem is that the title of the page only gets set in the current language. That's not a problem if the current language (language of the superuser who is installing the module) is the default language; if it isn't, the Process page is missing a title in the default language. This has the very awkward effect that a user using the backend in the default language (or any other language) will see an empty entry in the setup menu:

      This screenshot comes from my Cache Control module which includes a Process page. Now I realize the description sounds obscure, but for us it's a common setup: We a multiple bilingual sites where the default language is German and the second language is English. While the clients use the CMS in German, as a developer I prefer the English interface, so whenever I install a Process module I get this problem.
      As a module author, is there a way to handle this situation? I guess it would be possible to use post-installation hooks or create the pages manually, but I very much prefer the declarative approach. The page title is already translatable (through the __ function), but of course at the time of installation there is no translation, and as far as I'm aware it's not possible to ship translations with a module so they are used automatically. Could this situation be handled better in the core? I would prefer if the module installation process would always set the title of the Process page in the default language, instead of the language of the current user.
×
×
  • Create New...