-
Posts
328 -
Joined
-
Last visited
-
Days Won
10
Everything posted by Autofahrn
-
If you see that "call ... on null", then your $module variable is null. Are you certain that installing the module actually worked? I at least miss something like a getModuleInfo method.
-
Here is a quest for all Fieldtype gurus out there: I've stumbled over an issue (maybe bug) when using an InputfieldPageListSelect within the config inputfields returned from a fieldtype module. What I want/need to do is processing POST data and store parameters in a different form (associative array for example). To avoid storing the value twice in the database, I simply remove the value from the POST data. This works fine for all fields including the InputfieldPageListSelect, but that particular field continues to add some bogus entry into the field data (JSON object in the fields table). This is basically no big deal, but I guess it is not expected to be there. I've condensed the issue into a small fieldtype code: <?php namespace ProcessWire; /* * Fieldtype to diagnose issue with InputfieldPageListSelect and manually managing form data. * * This Fieldtype collects some private configuration data through the getConfigInputfields API. * After submission the parameters are stripped from the POST array and stored within an * associative array for this field. * * For some unknown reason values generated from InputfieldPageListSelect are still written * into database, the field's JSON data looks like this: * * { "collapsed":0, * "configParam":{ * "sometext":"This is some text", * "somecheckbox":1, * "somepage":1068, * "someoption":4 * }, * "someprefix[somepage]":0 <== this is not expected * } * * To simplify processing of the POST data, field names are formed to create an associative * array already in the POST data like "someprefix[sometext]". * The issue persists even if values use a plain name like "someprefix_sometext". * * Sidenote: The required attribute does not work, may relate to the array type of POST data. Any hint welcome! */ class FieldtypeInputRedirect extends Fieldtype { public static function getModuleInfo() { return array( 'title' => __('TEST Input Redirection'), 'version' => 1, 'summary' => __('TEST Input Redirection to field config'), 'installs' => 'InputfieldInputRedirect' ); } const thePrefix = 'someprefix'; const configParam = 'configParam'; // Field definition to simplify testing. private static function getCfgFlds() { return [ 'sometext' => [ 'type' => 'InputfieldText', 'label' => __('Type some Text'), // 'required' => 1, // Would be nice but not working 'columnWidth' => 25, ], 'somecheckbox' => [ 'type' => 'InputfieldCheckbox', // Requires special attention after setting the value 'label' => __('Toggle it'), 'columnWidth' => 25, ], 'somepage' => [ 'type' => 'InputfieldPageListSelect', 'label' => __('Point to a Page'), 'columnWidth' => 25, 'derefAsPage' => 1, 'parent_id' => '/', ], 'someoption' => [ 'type' => 'InputfieldSelect', 'label' => __('Pick a Color'), 'initValue' => 1, 'defaultValue' => '1', // 'required' => 1, 'columnWidth' => 25, 'options' => [ 1 => 'white', 2 => 'red', 3 => 'green', 4 => 'blue', 5 => 'black', ], ], ]; } public function ___getCompatibleFieldtypes(Field $field) { return null; } // No compatible fields public function sanitizeValue(Page $page, Field $field, $value) { return $value; } // No field, never called yet required public function getInputfield(Page $page, Field $field) { return($this->modules->get('InputfieldInputRedirect')); } // Generate Inputfield public function ___getConfigInputfields(Field $field) { // Get some PW variables $input = $this->wire('input'); $modules = $this->wire('modules'); /** * Process submission */ $configParam = $input->post(self::thePrefix); if(isset($configParam)) { // $this->message('Field SET: '.print_r($configParam, true)); $field->set(self::configParam, $configParam); // Store parameters to field (and database) $input->post->offsetUnset(self::thePrefix); // Remove array from POST data } else { // restore parameters from field $configParam = $field->get(self::configParam); } /** * Setup Inputfields */ $inputfields = parent::___getConfigInputfields($field); // Create wrapper for our own fields $fs = new InputfieldWrapper; $fs->skipLabel = InputField::skipLabelHeader; $fs->collapsed = false; // enumerate field configuration and generate fields dynamically foreach($this->getCfgFlds() as $configName => $configDef) { $cfg = $modules->get($configDef['type']); // Get Inputfield instance if($cfg) { $cfg->attr('id+name', self::thePrefix."[{$configName}]"); // Setup fieldname if(isset($configParam[$configName])) // Initialize value, if already set $cfg->value = $configParam[$configName]; if($configDef['type'] == 'InputfieldCheckbox') // Special attention to checkboxes $cfg->attr('checked', $cfg->value != 0); foreach($configDef as $k => $v) // Setup remaining attributes { switch($k) { case 'type': // Type already handled continue; case 'options': // create inputfield options $fldOpts = array(); foreach($v as $kopt => $opt) $fldOpts[] = "{$kopt}={$opt}"; $cfg->set('options', implode("\n", $fldOpts)); break; default: $cfg->set($k, $v); break; } } $fs->add($cfg); // Add field to fieldset } } $inputfields->prepend($fs); // Add fieldset to inputfields return($inputfields); } } along with this dummy Inputfield: <?php namespace ProcessWire; /* * Dummy inputfield for FieldtypeInputRedirect, not actually useful */ class InputfieldInputRedirect extends Inputfield { public static function getModuleInfo() { return array( 'title' => __('TEST Input Redirection', __FILE__), // Module Title 'summary' => __('TEST Input Redirection to field config', __FILE__), // Module Summary 'version' => 1, ); } public function ___render() { return '<span>This field is not intended to be used!</span>'; } // Required to generate field } Any hint welcome!. Edit: PW 3.0.123
-
Not sure if renaming index.php would be of any use. If you point the .htaccess to use the different index.php, you're old site will be gone anyway. Does your hoster support creation of subdomains (something like new.mysite.com)? Then I'd place the new setup into a subdirectory and point that subdomain to that directory. When you're done, you simply have to point your regular domain to that subdirectory (no need to move any file afterwards).
-
wire('log')->save("shopify", "collections = " . print_r($collections, true)); You missed the second parameter of print_r which instructs to use the return value rathern than echoing. http://php.net/manual/de/function.print-r.php
-
Did you try (shouldn't be necessary, though) $productPage = $pages->get("template=product, reference={$selectedProduct->id}");
- 10 replies
-
- inputfield
- asmselect
-
(and 2 more)
Tagged with:
-
I'd focus on the first errors which state: invalid default for 'created'. Not sure for PW2.7 installs (any reason to not use PW3?), but for PW3 the created fields defined like this (in install.sql): `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, Maybe the SQL engine of your MAMP can't deal with the specifications in those older import files and you'll need to adjust them.
- 7 replies
-
- processwire
- local webserver
-
(and 3 more)
Tagged with:
-
Is k31648_cms-pro3 a local database? Looks like your local installation tries to communicate with the database of a webhoster.
- 7 replies
-
- 1
-
- processwire
- local webserver
-
(and 3 more)
Tagged with:
-
Breadcrumbs in backend doesn't link to parent page
Autofahrn replied to dragan's topic in General Support
Ok, not related to PHP version and already happening on 3.0.62 (missing open on last breadcrumb). -
Breadcrumbs in backend doesn't link to parent page
Autofahrn replied to dragan's topic in General Support
Could this be related to PHP 7.2? -
Image field - clone image to other image field
Autofahrn replied to Peter Knight's topic in Wishlist & Roadmap
Does this need to happen in the admin? If it would be acceptable to have a "mover page" as a frontend form it shouldn't be too complicated to implement that via the API. -
How to implement a small AJAX-solution with db-request
Autofahrn replied to gerald's topic in API & Templates
@gerald: In case its still relevant, you'll find a fresh, working example here: -
Who is maintaining projects and users? Can users create new projects or only browse projects assigned to them? If the users do not need to access the backend, you'll not even need roles to realize that (access will be controlled from your PHP code then). Since users are managed by pages, the admin may add fields to the user templates as required. This could be a simple page select which holds the projects assigned to the particular user. Or you place a page select on your project template which selects the users assigned to that project (no need to modify the user template in this case).
-
How to catch PHP notice errors in AJAX requests?
Autofahrn replied to bernhard's topic in General Support
Just pimped the code with a catch-all handler. -
How to catch PHP notice errors in AJAX requests?
Autofahrn replied to bernhard's topic in General Support
Works for me (tried to keep it as compact as possible): <?php namespace ProcessWire; /* Quick test to capture out of band ECHO messages from PHP */ class WontNameItFoo { public function Quote() { return('The best is yet to come...'); } public function Einstein() { return('E = mc²'); } } $PhpErrors = ''; // This will be filled from our error handler global $PhpErrors; function php_error_handler($errno, $errstr, $errfile, $errline) { global $PhpErrors; // Add an LI element to our error string $PhpErrors .= "<li><b>RUNTIME ERROR #{$errno}:</b> $errstr in ".basename($errfile)."({$errline}):<br>"; $PhpErrors .= '<pre>'.file($errfile)[$errline-1].'</pre></li>'; } if($this->config->ajax) // Handling an AJAX request? { header('Content-type: application/json; charset=utf-8'); // Define response header set_error_handler('ProcessWire\php_error_handler'); // Register Error Handler try { // Perform some PHP processing without any kind of sanitation for testing only // In a productive environment proper parameter verification should be implented! $ajaxDate = 'Date: ' . date('l jS \of F Y h:i:s A', $input->post('timestamp')); $ajaxDiv = $input->post('dividend') . ' / ' . $input->post('divisor') . ' = ' . (string)($input->post('dividend') / $input->post('divisor')); $wnif = new WontNameItFoo(); $func = $input->post('function'); $ajaxFunc = $wnif->$func(); // This is brute force catching of fatal PHP errors... } catch(\Throwable $t) { php_error_handler($t->getCode(), $t->getMessage(), $t->getFile(), $t->getLine()); // $PhpErrors .= '<li><pre>'.$t->getTraceAsString().'</pre></li>'; // in case you like to see the stack trace } if($PhpErrors != '') // Errors captured from our error handler? $TheData = [ 'errors' => $PhpErrors ]; // Only return errors else $TheData = [ // No error, return proper result 'ajax-result' => $ajaxResult, 'ajax-division' => $ajaxDiv, 'ajax-date' => $ajaxDate, 'ajax-func' => $ajaxFunc, ]; if($input->get->callback) // JSONP? (not used here, would require GET request, useful for cross-domain query) echo $input->get->callback."(".json_encode($TheData).")"; else echo json_encode( $TheData ); // Regular AJAX response die(); } // Setup regular HTML content including script // You may replace "$content =" with echo, depending on your output scenario $content = "<div><h1>{$page->title}</h1> <form id='the-form' action='#'> Timestamp: <input id='timestamp' name='timestamp' type='text' value='SomeBogusData'><button type='button' onclick='setNow(\"#timestamp\");'>Now</button><br/> Divide <input name='dividend' type='text' value='1234'> by <input name='divisor' type='text' value='0'><br/> Function <select name='function'><option value='Einstein'>The Einstein</option><option value='Quote'>Personal Quote</option><option value='FourtyTwo'>The answer to life, the universe and everything</option></select></br> <button type='submit'>Execute</button> </form> <div id='ajax-status'></div> <div id='ajax-division'></div> <div id='ajax-date'></div> <div id='ajax-func'></div> </div> <script> function setNow(target) { $(target).val(Math.round((new Date()).getTime() / 1000)); } $(document).ready(function() { $('#ajax-status').html('Ready...'); $('#the-form').submit(function(event) { event.preventDefault(); // No default action $.ajax({ url: '.', type: 'post', data: $( '#the-form' ).serialize() }) .done(function( jsonData ) { if(jsonData['errors']) { $( '#ajax-status' ).html( 'ERROR: <ul>' + jsonData['errors'] + '</ul>' ); } else { $( '#ajax-status' ).html( 'SUCCESS!' ); // console.log(jsonData); for (var key in jsonData) { $('#'+key).html(jsonData[key]); } // Distribute result into DIVs } }) .fail(function() { $( '#ajax-status' ).append( 'FAILED' ); }); }); }); </script> "; See it live: https://www.team-tofahrn.de/ajax-test/ -
How to catch PHP notice errors in AJAX requests?
Autofahrn replied to bernhard's topic in General Support
Sure, I thought about something like this: $payload = $this->input->post('data'); $func = $actions[$action][0]; $options = $actions[$action][1]; $data = []; set_error_handler(...); // Setup handler // Execute whatever requested if(count($options)) $response = $func->__invoke($payload, $options); else $response = $func->__invoke($payload); if($Errs != '') // Errors happened? $data[] = (object)[ 'error' => $Errs ]; else // log data and response $data[] = (object)[ 'action' => $action, 'payload' => $payload, 'response' => $response, ]; You may even want to add a try..catch around the function invocation. I'll check later but don't see a reason why that should not work. -
How to catch PHP notice errors in AJAX requests?
Autofahrn replied to bernhard's topic in General Support
There is no difference for regular HTML or AJAX reply. If the error happens, PHP sends that out of band string back to the client. If you are waiting for a JSON, then this message prepends the JSON reply. Catching it with that error handler allows you to put the message into you JSON object before transmission. -
How to catch PHP notice errors in AJAX requests?
Autofahrn replied to bernhard's topic in General Support
Here we go: // Out of Band PHP Error grabber $Errs = ''; global $Errs; function regular_error_handler($errno, $errstr, $errfile, $errline) { global $Errs; $Errs .= "<li><b>Custom error:</b> [$errno] $errstr<br>Error on line $errline in $errfile</li>"; } set_error_handler('ProcessWire\regular_error_handler'); // assuming to operate in ProcessWire namespace // Execute some PHP $DateOutput = date('H:i', 'SomeBogusData'); $Zero = 0; $Result = 1 / $Zero; // Finally check for any out of band echo messages from PHP if($Errs != '') $content .= "Execution failed with<ul>{$Errs}</ul>"; -
How to catch PHP notice errors in AJAX requests?
Autofahrn replied to bernhard's topic in General Support
Maybe output buffering can help in this case? Just call ob_start before executing the code and finally use ob_get_contents to check for some unexpected output. Which PHP version are you running? -
Glad you get it running. In the end its not that complicated, but the dependancies need to be understood first. I know.... And, yes, toolbar entries are case sensitive (no need for an additional line, you may place the buttons anywhere), and sometimes you'll need to read the code in plugin.js to find the string you have to put in.
-
Is your CkEditor field indeed named "my_ckeditor_field"? If not, you'll need to edit your ready.php accordingly.
-
Does your ready.php start with <?php namespace ProcessWire; And to have the H buttons you'll need some more code (maybe plugin) which can be triggered from the toolbar reference. Edit: https://ckeditor.com/cke4/addon/formatbuttons
-
Not sure about 3.0.98, but with 3.0.123 its simple to add from Modules->Install. In the dropdown select "Process" and there you hopefully find "Page Clone".
-
yup, it says So if an image is simply uploaded and downloaded without manipulation (i.e. sizing), the original, unaltered version should be retrieved. At least that's the case in all my setups.
- 12 replies
-
- 1
-
- progressive
- interlaced
-
(and 4 more)
Tagged with:
-
Probably totally stupid question, but do the user-uploaded images go through PW-side image processing at all?
- 12 replies
-
- 1
-
- progressive
- interlaced
-
(and 4 more)
Tagged with:
-
For money stuff you may stick to regular integer field, just calculate in Cent and divide by 100 for display. Easy, stable, reliable and fast. Of course less convenient compared to Fieldtype Decimal.