Leaderboard
Popular Content
Showing content with the highest reputation on 10/23/2016 in all areas
-
This is a single page for an old farmhouse deep in the Black Forest, which you can rent for seminars or as a weekend getaway. When visiting the site first you can slide through three full sized background images. To access the main content you can either click the logo, the toggle icon or the container. The content mostly consists of accordion elements, but in the section nächtigen there is also an calendar (using the new Google Calendar Markup module) and an reservation form included. www.langenbachhof.de Modules used: ProCache PageTable Extended Google Client API Google Calendar Markup Markup Sitemap XML Tracy Debugger Email Obfuscation Regards, Andreas2 points
-
I see, thanks. Many tweaks work only on screens wider than 960px and below that some default values may kick in. Here the #title overlaps with the buttons as it is not an inline-block element. The link color comes from the default link color from the theme. I've overriden only the default state to keep the original hover color but this may result in such color combinations. I think I'll keep the white text color and use underline instead. Edit: done (v0.8.4)2 points
-
In this tutorial I will cover how to use clsource's REST Helper classes to create a RESTful API endpoint within a PW-powered site and how to connect to it from the outside world with a REST client. This is a quite lengthy tutorial. If you follow all along and make it through to the end, you should get both, a working REST API with ProcessWire and hopefully some more basic understanding how these APIs work. As always with PW, there are many ways you could do this. My way of implementing it and the code examples are loosely based on a real world project that I am working on. Also, this is the first tutorial I am writing, so please bear with me if my instructions and examples are not that clear to understand. And please let me know if something is missing or could be made more clear. The steps covered: create templates and pages in the PW backend to get an API endpoint (an URL where the API can be accessed at) copy and save the REST Helper classes to your site create a template file and write some logic to receive and process data through our endpoint and send data back to the REST client test the whole setup with a Browser REST Client Addon I will not go into fundamentals and technical details on how RESTful APis are supposed to work. I assume that you have already read up on that and have a basic understanding of the principles behind that technology. Some helpful resources to brush up your knowledge: https://en.wikipedia.org/wiki/Representational_state_transfer http://www.restapitutorial.com/lessons/whatisrest.html The complete pages.php template is attached to this post for copy/paste. Lets get started. 1. create templates and pages in the PW backend to get an API endpoint (an URL where the API can be accessed) First we need to create some templates and pages in the PW backend to make our REST API accessible from the outside world through an URL (API endpoint). In my example this URL will be: https://mysite.dev/api/pages/ Note the "https" part. While this is not mandatory, I strongly recommend having your API endpoint use the https protocol, for security reasons. Further down in step 3 we will use this URL to create new pages / update and get data of existing pages. Go to your PW test site admin and: create 2 new templates: one is called "api", the other one "pages". For a start, they both have only a title field assigned. Just create the templates. We will create the corresponding files later, when we need them. enable "allow URL segments" for the "pages" template. We will need this later to access data sent by the requests from the client. in the Files tab of the "pages" template check "Disable automatic append of file: _main.php" create a new page under the home page with title, name and template "api" and set it to hidden create a child page for the "api" page with title, name and template "pages" The pagetree should look somewhat like this: Ok, now we're all set up for creating our API endpoint. If you browse to https://mysite.dev/api/pages/ you will most likely get a 404 error or will be redirected to your home page as we do not have a template file yet for the "pages" template. We will add that later in step 3. 2. copy and save the REST Helper classes to your site I have the REST Helper class sitting in site/templates/inc/Rest.php and include it from there. You could save it in any other location within your site/templates folder. I forked clsource's original code to add basic HTTP authentication support. Click here to open my raw gist, copy the contents and save them to /site/templates/inc/Rest.php In the next step we will include this file to make the classes "Rest" and "Request" available to our template file. 3. create a template file and write some logic to receive and process data through our endpoint and send data back to the client This will be the longest and most complex part of the tutorial. But I will try to present it in small, easy to follow chunks. Since we access our API at https://mysite.dev/api/pages/, we need to create a template file called "pages.php" for our "pages" template and save it to /site/templates/pages.php. Go ahead and create this file (if you're lazy, copy the attached file). Now right at the top of pages.php, we start with <?php require_once "./inc/Rest.php"; to include the REST Helper classes. Next, we initialize some variables that we will keep using later on // set vars with the default output $statuscode = 200; $response = []; $header = Rest\Header::mimeType('json'); 3.1 retrieve data with a GET request Now that we have the basics set up, we will next create the code for handling the easiest request type, a GET request. With the GET request we will ask the API to return data for an existing page. To let the API know which page it should return data for, we need to send the page id along with our request. I am attaching the page id as an url segment to the API endpoint. So the URL that the client will use to retrieve data for a page will look like: https://mysite.dev/api/pages/1234 where 1234 is the unique page id. Add following code to pages.php // if we have an urlsegment and it is a numeric string we get data from or update an existing page: handle GET and PUT requests if($input->urlSegment1 && is_numeric($input->urlSegment1)) { $pageId = $input->urlSegment1; // GET request: get data from existing page if(Rest\Request::is('get')) { // get the page for given Id $p = $pages->get($pageId); if($p->id) { $pdata = ["id" => $pageId]; // array for storing page data with added page id $p->of(false); // set output formatting to false before retrieving page data // loop through the page fields and add their names and values to $pdata array foreach($p->template->fieldgroup as $field) { if($field->type instanceof FieldtypeFieldsetOpen) continue; $value = $p->get($field->name); $pdata[$field->name] = $field->type->sleepValue($p, $field, $value); } $response = $pdata; } else { //page does not exist $response["error"] = "The page does not exist"; $statuscode = 404; // Not Found (see /site/templates/inc/Rest.php) } } } else { // no url segment: handle POST requests } // render the response and body http_response_code($statuscode); header($header); echo json_encode($response); Lets brake this down: First we check for a numeric url segment which is our $pageId. Then the Rest Request class comes into play and checks what type of request is coming in from the client. For the GET request, we want to return all data that is stored for a page plus the page id. This is all good old PW API code. I am using the $pdata array to store all page data. Then I am handing this array over to the $response variable. This will be used further down to render the JSON response body. If the page does not exist, I am setting an error message for the $response and a status code 404 so the client will know what went wrong. The else statement will later hold our POST request handling. The last 3 lines of code are setting the header and status code for the response and print out the response body that is sent back to the client. You can now browse to https://mysite.dev/api/pages/1 where you should see a JSON string with field names and values of your home page. If you enter a page id which does not exist you should see a JSON string with the error message. Lets move on to updating pages through a PUT request 3.2 update pages with a PUT request Since our API needs to know the id of the page we want to update, we again need to append an id to our endpoint url. In this example we will update the title and name of our homepage. So the request url will be: https://mysite.dev/api/pages/1. For the GET request above, anyone can connect to our API to retrieve page data. For the PUT request this is not a good idea. Thus we will add basic authentication so that only authorized clients can make updates. I use basic HTTP authentication with username and password. In combination with the https protocol this should be fairly safe. To set this up, we need an API key for the password and a username of our choosing. We add the API key in the PW backend: add a new text field "key" and assign it to the "api" template. edit the "api" page, enter your key and save. (I am using 123456 as key for this tutorial) Now add following code right after the if(Rest\Request::is('get')) {...} statement: // PUT request: update data of existing page if(Rest\Request::is('put')) { // get data that was sent from the client in the request body + username and pass for authentication $params = Rest\Request::params(); // verify that this is an authorized request (kept very basic) $apiKey = $pages->get("template=api")->key; $apiUser = "myapiuser"; if($params["uname"] != $apiUser || $params["upass"] != $apiKey) { // unauthorized request $response["error"] = "Authorization failed"; $statuscode = 401; // Unauthorized (see /site/templates/inc/Rest.php) } else { // authorized request // get the page for given Id $p = $pages->get($pageId); if($p->id) { $p->of(false); $p->title = $sanitizer->text($params["title"]); $p->name = $sanitizer->pageName($params["name"]); $p->save(); $response["success"] = "Page updated successfully"; } else { // page does not exist $response["error"] = "The page does not exist"; $statuscode = 404; // Not Found (see /site/templates/inc/Rest.php) } } } Breakdown: We check if the request from the client is a put request. All data that was sent by the client is available through the $params array. The $params array also includes $params["uname"] and $params["upass"] which hold our API user and key. We set API key and user and check if they match with the values that were sent by the client. If they don't match we store an error message to the response body and set the appropriate status code. If authentication went through ok, we get the page via PW API and update the values that were sent in the request body by the client. Then we put out a success message in the response body. If the page does not exist, we send the appropriate response message and status code, just like in the GET request example above. Now you might wonder how the client sends API user/key and new data for updating title and name. This is covered further down in step 4. If you want to test the PUT request right now, head down there and follow the instructions. If not, continue reading on how to setup a POST request for creating new pages. 3.2 create new pages with a POST request Final part of the coding part is creating new pages through our API. For this to work we need to implement a POST request that sends all the data that we need for page creation. We will do this at our endpoint: https://mysite.dev/api/pages/ Paste following code within the else statement that has the comment "// no url segment: handle POST requests": // POST request: create new page if(Rest\Request::is('post')) { // get data that was sent from the client in the request body + username and pass for authentication $params = Rest\Request::params(); // verify that this is an authorized request (kept very basic) $apiKey = $pages->get("template=api")->key; $apiUser = "myapiuser"; if($params["uname"] != $apiUser || $params["upass"] != $apiKey) { // unauthorized request $response["error"] = "Authorization failed"; $statuscode = 401; // Unauthorized (see /site/templates/inc/Rest.php) } else { // authorized request // create the new page $p = new Page(); $p->template = $sanitizer->text($params["template"]); $p->parent = $pages->get($sanitizer->text($params["parent"])); $p->name = $sanitizer->pageName($params["name"]); $p->title = $sanitizer->text($params["title"]); $p->save(); if($p->id) { $response["success"] = "Page created successfully"; $response["url"] = "https://mysite.dev/api/pages/{$p->id}"; } else { // page does not exist $response["error"] = "Something went wrong"; $statuscode = 404; // just as a dummy. Real error code depends on the type of error. } } } You already know what most of this code is doing (checking authorisation etc.). Here's what is new: We create a page through the PW API and assign it a template, a parent and basic content that was sent by the client. We check if the page has been saved and update our response body array with a success message and the URL that this page will be accessible at through the API for future requests. The client can store this URL for making GET or PUT requests to this page. If you're still reading, you have made it through the hard part of this tutorial. Congratulations. Having our code for reading, updating and creating pages, we now need a way to test the whole scenario. Read on to find out how this can be done. 4. test the whole setup with a Browser REST Client Addon The link in the heading will take you to a place from which you can install the very useful RESTClient addon to your favorite browser. I am using it with Firefox which is still the dev browser of my choice. Open a RESTClient session by clicking the little red square icon in the browsers addon bar. The UI is pretty straightforward and intuitive to use. 4.1 test the GET request Choose Method GET and fill in the URL to our endpoint. If you do not have a SSL setup for testing, just use http://yourrealtestdomain.dev/api/pages/1. If you happen to have a SSL test site with a self signed certificate, you need to point your browser to the URL https://yourrealtestdomain.dev/api/pages/ first in your test browser and add the security exception permanently. Otherwise RESTClient addon won't be able to retrieve data. If you have a test site with a 'real' SSL certificate, everything should be fine with using the https://... URL Hit send. In the Response Headers tab you should see a Status Code 200 and in the Response Body tabs a JSON string with data of your page. now change the 1 i the URL to some id that does not exist in your site and hit send again. You should get a 404 Status Code in the Response Headers tab and an error message "{"error":"The page does not exist"}" in the Response Body (Raw) tab. If you get these results, congrats! The GET request is working. For further testing you can save this request through the top menu Favorite Requests->Save Current Request. 4.1 test the PUT request Choose Method PUT and fill in the URL to our endpoint ending with 1 (http://yourrealtestdomain.dev/api/pages/1). In the top left click Headers->Content-Type: application/json to add the right content type to our request. If you miss this step, the request will not work. You will now see a "Headers" panel with all your headers for this request Click on Authentication->Basic Authentication. In the modal window that pops up, fill in user (myapiuser) and password (your API key). Check "Remember me" and hit Okay. You now should see Content-Type and Authorization headers in the "Headers" panel. Next, we need to send some data in the request body for updating our page title and name. Since we're using JSON, we need to create a JSON string that contains the data that we want to send. As I will update the home page for this example, my JSON reads { "title" : "Newhome", "name" : "newhome" } Be careful that you have a well formed string here. Otherwise you will get errors. Paste this into the "Body" panel of the REST Client addon. Hit send. In the Response Headers tab you should see a Status Code 200 and in the Response Body tabs a JSON string "{"success":"Page updated successfully"}". Now go to the PW backend and check if title and name of your page have been updated. If yes, congrats again. 4.2 test the POST request Choose Method POST and fill in the URL to our endpoint without any page id (http://yourrealtestdomain.dev/api/pages/). In the top left click Headers->Content-Type: application/json to add the right content type to our request. If you miss this step, the request will not work. You will now see a "Headers" panel with all your headers for this request Click on Authentication->Basic Authentication. In the modal window that pops up, fill in user (myapiuser) and password (your API key). Check "Remenber me" and hit Okay. You now should see Content-Type and Authorization headers in the "Headers" panel. Next, we need to send some data in the request body for updating our page title and name. Since we're using JSON, we need to create a JSON string that contains the data that we want to send. I will create a new page with template basic-page and parent /about/ for this example, my JSON reads { "template" : "basic-page", "parent" : "/about/", "title" : "New Page created through api", "name" : "newapipage" } Be careful that you have a well formed string here. Otherwise you will get errors. Paste this into the "Body" panel of the REST Client addon. Hit send. In the Response Headers tab you should see a Status Code 200 and in the Response Body tabs a JSON string "{"success":"Page created successfully","url":"https:\/\/mysite.dev\/api\/pages\/1019"}". Now go to the PW backend and check if title and name of your page have been updated. If yes, you're awesome! Summary By now you have learned how to build a simple REST API with ProcessWire for exchanging data with mobile devices or other websites. Notes I tested this on a fresh PW 2.7.2 stable install with the minimal site profile and can confirm the code is working. If you experience any difficulties in getting this to work for you, let me know and I will try to help. There purposely is quite a lot of repetion in the example code to make it easier to digest. In real life code you might not want to use procedural coding style but rather separate repeating logic out into classes/methods. Also, in life applications you should do more sanity checks for the authentication of clients with the API / for the data that is delivered by the client requests and more solid error handling. I skipped these to make the code shorter. RESTful services are by definition stateless (sessionless). My implementation within PW still opens a new session for each request and I haven't found a way around that yet. If anyone can help out this would be much appreciated. And finally big thanks to clsource for putting the Rest.php classes together. pages.php.zip1 point
-
Hey everyone, Max from Snipcart here! We just published a full tutorial showing how to use ProcessWire + Snipcart (our dev-first HTML/JS shopping cart platform) to enable e-commerce. It was pretty much my first time playing around with the Apache/MySQL/PHP stack, so I'd love to get some feedback on the demo code. Oh, and also, if you feel like the Snipcart integration could have been done in a different/better way with ProcessWire, let me know! > Blog post tutorial > (Very) simple live demo > GitHub repo Cheers folks.1 point
-
Thought I'd show some work in progress modules. Subscribers https://github.com/benbyford/Subscribers has functions for logging in new users, added with new subscriber role bulk export the subscriber users to comma delineated SubscriberList (submodule) module adds an admin page to view your subscribers and page through them, or export WireMailChimp https://github.com/benbyford/WireMailChimp (though I need to change the name on github) Implements https://github.com/drewm/mailchimp-api adds any user save to a mailchimp list settings for API and List id only adds users that have a checked email_subscribe field to true1 point
-
Module: http://modules.processwire.com/modules/template-file-helper/ Repo: https://bitbucket.org/pwFoo/templatefilehelper/overview TemplateFileHelper module features add global controller and template to current page by a Page::render hook Manage global ($layout) and current page ($view) styles and scripts with a $config->scripts / $config->styles context mapping. So $config->styles / $config->scripts works fine too load sub-templates with a controller file an array of data to fill template variables just an html template Ajax page load in mind Usage Global layout A global controller / template is added by a Page::render hook. /site/templates/_layout.php // controller /site/templates/_layout.tpl // view / html template Example _layout.tpl <!doctype html> <html lang="de"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>TemplateFileHelper Processwire</title> <?=$styles?> <?=$scripts?> </head> <body> <div id="nav"><?=$navigation?></div> <div id="pageContent"><?=$pageContent?></div> </body> </html> Example _layout.php // MarkupSimpleNavigation $nav = $modules->get('MarkupSimpleNavigation'); $layout->set('navigation', $nav->render($opts)); // Global and current page styles $styles = ''; foreach ($layout->styles as $style) { $styles .= "<link href='{$style}' rel='stylesheet' class='global'>"; } foreach ($view->styles as $style) { $styles .= "<link href='{$style}' rel='stylesheet' class='current'>"; } $layout->set('styles', $styles); // Global and current page scripts $scripts = ''; foreach ($layout->scripts as $script) { $scripts .= "<script src='{$script}' type='text/javascript' class='global'></script>"; } foreach ($view->scripts as $script) { $scripts .= "<script src='{$script}' type='text/javascript' class='current'></script>"; } $layout->set('scripts', $scripts); Current page The PW template of current page will rendered inside the global view by Page::render hook. /site/templates/basic-page.php // controller /site/templates/basic-page.tpl // view / html template Example basic-page.tpl <div><?=$contentHome?></div> Example basic-page.php $view->set('contentHome', 'Simple output...'); echo $view->render(); Output (for example to debug) is possible too. echo "My PW template file output..."; $view->set('contentHome', 'Simple output...'); echo $view->render(); Sub-templates It's possible to use sub-templates / chunks inside of a PW template / controller. Sub-template with controller / view files $part = $view->load('parts/test1', 'parts/test1'); // relative to /site/templates (view = .tpl, controller = .php $part = $view->load('parts/test1', true); // same as above. "True" instead of write identical path / file twice $part = $view->load('parts/test1', 'parts/test1_controller'); // view "parts/test1.tpl", controller "parts/test1_controller.php" Sub-template with array data $part = $view->load('chunks/test1', array('variable1' => "value1", 'variable2' => 'value2')); Sub-template just a html chunk $part = $view->load('chunks/test1'); // view file /site/templates/chunks/test1.tpl PW template file as view Because direct output inside a PW template file is possible it also works without a view. Example: PW template without viewTested with the FrontendUser module quick and dirty... $fu = $modules->get('FrontendUser'); $fu->login(); $button = $fu->form->fhSubmitBtn; if (!empty($_GET['logout'])) { $fu->logout($page->url); } $processed = $fu->process($page->url); if ($processed && !$user->isGuest()) { // $processed == false if login failed (not submitted / login successful == true) echo "Hello $user->name!"; echo "<a href='$page->url?logout=1'>Logout</a>"; } else { echo $fu->render(); } Scripts / Styles context The module itself takes care about the global (inside _layout.php) and "current" (inside PW template file). Just use PW $config to set styles and scripts. $config->scripts->add('...'); $config->styles->add('...'); You can also force the context by use the additional global api variables. $layout->scripts->add('...'); // global context $layout->styles->add('...'); // global context $view->scripts->add('...'); // current page context $view->styles->add('...'); // current page context1 point
-
You're correct, that there's no function context, but a return statement does also stop the execution of code in files loaded by require/include statements. Most often a $this->halt() without return doesn't make much sense.1 point
-
blynx, your solution is definitely ingenious – in total and detail! I played around with all parts and everything was working immediately without any issues. Standing ovations! What I like the most is the relation of maximum result with minimum effort – this reveals true masters. To get the synonym and sync problem solved with a few lines of code in very short time is more than I dared to dream of. So another giant thank you!1 point
-
Hej, I think thats no problem. When you have the link between synonyms and entries like I described, it is easy to retrieve the tags from the entry when you query a synonym: <?php # # "linked_entry" is the page field on the synonym holding the # reference to the entry. # synonyms have no tags field. # // get the tags of synonyms $a_synonym = $pages->get("parent=synonyms, name=airplane"); $synonyms_tags_via_its_linked_entry = $a_synonym->linked_entry->tags; // edit: in one line: $synonyms_tags_via_its_linked_entry = $pages->get("parent=synonyms, name=airplane")->linked_entry->tags; // find synonyms with tags $those_synonyms = $pages->find("parent=synonym, linked_entry.tags=some_tag|another_tag"); You just need to tag your entries and through the link in the synonym its very easy to handle anything tag related. But the syncing you describe would still be possible - though I don't think you need that if the tags of the synonym and the entry will always be the same. Regarding hooks: Have a close look at https://processwire.com/api/hooks/ and this when you got the idea: https://processwire.com/api/hooks/captain-hook/ and also search the forum for more examples! This is a rough sketch of a hook that might sit in the init.php / ready.php file. It may work out of the box, but I am still in the trial and error phase when it comes to hooks and haven't teste this one but it should work more or less somehow like this: <?php # keep synonyms linked_entry in snyc with entries synonyms wire()->addHookAfter('Pages::saved', function($event) { $page = $event->arguments(0); // what page was the hook called on? $template = $page->template; // what template has that page // see if the saved page is an entry because this hook is called on every page save if($template == "entry") { /* $related_synonym_pages = $pages->find("parent=synonyms, name={$page->synonyms}"); foreach($related_synonym_pages as $syn) { $syn->setAndSave("linked_entry", $page); } */ // haha, this happens to me all the time, the following should be simplier =) foreach($page->synonyms as $syn) { // get the set synonyms directly from the page $syn->setAndSave("linked_entry", $page); // set this page to that synonym } } }); So, this is the hook for: Edit synonyms on entry page, save it → hook updates the related synonyms which are set on the entry page enjoy1 point
-
GitHub was down for a few hours two days ago, maybe this is why. https://status.github.com/messages1 point
-
Thanks, @fbg13It's not quit ready for prime time yet, there are some bugs I'm working on, will update here.1 point
-
hi @tpr, seems i found a little bug: when hovering over the publish button, the hover event is not tied to the button but to the page label. it appears only on smaller screens when the buttons are floating right! another little thing: i've noticed some times that when hovering the tooltips the color gets somewhat ugly: as you can see i'm using reno here. don't know where this comes from? thank you once more for sharing the module! makes working with processwire even more fun1 point
-
1 point
-
Hm, well - regarding "thousands of pages": There was this blogpost once: https://processwire.com/blog/posts/find-and-iterate-many-pages-at-once/ about the new findmany() function: https://processwire.com/api/ref/pages/find-many/ - but from my understanding, this only applies if you really want to retrieve and do something with that many pages. In an encyclopaedia application you will of course search inside of manymany pages but you mostly only retrieve one or a small subset. I would assume (though I am not an expert) that the findMany() case does not apply here. The actual link will actually be the other way around. The synonyms don't know anything about their relation to someone else. That's why I was referring to the tagging: You have the entries and they point to synonyms: plane → aircraft, ufo, flying saucer, … but with your application logic you can create that link. Assuming: entries plane car fork ... synonyms airplane automobile ufo flying saucer ... Then, for example you get a query for "airplane": <?php $incoming_query_term = "airplane"; $entry = $pages->get("name=$incoming_query_term, parent=entries"); // see if there is an entry if($entry instanceof NullPage) { // no entry? $synonym = $pages->get("name=$incoming_query_term, parent=synonyms"); // get the synonym $entry = $pages->get("synonyms=$synonym, parent=entries"); // get the entry which has that synonym in its synonyms page field // eh, should also work, combined and short: $entry = $pages->get("synonyms=[name=$incoming_query_term, parent=synonyms], parent=entries"); } I guess your tagging should work kind of the same? edit: Mh, reread your original post - I think it would be more complicated to have the synonyms in a field. Maybe it feels stupid to have extra pages for the synonyms but I think it is the better solution. The downside is maybe that database queries take longer - but since processwire has the findMany() method now I don't think it is any problem to handle that many pages. One consideration might be helpful for rendering the list: Without this you would have to retrieve the entry for a synonym for every synonym by code like $pages->get("synonyms=THIS_SYNONYM.id") ... You could link from the synonyms to the entries by giving them a page field, too, where you store the linked entry. You could create that link with a hook automatically every time a synonym is created, so that every synonym has an entry-link. The problem here is to keep the links coherent. But then it would be very easy to render the list: Find all entries and all synonyms to one PageArray (probably paginated then, findMany?). Sort by name. Render them accordingly to their type: Entries become direkt links to the entry, synonyms become that "aircraft → plane" output.1 point
-
Mh, The synonyms field could be a simple textarea field "synonyms" on the "root word" with a synonym in each line. And when you are looking for the root page for a synonym: <?php $pages->find("synonyms*=requested_synonym") // or ->get() Would this do it? But I'd say having synonym pages might give you more flexibility - maybe you want to add properties to synonyms later .. who knows ^^. I don't think it is a downside having lots of "empty" pages. I probably would store all synonyms in a synonyms folder page as a storage and having a page field on the actual entry with that inputfield: http://modules.processwire.com/modules/inputfield-page-autocomplete/ It'll basically just be like tagging and one doesn't have to think much about those tag / synonym pages. They can be hidden somewhere. Finding correlating pages would work like above. (Not sure about the *= though, works with just = on a setup I have). This might also prevent you from some errors since every synonym is an actual entity in the system.1 point
-
The bit that I can't work out at the moment is how to set the matrix item type using a friendly name. I'm sure @ryan will have built in a way to do this, but until he responds you can set the matrix type as an integer using "repeater_matrix_type". First you need to find out the integer for the type of row you want to add. You can do this by dumping a repeater item of the right type and checking the repeater_matrix_type value in Tracy. Or you can open the field settings and inspect the source for the type you want to add. For example, in the screenshot below you can see the id of the inputfield for the "body" type is "matrix3_item", therefore the repeater_matrix_type integer is 3. So find out the repeater_matrix_type value (integer) for "article_content_text" and then you would run some code like this... $articles = $pages->find("template=article"); foreach($articles as $article) { $text = $article->article_text; $article->of(false); $new_item = $article->my_matrix_field->getNew(); // replace with the name of your matrix field $new_item->repeater_matrix_type = 3; // replace with the integer of your matrix type $new_item->article_text = $text; // assuming you added the article_text field to this matrix type $new_item->save(); $article->my_matrix_field->add($new_item); $article->save(); } But first test this works for a single article page before you process all the articles.1 point
-
When importing images to pages, make sure the page exists first. So if you are creating a new page, save it in your API code ($page->save()) before adding the image to it. Otherwise, PW won't know where to put the image(s) since the /site/assets/files/* directories are based on the page ID. If you are adding an image to a single-image field, you can just set the value of it to the URL, i.e. $page->image = 'http://www.something.com/some-image.png'; If you are adding an image to a mult-image field, you can add() it: $page->images->add('http://www.something.com/some-image.png'); Either of the above makes PW copy the image to it's assets and create the proper object. And then don't forget to: $page->save();1 point