Jump to content

suntrop

Members
  • Posts

    323
  • Joined

Posts posted by suntrop

  1. I am using repeater matrix fields and need to add a field from those to the admin live search in the navbar. But the settings for ProcessPageSearch only allow some other fields. Not repeater fields.

    I found this old posting of Ryan, but perhaps this changed again. At least, I can't see any text input field.

    On 4/1/2011 at 3:59 PM, ryan said:

    search fields in Modules > Process > Page Search. But went and tried it myself and see we're using a multi selection field rather than a text input. :) So I went ahead and changed it to a text input so that you can use subfields (like filefield.description) for searches. If you grab the latest commit, you should be able to configure the Page Search module to use filefield.description for admin searches.

    But then I found this 

     

    With code to add custom searched pages. But the code is not working as expected. Actually, it looks like it never is executed.

    $wire->addHook('ProcessPageSearchLive::findCustom', function(HookEvent $event) {
      bd('This never fires');
      $data = $event->arguments(0); // array 
      $search = $event->object; // ProcesPageSearchLive 
      $group = 'Pages modified today'; // description of this type of search
      if($data['q'] === 'today') {
        $items = $event->wire()->pages->find("modified>=today, include=unpublished"); 
        foreach($items as $item) {
            $search->addResult($group, $item->title, $item->editUrl); 
        }
      }
    }); 

    I tested multiple hook points, but none worked. ProcessPageSearchLive::execute or ProcessPageSearchLive::findReady

    Code is in /site/templates/admin.php

    Using PW 3.0.243

  2. I noticed something strange, with a selector I cannot explain why this happens.

    $item_number = ' ';
    $p = wire('pages')->get('template=product, item_number=' . $item_number);
    echo $p->title;

    The code above finds a page with an item_number set to the value of "50032". There is no space (had a look at the DB).

    I would have though using the = operator the code above gets nothing or if present something with an empty item_number. But no with a totally different value.

    It works as expected if I change the code to:

    $p = wire('pages')->get("template=product, item_number='{$item_number}'");

    Does anybody know why the first code example works differently?

    image.thumb.png.4c0f489c79894757d7b611cf291264be.png

    PW 3.0.243

  3. Thanks guys! 

    @bernhard That is quite nice, to add the second field by JS. I was thinking of adding it via PW's hook system and do the conversion in PHP. But I like your idea. 

    Had to change some parts, because sometimes the field is inside a repeater field and the names are price_repeater1234. Perhaps it is just me, but I would have thought conditional hooks take this into account. I had to remove the Inputfield(name=price) and check from within the hook. BTW, there is a new str_starts_with() function in PHP 8 ? 

    @MarkE Looks interesting! Like the idea a lot. This time I'll stick with the simpler help of JS. 

    • Like 1
  4. Hello everybody ?

    I am in need of some form of advice or ideas. I've got a site that displays products along with prices. Prices stored in net, but showed on the frontend and newsletter as its gross value. We decided to use net because there are three different gross values (different countries, calculated via external API) and it makes programming easier.

    So, now, my client wishes to input the gross value into the CMS. That would cause a lot of changes, (it is error-prone) and makes some things more difficult at our end of the product. Despite I'd like to give my clients what they need, I was thinking to use hooks for that. So whenever something is put into the field "price" will get converted before storing in the DB and vice versa gets converted to be shown as gross in the field value. That way, I "just" have to change it at a single point: the hook for the CMS field.

    What you think? Is this kind of more a hacky way and brings in the long run more problems than short benefits? I am always used to work with what I actually have and see :-)

  5. Hi all

    the password reset isn't working correctly. When I enter the username, I receive the reset email/link https://www.example.com/memberarea/login/?forgot=1&u=1222&t=nKIvd6Rpin4El.3Jc19aTPsDWAaZhw%2F9 

    But when I click the link I get redirected to the actual login page. The URL is https://www.example.com/memberarea/login/ again, there is no notification/error message and nothing to put in the verification code or reset the password. I just checked there is no redirect on behalf of my site/code.

    Found another forum thread and github issue with the same effect, but without any solution.

    PHP 7.4
    PW 3.0.165
    Login/Register 0.0.2
    ProcessForgotPassword 1.0.3
    Using it on frontend login, not admin login page

  6. I have updated to PW 3.0.184 last weekend. Noticed this week, Mail-Login is not working any more. I guess there must be changes made in core or the Login module (had something ~3.0.164 before).

    The Login module says now, "To use email login, you must enable the “unique” setting for your email field." When I enable the checkbox "Unique" and save the "email" field, the checkbox is cleared again.

    There is no error message. But it is probably because there are already 30 email addresses more than once used.

    Problem now: It would be quite hard to check which accounts are the latest/active ones and which could be renamed or whatever. 

    Anybody with an idea? Anyone knows when things changed in the Login module?

  7. Yes, I had set the namespace properly. 

    Strange part now, I installed another PW instance, a couple of hours ago, and first thing I tested was the Functions API in a newly created _main.php. It worked. I did a lot of testing and lastly just copied the file itself. That file worked (was just an echo page()->id). I copied the markup again and everything was like before, but it now works.

    I have no idea what was wrong with the other file. Just tested with different encodings, BOM, w/out namespace etc. but nothing to reproduce the error.

  8. It is quite some time since I launched my last PW project and can't remember/find if I forgot something. 

    The functions API in my /site/config.php is set to true. I have just installed a blank new PW project. But every call ends with an error.

    <?=
    
    var_dump($config->useFunctionsAPI);
    page()->get('title');
    
    ?>
    
    bool(true) 
    Darn… Fatal Error: Uncaught Error: Call to undefined function page() in site/templates/_main.php:15

    The config setting is correct, but still it is not working. Did I miss something? I just installed 3.0.165

     

    Edit: Just noticed it works fine in template files like basic-page.php and home.php but not in _main.php (which gets appended)

  9. 2 hours ago, Jan Romero said:

    Can you confirm that the config takes

    Yes, can confirm and I had disabled 16A

    Just upgraded to current dev version. It got kind of worse. When I save a page with the pagename "teßtpage" the field is empty after admin page reloads. DB has a wrong punycode of "xn-stseite". However, saving "testsäite" will save but still results in a 404.

  10. I am using images tags as links and some tags contain special characters (like schwarzweiß). Links are pointing to a URL segment.

    Problem is, URL with special chars are not working. I added $config->pageNameCharset = 'UTF8'; in my config file but still I see a 404 on URL with special chars.

    Any idea?

  11. Thanks, but I don't get what you are trying to say. I need to have two separate addresses, because shipping is mostly other than billing address.

    But I still can't see how PW works exactly saving data. First PW calls sanitizeValue() and next calls sleepValue(). But when I check $value in sleepValue()

    $sleepValue = [
                'data_billing_company'     => isset($value->billing_company) ? $value->billing_company : $page->billing_company,
                //…
                'data_shipping_gender'     => isset($value->shipping_gender) ? $value->shipping_gender : $page->shipping_gender,
            ];

    it doesn't work either. Seems to be all $value->xxx are always set, even when not set when saving data from API.

  12. I created a custom fieldtype to store two addresses. It receives its data from a custom form and will later use it in a PDF. However, the problem is, users can save billing and shipping address separately with two slightly different frontend forms. When I save one form only data saved by this from will be saved, all other fields get deleted.

    image.thumb.png.d6829908fe3093503d311da265c115fd.png

    So if the user saves his shipping address all billing fields are empty after the page is saved. First version of my fieldtype only had two textarea fields and everything worked fine. But now changed to have more control over every data field (name, street, etc.).

    I started from copying the Dimension fieldtype, which was a copy of the MapMaker fieldtype I guess.

    Problem should be inside Address::set() or the ___sleepValue()

    // Frontend form to save billing address
    $p->of(false);
    $p->address->billing_gender     = sanitizer()->string( input()->post('gender') );
    $p->address->billing_firstname  = sanitizer()->string( input()->post('first_name') );
    $p->address->billing_lastname   = sanitizer()->string( input()->post('last_name') );
    $p->address->billing_street     = sanitizer()->string( input()->post('street') );
    $p->address->billing_zipcode    = sanitizer()->string( input()->post('zipcode') );
    $p->address->billing_city       = sanitizer()->string( input()->post('city') );
    $p->address->billing_company    = sanitizer()->string( input()->post('company') );
    $p->address->billing_vatid      = sanitizer()->string( input()->post('vatid') );
    $p->address->billing_country    = sanitizer()->int( input()->post('country') );
    $save = $p->save('address');
    <?php namespace ProcessWire;
    
    /**
     * ProcessWire Address Fieldtype
     *
     */
    
    class FieldtypeAddress extends Fieldtype {
    
    
    	/**
    	 * Initialize this Fieldtype
    	 *
    	 */
    	public function init() {
    		parent::init();
    	}
    
    
    
    	/**
    	 * get Inputfield for this fieldtype, set config attributes so they can be used in the inputfield
    	 *
    	 */
    	public function getInputfield(Page $page, Field $field) {
    		$address = $this->modules->get('InputfieldAddress');
    		return $address;
    	}
    
    
    
    	/**
    	 * Get the database schema for this field
    	 *
    	 * @param Field $field In case it's needed for the schema, but usually should not.
    	 * @return array
    	 */
    	public function getDatabaseSchema(Field $field) {
    
    		$schema                            = parent::getDatabaseSchema($field);
    		$schema['data']                    = 'TEXT NOT NULL'; // user last name
    		$schema['data_billing_firstname']  = 'TEXT NOT NULL';
    		$schema['data_billing_gender']     = 'TEXT NOT NULL';
    		$schema['data_billing_company']    = 'TEXT NOT NULL';
    		$schema['data_billing_vatid']      = 'TEXT NOT NULL';
    		$schema['data_billing_street']     = 'TEXT NOT NULL';
    		$schema['data_billing_zipcode']    = 'TEXT NOT NULL';
    		$schema['data_billing_city']       = 'TEXT NOT NULL';
    		$schema['data_billing_country']    = 'TEXT NOT NULL';
    		$schema['data_shipping_lastname']  = 'TEXT NOT NULL';
    		$schema['data_shipping_firstname'] = 'TEXT NOT NULL';
    		$schema['data_shipping_company']   = 'TEXT NOT NULL';
    		$schema['data_shipping_street']    = 'TEXT NOT NULL';
    		$schema['data_shipping_zipcode']   = 'TEXT NOT NULL';
    		$schema['data_shipping_city']      = 'TEXT NOT NULL';
    		$schema['data_shipping_country']   = 'TEXT NOT NULL';
    		$schema['data_shipping_department']= 'TEXT NOT NULL';
    		$schema['data_shipping_gender']    = 'TEXT NOT NULL';
    
    		// Remove index from data column
    		unset($schema['keys']['data']);
    
    		return $schema;
    	}
    
    
    
    	/**
    	 * Any value will get sanitized before setting it to a page object
    	 * and before saving the data
    	 *
    	 */
    	public function sanitizeValue(Page $page, Field $field, $value) {
    
    		if(!$value instanceof Address) $value = $this->getBlankValue($page, $field);
    
    		if (
    			$value->isChanged('billing_company') ||
    			$value->isChanged('billing_gender') ||
    			$value->isChanged('billing_vatid') ||
    			$value->isChanged('billing_firstname') ||
    			$value->isChanged('billing_lastname') ||
    			$value->isChanged('billing_street') ||
    			$value->isChanged('billing_zipcode') ||
    			$value->isChanged('billing_city') ||
    			$value->isChanged('billing_country') ||
    			$value->isChanged('shipping_company') ||
    			$value->isChanged('shipping_firstname') ||
    			$value->isChanged('shipping_lastname') ||
    			$value->isChanged('shipping_street') ||
    			$value->isChanged('shipping_zipcode') ||
    			$value->isChanged('shipping_city') ||
    			$value->isChanged('shipping_country') ||
    			$value->isChanged('shipping_department') ||
    			$value->isChanged('shipping_gender')
    		) {
    			$page->trackChange($field->name);
    		}
    
    		return $value;
    	}
    
    
    
    	/**
    	 * Get raw data values from database and perhaps adjust data for $page output
    	 *
    	 */
    	public function ___wakeupValue(Page $page, Field $field, $value) {
    
    		if(empty($value) ) return false;
    
    		// get blank
    		$address = $this->getBlankValue($page, $field); // TODO: required?
    
    		$country = $this->pages()->get( (int)$value['data_billing_country'] );
    		$address->billing = WireArray::new([
    			'gender'     => (string)$value['data_billing_gender'],
    			'company'    => (string)$value['data_billing_company'],
    			'vatid'      => (string)$value['data_billing_vatid'],
    			'first_name' => (string)$value['data_billing_firstname'],
    			'last_name'  => (string)$value['data'],
    			'street'     => (string)$value['data_billing_street'],
    			'zipcode'    => (string)$value['data_billing_zipcode'],
    			'city'       => (string)$value['data_billing_city'],
    			'country'    => $country,
    			'block'      => (string)$value['data_billing_company'] . PHP_EOL . (string)$value['data_billing_firstname'] . ' ' . (string)$value['data'] . PHP_EOL . (string)$value['data_billing_street'] . PHP_EOL . (string)$value['data_billing_zipcode'] . ' ' . (string)$value['data_billing_city'] . PHP_EOL . (string)$country->title,
    		]);
    
    
    		$country = $this->pages()->get( (int)$value['data_shipping_country'] );
    		$address->shipping = WireArray::new([
    			'gender'     => (string)$value['data_shipping_gender'],
    			'company'    => (string)$value['data_shipping_company'],
    			'department' => (string)$value['data_shipping_department'],
    			'first_name' => (string)$value['data_shipping_firstname'],
    			'last_name'  => (string)$value['data_shipping_lastname'],
    			'street'     => (string)$value['data_shipping_street'],
    			'zipcode'    => (string)$value['data_shipping_zipcode'],
    			'city'       => (string)$value['data_shipping_city'],
    			'country'    => $country,
    			'block'      => (string)$value['data_shipping_company'] . PHP_EOL . (string)$value['data_shipping_firstname'] . ' ' . (string)$value['data_shipping_lastname'] . PHP_EOL . (string)$value['data_shipping_street'] . PHP_EOL . (string)$value['data_shipping_zipcode'] . ' ' . (string)$value['data_shipping_city'] . PHP_EOL . (string)$country->title,
    		]);
    
    
    		return $address;
    	}
    
    
    
    	/**
    	 * Get data from $page and adjust data for storing in database
    	 *
    	 */
    	public function ___sleepValue(Page $page, Field $field, $value) {
    
    		// throw error if value is not of the right type
    		if(!$value instanceof Address) throw new WireException('Expecting an instance of Address');
    
    		$sleepValue = [
    			'data_billing_company'     => (string)$value->billing_company,
    			'data_billing_vatid'       => (string)$value->billing_vatid,
    			'data_billing_gender'      => (string)$value->billing_gender,
    			'data_billing_firstname'   => (string)$value->billing_firstname,
    			'data'                     => (string)$value->billing_lastname,
    			'data_billing_street'      => (string)$value->billing_street,
    			'data_billing_zipcode'     => (string)$value->billing_zipcode,
    			'data_billing_city'        => (string)$value->billing_city,
    			'data_billing_country'     => (string)$value->billing_country,
    			'data_shipping_company'    => (string)$value->shipping_company,
    			'data_shipping_firstname'  => (string)$value->shipping_firstname,
    			'data_shipping_lastname'   => (string)$value->shipping_lastname,
    			'data_shipping_street'     => (string)$value->shipping_street,
    			'data_shipping_zipcode'    => (string)$value->shipping_zipcode,
    			'data_shipping_city'       => (string)$value->shipping_city,
    			'data_shipping_country'    => (string)$value->shipping_country,
    			'data_shipping_department' => (string)$value->shipping_department,
    			'data_shipping_gender'     => (string)$value->shipping_gender,
    		];
    
    
    		return $sleepValue;
    	}
    
    
    
    	/**
    	 * Format value for output
    	 *
    	 */
    	public function ___formatValue(Page $page, Field $field, $value) {
    		return $value;
    	}
    
    
    
    	/**
    	 *
    	 * Add mapping to different name for use in page selectors
    	 * This enables us to use it like "field.min=10, field.max<=200, field.graduation>10"
    	 */
    	public function getMatchQuery($query, $table, $subfield, $operator, $value) {
    		if ($subfield == 'billing_company') $subfield = 'data_billing_company';
    		if ($subfield == 'billing_gender') $subfield = 'data_billing_gender';
    		if ($subfield == 'billing_vatid') $subfield = 'data_billing_vatid';
    		if ($subfield == 'billing_firstname') $subfield = 'data_billing_firstname';
    		if ($subfield == 'billing_lastname') $subfield = 'data';
    		if ($subfield == 'billing_street') $subfield = 'data_billing_street';
    		if ($subfield == 'billing_zipcode') $subfield = 'data_billing_zipcode';
    		if ($subfield == 'billing_city') $subfield = 'data_billing_city';
    		if ($subfield == 'billing_country') $subfield = 'data_billing_country';
    		if ($subfield == 'shipping_company') $subfield = 'data_shipping_company';
    		if ($subfield == 'shipping_firstname') $subfield = 'data_shipping_firstname';
    		if ($subfield == 'shipping_lastname') $subfield = 'data_shipping_lastname';
    		if ($subfield == 'shipping_street') $subfield = 'data_shipping_street';
    		if ($subfield == 'shipping_zipcode') $subfield = 'data_shipping_zipcode';
    		if ($subfield == 'shipping_city') $subfield = 'data_shipping_city';
    		if ($subfield == 'shipping_country') $subfield = 'data_shipping_country';
    		if ($subfield == 'shipping_department') $subfield = 'data_shipping_department';
    		if ($subfield == 'shipping_gender') $subfield = 'data_shipping_gender';
    
    		return parent::getMatchQuery($query, $table, $subfield, $operator, $value);
    	}
    
    
    
    	/**
    	 * there's none compatible
    	 *
    	 */
    	public function ___getCompatibleFieldtypes(Field $field) {
    		return null;
    	}
    
    
    
    	/**
    	 * blank value is an WireData object Address
    	 *
    	 */
    	public function getBlankValue(Page $page, Field $field) {
    		return new Address();
    	}
    
    
    
    	/**
    	 * Get any inputfields used for configuration of this Fieldtype.
    	 *
    	 * This is in addition any configuration fields supplied by the parent Inputfield.
    	 *
    	 * @param Field $field
    	 * @return InputfieldWrapper
    	 *
    	 */
    	public function ___getConfigInputfields(Field $field) {
    		$inputfields = parent::___getConfigInputfields($field);
    		// nothing yet
    		return $inputfields;
    	}
    
    }
    
    
    
    
    
    /**
     * Helper WireData Class to hold an address object
     *
     */
    class Address extends WireData {
    
    	public function __construct() {
    		// bd('address construct');
    		// $this->set('billing_company', null);
    		// $this->set('billing_gender', null);
    		// $this->set('billing_vatid', null);
    		// $this->set('billing_firstname', null);
    		// $this->set('billing_lastname', null);
    		// $this->set('billing_street', null);
    		// $this->set('billing_zipcode', null);
    		// $this->set('billing_city', null);
    		// $this->set('billing_country', null);
    		// $this->set('shipping_company', null);
    		// $this->set('shipping_firstname', null);
    		// $this->set('shipping_lastname', null);
    		// $this->set('shipping_street', null);
    		// $this->set('shipping_zipcode', null);
    		// $this->set('shipping_city', null);
    		// $this->set('shipping_country', null);
    		// $this->set('shipping_department', null);
    		// $this->set('shipping_gender', null);
    	}
    
    
    	public function set($key, $value) {
    		bd('VALUE: '.$value, 'address set: ' . $key );
    
    		// if (
    		// 	$key == 'billing_company' ||
    		// 	$key == 'billing_gender' ||
    		// 	$key == 'billing_vatid' ||
    		// 	$key == 'billing_firstname' ||
    		// 	$key == 'billing_lastname' ||
    		// 	$key == 'billing_street' ||
    		// 	$key == 'billing_zipcode' ||
    		// 	$key == 'billing_city' ||
    		// 	$key == 'billing_country' ||
    		// 	$key == 'shipping_company' ||
    		// 	$key == 'shipping_firstname' ||
    		// 	$key == 'shipping_lastname' ||
    		// 	$key == 'shipping_street' ||
    		// 	$key == 'shipping_zipcode' ||
    		// 	$key == 'shipping_city' ||
    		// 	$key == 'shipping_department' ||
    		// 	$key == 'shipping_gender' ||
    		// 	$key == 'shipping_country'
    		// ) {
    		// 	if(!is_string($value) && !is_int($value) && !is_null($value)) {
    		// 		$value = $this->$key ? $this->$key : 0;
    		// 		throw new WireException("Address Object only accepts string (string) values");
    		// 	}
    		// }
    		return parent::set($key, $value);
    	}
    
    	public function get($key) {
    		// bd('address get: ' . $key);
    		return parent::get($key);
    	}
    
    }

     

  13. I have a field 'history' to track some field's changes. When changing, for example, the field 'state' in the PW backend I get correct result (1 entry).

    But when I set 'state' from a template file with:

    $page->of(false);
    $page->state = 1138; // field state is Page reference and 1138 is a state with title New
    $page->save('state');
    $page->of(true);

    … I have two entries in the 'history' field:

    2020-02-06 16:19:40    State -/- => New
    2020-02-06 16:19:40    State -/- => -/-
    $this->addHookAfter('Page(template=testtemplate)::changed()', function($event) {
    
    	/* @var $event HookEvent */
    	/* @var $page Page */
    	$page = $event->object;
    	$field = $event->arguments(0); // field
    	$old = $event->arguments(1); // old value
    	$new = $event->arguments(2); // new value
    
    	$track_fields = ['title', 'state', 'items'];
    	if (!in_array($field, $track_fields)) return;
    
    	$label = fields()->get($field)->getLabel();
    	bd($old, $label . ' old');
    	bd($new, $label . ' new');
    
    
    	$old_value = ($old instanceof Page) ? $old->title : '-/-';
    	$new_value = ($new instanceof Page) ? $new->title : '-/-';
    
    
    	$history = date('Y-m-d H:i:s') . "\t" . $label . ' ' . $old_value . ' => ' . $new_value;
    
    	// $page->history = $page->history . PHP_EOL . $history;
    	$page->setAndSave('history', $page->history . PHP_EOL . $history);
    });

    Running this in TracyDebugger will result in two entries as well:

    $page->setAndSave('state', 'new');

     

  14. I changed my default setcookie() functions to the newly added $input->cookie method as described in https://processwire.com/blog/posts/pw-3.0.141/

    Just noticed no cookies are saved when using PW's $input->cookie->set() (in template file). I am using PW 3.0.148, PHP 7.3 and testing with setcookie('test', 'test') works just fine. Tried to add age, path and domain as well, but nothing works.

    setcookie('defaultsetcookie', 'works');
    
    $config->cookieOptions = [
      'age' => 604800,
      'path' => null,
      'domain' => null,
      'secure' => null,
      'httponly' => false,
      'fallback' => true
    ];
    
    $c = $input->cookie->set('pwcookie', 'wontwork');
    print_r( $c );
    print_r( $_COOKIE );

    Output

    ProcessWire\WireInputDataCookie Object
    (
        [defaultsetcookie] => works
        [wire] => 89ortkjmq5dsgb7em2h6ljod9v
        [pwcookie] => wontwork
    )
    Array
    (
        [defaultsetcookie] => works
        [wire] => 89ortkjmq5dsgb7em2h6ljod9v
        [pwcookie] => wontwork
    )

    Any idea what is wrong? It is strange setcookie() works but PW methods won't.

  15. When I check if the page has an image attached, I get the error 

    PHP Warning: count(): Parameter must be an array or an object that implements Countable in 

    But this should be the correct way

    if ( count(page()->images) ) {
       $heroimage = page()->images->first()->url;
    } elseif ( pages()->get('/')->images->first()->url ) {
       $heroimage = pages()->get('/')->images->first()->url;
    }

    I found some issues with this on GitHub, but it was fixed. Using PHP 7.3 and PW 148 (same issue before update).

  16. I've got an existing (pro field) textareas field containing two Page Reference fields.

    Do you know if subfields are supported using field templates? Those won't work 

    $page->render('related', 'textareas/subfield');
    $page->render->textareas; // will output both subfields

     

  17. Thanks for the link. Had not found the source. It seems the 'data-close' button will only listen for clicks if it is defined in 'data-buttons' as well. But all buttons living there will get the same design. Not that good, when Save and Cancel look the same, but it will work for now.

×
×
  • Create New...