Leaderboard
Popular Content
Showing content with the highest reputation on 03/06/2022 in all areas
-
Hello all! I guess I'm a little late to the party, but here's an explanation to my AppApi approach. I basically wanted to achieve exactly the same thing with my projects as well: A universal JSON api that I make all public ProcessWire pages also queryable as JSON. For this I use the combination of my Twack module and AppApi. Twack is a component system that allows me to get a JSON output from each ProcessWire page in addition to the standard HTML output. Twack registers a route that allows to query each Page from the PageTree (via ID or Path). But for this route you don't need the Twack module, of course. As here it would work only with the AppApi module: routes.php: <?php namespace ProcessWire; require_once wire('config')->paths->AppApi . 'vendor/autoload.php'; $routes = [ 'page' => [ ['OPTIONS', '{id:\d+}', ['GET', 'POST', 'UPDATE', 'DELETE']], ['OPTIONS', '{path:.+}', ['GET', 'POST', 'UPDATE', 'DELETE']], ['OPTIONS', '', ['GET', 'POST', 'UPDATE', 'DELETE']], ['GET', '{id:\d+}', PageApiAccess::class, 'pageIDRequest'], ['GET', '{path:.+}', PageApiAccess::class, 'pagePathRequest'], ['GET', '', PageApiAccess::class, 'dashboardRequest'], ['POST', '{id:\d+}', PageApiAccess::class, 'pageIDRequest'], ['POST', '{path:.+}', PageApiAccess::class, 'pagePathRequest'], ['POST', '', PageApiAccess::class, 'dashboardRequest'], ['UPDATE', '{id:\d+}', PageApiAccess::class, 'pageIDRequest'], ['UPDATE', '{path:.+}', PageApiAccess::class, 'pagePathRequest'], ['UPDATE', '', PageApiAccess::class, 'dashboardRequest'], ['DELETE', '{id:\d+}', PageApiAccess::class, 'pageIDRequest'], ['DELETE', '{path:.+}', PageApiAccess::class, 'pagePathRequest'], ['DELETE', '', PageApiAccess::class, 'dashboardRequest'] ] ]; You can use this class to get the page-outputs: <?php namespace ProcessWire; class PageApiAccess { public static function pageIDRequest($data) { $data = AppApiHelper::checkAndSanitizeRequiredParameters($data, ['id|int']); $page = wire('pages')->get('id=' . $data->id); return self::pageRequest($page); } public static function dashboardRequest() { $page = wire('pages')->get('/'); return self::pageRequest($page); } public static function pagePathRequest($data) { $data = AppApiHelper::checkAndSanitizeRequiredParameters($data, ['path|pagePathName']); $page = wire('pages')->get('/' . $data->path); return self::pageRequest($page); } protected static function pageRequest(Page $page) { $lang = SELF::getLanguageCode(wire('input')->get->pageName('lang')); if (!empty($lang) && wire('languages')->get($lang)) { wire('user')->language = wire('languages')->get($lang); } else { wire('user')->language = wire('languages')->getDefault(); } if (!$page->viewable()) { throw new ForbiddenException(); } return $page->render(); } private static function getLanguageCode($key) { $languageCodes = [ 'de' => 'german', 'en' => 'english' ]; $code = '' . strtolower($key); if (!empty($languageCodes[$key])) { $code = $languageCodes[$key]; } return $code; } } On top of your ProcessWire-template file you have to check if an api-call is active. If so, output JSON instead of HTML: <?php // Check if AppApi is available: if (wire('modules')->isInstalled('AppApi')) { $module = $this->wire('modules')->get('AppApi'); // Check if page was called via AppApi if($module->isApiCall()){ // Output id & name of current page $output = [ 'id' => wire('page')->id, 'name' => wire('page')->name ]; // sendResponse will automatically convert $output to a JSON-string: AppApi::sendResponse(200, $output); } } // Here continue with your HTML-output logic... That should be everything necessary to enable your ProcessWire-templates to output JSON. You will have an /api/page/ endpoint, which can be called to get the JSON-outputs. /api/page/test/my-page -> ProcessWire page 'my-page' in your page-tree under test/ /api/page/42 -> ProcessWire page with id 42 /api/page/ -> root-page And a small addition: If you want to query the page files also via api, have a look at my AppApiFile module. With it you can query all images via an /api/file/ interface.4 points
-
2 points
-
I bet that the first version of LR was removed because the module is not maintained in favor of the new version. As well, the pro module make things easy to implement and will let you sleep tight, as most hassles (security.. blabla..) got handled by ryan and contributors. If you want to try it out before pulling out the wallet, you can find the free version on the author's github ? https://github.com/ryancramerdesign/LoginRegister - (I have myself the first version in the wild since years without issue / registration disabled) and you will find some threads around the forum to customize it.2 points
-
AppApiPage adds the /page endpoint to the AppApi routes definition. Makes it possible to query pages via the api. This module relies on the base module AppApi, which must be installed before AppApiPage can do its work. Route Description /api/page/ Calls the root page of the page-tree /api/page/42 Will call the page with id=42 /api/page/my/test/page Calls your page with path my/test/page After installing AppApi and AppApiPage, you simply have to add the following code at the top of your ProcessWire-template to provide your page with a custom JSON output: <?php // Check if AppApi is available: if (wire('modules')->isInstalled('AppApi')) { $module = $this->wire('modules')->get('AppApi'); // Check if page was called via AppApi if($module->isApiCall()){ // Output id & name of current page $output = [ 'id' => wire('page')->id, 'name' => wire('page')->name ]; // sendResponse will automatically convert $output to a JSON-string: AppApi::sendResponse(200, $output); } } // Here continue with your HTML-output logic...1 point
-
The module can generate basic ICS calendar strings and files. Usage Example: $icsgen = wire()->modules->IcsGenerator; // set properties $icsgen->setArray(array( 'date' => new \DateTime('2033-12-24 12:00'), 'dateEnd' => new \DateTime('2033-12-24 13:00'), 'summary' => 'Event title', 'description' => 'Event description', )); // get path to a temporary .ics file // (using wire()->files->tempDir) $icspath = $icsgen->getFile(); // send email with ics file $mail = wireMail(); $mail->attachment($icspath, 'calendar.ics'); $mail->to($user->email); $mail->subject('ICS Demo'); $mail->body('This is a ICS demo.'); $numSent = $mail->send(); For more infos see GitHub Readme or Modules Page. If you experience reproducable issues please open a GitHub issue.1 point
-
@kongondo I don't understand. Is added anything better than saveReady? Wouldn't you have to do a save() or setAndSave() in your example? And isn't the id=0 obsolete (or even wrong) if you are using the added hook?1 point
-
Maybe then.. <?php $wire->addHookAfter("Pages::added(template=xyz,id=0)", function($event) { $page = $event->arguments(0); $page->status = 1; // auto-publish }); ? ?1 point
-
Alternatively to hiding/renaming the publish button you can auto-publish the page when it is created: <?php $wire->addHookAfter("Pages::saveReady(template=xyz,id=0)", function($event) { $page = $event->arguments(0); $page->status = 1; // auto-publish });1 point
-
@ClausWell, I can't guess where you would need the output of the SVG. If you need it just before the body content, it could look s.th. like this: $content = "<div class='svg-container'>" . file_get_contents($page->image->filename) . "</div>"; $content .= $page->body; Note the .= for appending to $content. If you want the SVG to appear somewhere in the middle of the body content I'd recommend looking into the Hanna Code module. If all you need is a single (or few) SVG in your page body, Hanna Code might also work without an extra SVG field, when you'd copy the SVG source directly in a tag (Haven't tested this). You could then place the tag within the body field like [[svg]]. The body field will the need to have the Hanna Code Text Formatter added as last element (in body Field Settings > Details > Text Formatters) to be able to output the tag.1 point
-
Thx teppo, I'm not sure if it was me. I never got any further than testing WireFrame. I think I don't have it in any of my projects so it's out of my head and you can ignore my request if there is still something left ?1 point
-
@Claus Instead of the image tag <img src="<?=$page->image->url?>" /> you would directly write the content of the svg file <svg>...</svg> <?=file_get_contents($page->image->filename)?> filename should give the full server path to the file. A relative path might also work. Note that ideally there should be no XML declaration in the SVG file. Also be aware that a 'bad' SVG can break your page or can do other evilous things. You shouldn't allow editors to upload SVG files, at least not without testing (or hide the field for non-superusers). Inlining allows to access SVG contents through external JS & CSS. From simple color changes on hover to animations (CSS & JS), there are a lot of useful benefits. There are also other ways that might work for you here like using <object> or <embed> tags. A good overview is Using SVG | CSS-Tricks - CSS-Tricks1 point
-
1 point
-
As we continue to work towards the next master version, this week I've been working on fixing reported issues. A new $sanitizer->words() method was also added which reduces a string to contain just words without punctuation and such. It was added in part to work on an issue reported with the tags feature in the field editor, but should be handy for other cases as well. As part of that update, the existing $sanitizer->word() (singular) method was re-written to support the features needed for the new words() plural method. This week I've also been working on a pull request from Bernhard that enables greater customization of AdminThemeUikit by way of custom render files and hooks. I'm bringing in that PR and it has a lot of good ideas that have inspired some related updates to it. I've got a bit more work and testing to do before committing, but that part should be ready early next week, along with more core updates. Thanks for reading and have a good weekend!1 point
-
Haven't tested this in a modal. One way to do it. <?php namespace ProcessWire; $this->addHookAfter("ProcessPageEdit::buildForm", null, "hookModifyEditFormGUI"); function hookModifyEditFormGUI(HookEvent $event) { if ($event->method == 'buildForm') { $page = $event->process->getPage(); // here you can use $page to skip changes based on a condition // ------------ // get ProcessPageEdit Form $form = $event->return; // not needed just for debugging // $children = $form->children; // get save + keep unpublished button $saveAndKeepUnpublished = $form->children->get("id=submit_save_unpublished"); // if we found it, remove save + keep unpublished if ($saveAndKeepUnpublished) { $form->remove($saveAndKeepUnpublished); } // ------- // get publish button $publish = $form->children->get("id=submit_publish"); // if we found it, change its value if ($publish) { $publish->value = "For Pete's Sake"; } // <<<<<<<<<<<<<<<< // @debug bd($event, __METHOD__ . ': $event at line #' . __LINE__); bd($event->method, __METHOD__ . ': $event->method at line #' . __LINE__); bd($page, __METHOD__ . ': $page at line #' . __LINE__); bd($form, __METHOD__ . ': $form buildForm - at line #' . __LINE__); // bdb($children, __METHOD__ . ': $children buildForm - at line #' . __LINE__); bdb($saveAndKeepUnpublished, __METHOD__ . ': $saveAndKeepUnpublished buildForm - at line #' . __LINE__); bdb($publish, __METHOD__ . ': $publish buildForm - at line #' . __LINE__); // >>>>>>>>>>>>>>>>>> } }1 point
-
I could be wrong, but what I think @wbmnfktr is looking for is a **standardized** Processwire APIs across all Processwire installations that is on by default? This could be beneficial by allowing: third party services to integrate easily with Processwire. Something like zapier.com could build a Processwire connector that consumes the API to allow for no-code workflows that connect different systems and services together? a site aggregator website that could consume the other Processwire website's API and report back the details. For example, which sites need module or Processwire updates. Something like https://sitedash.app/ for Modx Static Site Generators to consume and build a fast static website that can be hosted on a global CDN. a Single Page Application built with Vue.js/React.js/React Native, etc.. that could be replace the Processwire Admin. I think https://www.sanity.io/ can do this? Everything is fully decoupled. Why would you want a different admin? What if you wanted to build a native Mobile app to administer your Processwire site? admin components that consume that consume the API for different admin experiences? Wordpress uses the API for their new Block Editor https://developer.wordpress.org/block-editor/ Sure stuff like sitedash.app can be built right now with Processwire, but services like zapier.com and others aren't going to spend time building a API connector if it isn't included in Processwire core and isn't standardized. I agree with flydev - there are other things to consider as well like issuing API tokens, content throttling, API versioning, providing data in different formats other than json and REST like GraphQL, webhooks, autogenerated API documentation like https://swagger.io/. https://api-platform.com/ covers a lot of these topics. https://strapi.io/ does a good job with some of these things like issuing tokens for integrating third party clients. Thanks everyone for posting solutions that could work. I enjoying reading and watching the many different ways you can do things with and without modules. Thanks @flydev ?? for the AppAPI demo. Thanks @bernhard for showing/creating the RockHeadless module and demo - dang your fast. I like how you demonstrate how you can also expose the children of certain pages to the API as well. That's is another aspect that has to be considered since Processwire is different than most bucket based CMSs. Processwire is tree based around hierarchy.1 point
-
On my side, from what I understand (and what I would like to see implemented) is something like the following : - in config.php set $config->restapi = [ 'endpoint' => 'api', 'enabled' => true]; then use simples built-in functions to get data from api (eg, home page) GET /api/1 Anyway, even if it could/should be easy to use, things are a bit more complex than what we can see here in this thread. I mean, almost all functionalities of AppApi should definitely exists.1 point
-
To add my two cents here... I'm totally on board with this and I started to donate in 2019, through 2021 to some devs for their modules. Most often through their publicly available and mentioned ways, such like PayPal, BuyMeACoffee, ... There is one thing with this... as I wrote some of them about it just to tell and check... they said: "Oh... don't have that account anymore!" or "Oh... that changed!". So... to all of us in some kind: please check if those PayPals and Co. still are up to date. To those that donate: write a message to your favourite devs. Feels awkward, but at least you can be sure the money goes where it should go. Another almost unrelated thing: I stopped using my DEV-licenses for client projects. Sure... that's what they are for but... even a hairdresser can afford FormBuilder and ProCache. Why stop there? I use those only for my very personal projects now and I feel much better with this.1 point
-
I was about to create a similar topic, but why do it if this one already exists))) Not so long ago I started donating to some ProcessWire modules' authors. And each 1st of the month I am looking at my Patreon receipt in my email with a kind of a pride. I think that this thing is my little contribution to the community I love so much and which gave so much to me for free. I do know that Ryan likes to receive his support with pro modules payment. But many modules really shouldn't be paid/pro as they are so essential to many (and so fun to build). But their authors still would be glad to receive some money to sustain their enthusiasm supporting them and creating new features. I am sure the appreciation itself is equally important, but what is an easier way to show it than ???))) The other thing is that I sometimes notice some great improvements that seem to happen to modules as soon as some support comes in. I am writing this to encourage everyone to support the PW ecosystem by donating to module authors. I will list the modules I know that clearly asked for donations. I am sure that is not an extensive list. But at least something to start with. Tracy Debugger Mystique and other modules by ukyo (please don't miss this one @Jonathan Lahijani))) Rock Migrations and a bunch of rock stuff by bernhard All the great stuff from teppo I really like the Patreon/OpenCollective/Github donations, but only 1 of 3 listed used them. Sooooo..... Start throwing money at these fine gentlemen)) Support yourself by making you favorite modules not go away. I wish we could bring back @tpr to support his AOS and wire shell by @marcus and @justb3a. Would they keep supporting their thing is they had some donations coming in? Who knows. And please feel free to list you other module authors that you know asked for support below. Edit 2022-10-27: added teppo's link1 point
-
HTMX is quite good. $config->ajax won't detect HTMX requests though, so I recommend adding this to your /site/ready.php: // if htmx request, DO NOT use _main.php if(array_key_exists('HTTP_HX_REQUEST', $_SERVER)) { $config->appendTemplateFile = ''; $config->htmxRequest = true; } That assumes you are using the Markup Regions output strategy by the way. Use $config->htmxRequest as needed.1 point
-
$items = $pages->find("id>1"); $home = $pages->get("id=1"); $customPaginatedArray = new PaginatedArray; foreach ($items as $item) : if ($item->parent == $home) : $customPaginatedArray->add($item); endif; endforeach; // should return an array of pages that are direct children of the homepage $limit = 10; $start = ($input->pageNum-1)*$limit; $total = $customPaginatedArray->count(); foreach ($customPaginatedArray->filter("limit=$limit, start=$start") as $c) : echo $c->title . '<br>'; endforeach; $customPaginatedArray->setStart($start); $customPaginatedArray->setLimit($limit); $customPaginatedArray->setTotal($total); echo $customPaginatedArray->renderPager();1 point