Jump to content

IPCommerceFan

Clients
  • Posts

    493
  • Joined

  • Last visited

 Content Type 

Downloads

Release Notes

IPS4 Guides

IPS4 Developer Documentation

Invision Community Blog

Development Blog

Deprecation Tracker

Providers Directory

Forums

Events

Store

Gallery

Everything posted by IPCommerceFan

  1. Have you tried something like: {{sort($images); sort($thumbs);}} Before plugging them into the foreach loop? sort() sorts by value, so if the value is the filename, it should align them.
  2. 4.6.7 - All 3rd party apps/plugins disabled: It looks like there is a ( PHP 8 ) TypeError in applications\nexus\sources\Package\Package.php, in the upgradeDowngrade function, lines 3427 and 3433. TypeError: count(): Argument #1 ($value) must be of type Countable|array, null given (0) #0 /home/user/public_html/applications/nexus/extensions/nexus/Item/UpgradeCharge.php(59): IPS\nexus\_Package->upgradeDowngrade(Object(IPS\nexus\Purchase), Object(IPS\nexus\Package\Product), NULL, true) #1 /home/user/public_html/applications/nexus/sources/Invoice/Invoice.php(1747): IPS\nexus\extensions\nexus\Item\_UpgradeCharge->onPaid(Object(IPS\nexus\Invoice)) #2 /home/user/public_html/applications/nexus/modules/front/checkout/checkout.php(1514): IPS\nexus\_Invoice->markPaid() #3 /home/user/public_html/system/Helpers/Wizard/Wizard.php(181): IPS\nexus\modules\front\checkout\_checkout->_pay(Array) #4 /home/user/public_html/applications/nexus/modules/front/checkout/checkout.php(170): IPS\Helpers\_Wizard->__toString() #5 /home/user/public_html/system/Dispatcher/Controller.php(101): IPS\nexus\modules\front\checkout\_checkout->manage() #6 /home/user/public_html/applications/nexus/modules/front/checkout/checkout.php(57): IPS\Dispatcher\_Controller->execute() #7 /home/user/public_html/system/Dispatcher/Dispatcher.php(153): IPS\nexus\modules\front\checkout\_checkout->execute() #8 /home/user/public_html/index.php(13): IPS\_Dispatcher->run() #9 {main} If the package you are upgrading does not have any Renewal Options, there is nothing to count(), so a TypeError is thrown due to NULL not being countable. Suggest changing this: if ( \count( $renewalOptions ) === 1 ) { $term = array_pop( $renewalOptions ); } elseif ( \count( $renewalOptions ) !== 0 ) { throw new \InvalidArgumentException; } to: if ( \is_countable( $renewalOptions) && \count( $renewalOptions ) === 1 ) { $term = array_pop( $renewalOptions ); } elseif ( \is_countable( $renewalOptions) && \count( $renewalOptions ) !== 0 ) { throw new \InvalidArgumentException; } Confirmed the fix first by adding some renewal options. This worked. Then confirmed by whipping up a plugin that redeclares the whole function with the fix included. It works as it should now. 👍
  3. I would love to be able to react to guides, because I'd be +1'ing this one if I could. lol
  4. I wonder if it'd be worthwhile to include a check before running the upgrader, to make sure the suite isn't in dev mode? If it is, don't allow the upgrade and instruct how to turn off dev mode? OR, what if dev tools were ready prior to the official release, and clicking "Upgrade" upgraded both the suite AND the dev tools seamlessly (only if the dev tools are present already)? Just ideas!
  5. Hi Stan, Wish I could help, but I will say it looks like you posted in Developer Connection, so you probably won't catch the attention of staff as quickly here. IPS has stated they have staff manning the Community Support forum as a first line support method: https://invisioncommunity.com/forums/forum/406-community-support/ You should be able to create a support request though, via your Client Area: https://invisioncommunity.com/clientarea/purchases/
  6. By the way, strictly answering your question, this is how you send array fields via URL: customFields[3]=foo&customFields[4]=bar
  7. Hi @Roboko Here's an example you can plug into a custom php block for testing purposes. Just update communityUrl, apiKey, and the specified member ID: <?php //REST API URL and KEY $communityUrl = 'https://www.yourdomain.com/'; $apiKey = 'abcdefghijklmnopqrstuvwxyz123456'; $id = 1; //Member ID // REST Endpoint $endpoint = "/core/members/{$id}"; $curl = curl_init( $communityUrl . 'api' . $endpoint ); // POST data $curl_post_data = array( 'customFields' => array( '3' => 'foo', '4' => 'bar' ), ); // Prepare data for cURL POST $curl_post_data = urldecode(http_build_query($curl_post_data)); //Turn parameter array into a string that looks like 'category=1&author=1&title=test file', etc. Only non-null items are included in this list. urldecode turns characters like %26 back into &. // POST Data curl_setopt_array( $curl, array( CURLOPT_RETURNTRANSFER => TRUE, CURLOPT_HTTPAUTH => CURLAUTH_BASIC, CURLOPT_USERPWD => "{$apiKey}:", CURLOPT_POST => TRUE, CURLOPT_POSTFIELDS => $curl_post_data ) ); // Get Response JSON $response = curl_exec( $curl ); // Build object $response = json_decode($response); echo \IPS\Member::load($response->id)->url()->setQueryString( 'tab', 'field_core_pfield_3' ); echo \IPS\Member::load($response->id)->url()->setQueryString( 'tab', 'field_core_pfield_4' ); Hope it helps!
  8. Yeah same results here, though I have to assume most probably pay to remove the "Powered by Invision Community" line if they're selling products. There is no built-in functionality which would call up a specific picture based on form selections. There is functionality which can change stock level or price depending on which options are selected on the form, though, so a developer could likely look at how this works and apply the same logic to which image is displayed, of the uploaded package images. e.g.: The form: The package: This is what a developer could probably accomplish: mockup Where the dropdown options are sourced from here: Ultimately I feel this should be a built-in functionality since you see it everywhere, but the fact it can be willed into existence with some code is at least a benefit of using this platform. I explored Shopify and BigCommerce a few years ago, but ultimately came back to Commerce due to its flexibility for our use case, and the integrated support ticket system.
  9. You might try searching google for "Store" and "Powered by Invision Community". We've used Commerce (Nexus) for almost a decade with great success: https://www.trifectaperformance.com/ Our use case might be considered a "simple" implementation, but given Commerce runs on IC's framework, the sky is the limit if some functionality that doesn't exist is needed.
  10. @Liloz01, I'd say the comments in the source files are a pretty good form of documentation. I use a 3rd party app called FileLocator aka Agent Ransack to search the source files for these sorts of things: We knew exactly what to search for in this case, but a search for just "moderator" would have ultimately led to the same result since the comment includes the word in line 72. I'm no programmer, but this tool along with a good IDE like PhpStorm have made all the difference in developing my own plugins as the need arises! As for how to know what you can do with \IPS\Member::loggedIn, I'd search for "\IPS\Member" and browse around to see how it is used, especially as it pertains to functions which accept a Member object. (To find it used strictly in functions I'd search for "@param \IPS\Member") e.g.: \IPS\Member::loggedIn()->memberPostCount() /** * Post count for member * * @param \IPS\Member $member The member * @param bool $includeNonPostCountIncreasing If FALSE, will skip any posts which would not cause the user's post count to increase * @param bool $includeHiddenAndPendingApproval If FALSE, will skip any hidden posts, or posts pending approval * @return int */ public static function memberPostCount( \IPS\Member $member, bool $includeNonPostCountIncreasing = FALSE, bool $includeHiddenAndPendingApproval = TRUE ) Hope that helps!
  11. Agreed, adding campaign-specific options would be great. I believe the first option may only ever apply to purchases (thus I would make it apply only to them), though I admittedly haven't considered how anyone might use it for any of the other campaign types.
  12. Valid point! (no pun intended haha) Bill Gates used to say in meetings when presented with something that didn't make sense: "I'm confused." If you really mucked it up, he'd say "You're confused.". 😄 Anyway, the validation is to make sure valid regex is entered into the field, so it should be language agnostic.. The reason it is Translatable is simply because I'm trying to stick to the conventions set out in the 3rd party application I'm writing a plugin for (all the other fields that would normally be 'Text' are 'Translatable' here). So, the use of the Translatable field is sort of a "when in Rome" approach. 🙂 Btw if we _really_ want to nitpick, I should have also used a language string for ' is not a valid regex string.', but it was an acceptable casualty. Maybe I'll go fix it later. lol edit: I think I see what you're saying now, but it probably still doesn't matter since this plugin won't see any sort of distribution beyond my own site where only one language string is in use. Fair warning to anyone considering this method though!
  13. In that same vein, if the originating "type" (like a purchase) is cancelled, I think it would be reasonable to expect the campaign instance to be cancelled as well. e.g. Someone buys a product, a campaign fires and queues up an email to be sent 30 days later requesting a product review. If the customer changes their mind and the purchase is cancelled, we wouldn't want that email to still go out.
  14. @liquidfractal, I discovered this need as well last night! I've found that there is a check that asks "Does this campaign ID exist for this member already?". If its true, then you can't add any more of the same campaign. I think if we had some extra criteria added to Instances, we could get around this. For example, maybe we could use the purchase id? If the campaign ID and purchase ID pair exist for a given member, don't create an Instance. If the purchase has never had the particular campaign run on it, run it! This way a member can have multiple instances of the same campaign active, but associated to the individual purchases. To get the purchase id, maybe we could capture it when the instance is created via purchase? We'd use the purchase id as the search criteria instead of the package id, then when actually launching the instance, we could save the purchase id as some variable, then redeclare the package id as the value for that function in order to keep it working the way it normally does (because we still want to only run the campaign only on certain packages). Just some thoughts!
  15. Ahh, I thought it conspicuous that 1 wasn't a 0 (my assumption being it represented the first item in an array) I've modified it to indicate the language key for the logged in member: $form->add ( new \IPS\Helpers\Form\Translatable( 'dripcampaigns_step_vin_regex', NULL, NULL, array( 'placeholder' => '/[A-Z0-9]+/i', 'app' => 'dripcampaigns', 'key' => $this->id ? "dripcampaigns_step_vin_regex_{$this->id}" : NULL ), function( $val ) { $langID = \IPS\Member::loggedIn()->language()->id; if ( $val[$langID] AND @preg_match( $val[$langID], NULL ) === false ) { throw new \DomainException( $val[$langID] . ' is not a valid regex string.'); } } ) ); return parent::form( $form ); Thanks again!
  16. I gave it a shot: $form->add ( new \IPS\Helpers\Form\Translatable( 'dripcampaigns_step_vin_regex', NULL, NULL, array( 'placeholder' => '/[A-Z0-9]+/i', 'app' => 'dripcampaigns', 'key' => $this->id ? "dripcampaigns_step_vin_regex_{$this->id}" : NULL ), function( $val ) { if ( $val[1] AND @preg_match( $val[1], NULL ) === false ) { throw new \DomainException($val[1] . ' is not a valid regex string'); } } ) ); It worked! Upon closer inspection, it appears I had a parenthesis where one didn't belong, so this was ultimately a syntax error: 'key' => ( $this->id Incidentally, the validation was treating $val as an array rather than a string, so validation kept failing. e.g. If we json_encode the array, it appears like this: Thus changing $val to $val[1] fixed it, though I get the impression this field value should not be treated as an array in the first place. In any case, this works now! Thanks again for taking a look @Daniel F! Your support is very much appreciated.
  17. Thanks Daniel. I tried and failed, then. lol This is how I was attempting to use it: $form->add( new \IPS\Helpers\Form\Translatable( 'dripcampaigns_step_vin_regex', $this->id ? $this->input_format : NULL, FALSE, array( 'placeholder' => '/[A-Z0-9]+/i', 'app' => 'dripcampaigns', 'key' => ( $this->id ? "dripcampaigns_step_vin_regex_{$this->id}" : NULL ), function( $val ) { if ( $val AND @preg_match( $val, NULL ) === false ) { throw new \DomainException('form_bad_value'); } }, NULL, NULL, 'dripcampaigns_step_vin_regex' ) ) ); It seems to not even try to run the custom validation code this way. The regex validation is copied from system\CustomField (notably a Text field): $form->add( new \IPS\Helpers\Form\Text( 'pf_input_format', $this->id ? $this->input_format : NULL, FALSE, array( 'placeholder' => '/[A-Z0-9]+/i' ), function( $val ) { if ( $val AND @preg_match( $val, NULL ) === false ) { throw new \DomainException('form_bad_value'); } }, NULL, NULL, 'pf_input_format' ) ); If I re-format it as a text field, it works: $form->add( new \IPS\Helpers\Form\Text( 'dripcampaigns_step_vin_regex', $this->id ? $this->input_format : NULL, FALSE, array( 'placeholder' => '/[A-Z0-9]+/i' ), function( $val ) { if ( $val AND @preg_match( $val, NULL ) === false ) { throw new \DomainException('form_bad_value'); } }, NULL, NULL, 'dripcampaigns_step_vin_regex' ) ); It needs to be Translatable so that the value can be stored as a language string when the form is submitted though. Thank you for pointing me in the right direction. I'll look at CustomItem and report back if I get it to work!
  18. Does Translatable support $customValidationCode as of 4.6.5.1? I just finished a brain-bending session in 4.4.10 trying to get it to work to no avail despite it working fine with \IPS\Helpers\Form\Text After discovering this thread I went ahead and implemented the validation somewhere else.
  19. Hello, Thank you for developing this application! We are upgrading from 4.4.10 to 4.6.5.1 soon, and one of the reasons we haven't upgraded yet is our dependence on the no-longer-supported Rules application. We use it to perform actions both immediately after a purchase is made, as well as some amount of time later. We can do the "immediately after" stuff via creating our own plugins, but not the "some amount of time later" things. Its beyond my abilities to create a scheduler for that. Upon installing (the 4.4.10 version) Email Drip Campaigns, I see a couple of areas for improvement that would really help our use case. 1. The ability to evaluate the purchase custom fields to see if the campaign should be run or not. For example, a vehicle's identification number informs a lot of these decisions. If it is a 2011 Chevrolet Cruze, request some specific information about the transmission. If it is a 2017 and up vehicle, request some other information. If the purchase is for some custom widget, send an email to our warehouse staff to specifically package it up. 2. In addition to the actions of "Send an email" and "Send a personal conversation", we would benefit from "Send a Support Request", where we also associate the purchase to the request. 3. In lieu of adding a specific action, it would be nice if we could "Run custom php", and basically just use the same code we've always used, but triggered by EDC instead of Rules. All in all, we are looking forward to replacing Rules with EDC because it fulfills all we ever used Rules for anyway. We just need it to be able to create support requests, and evaluate custom fields. Thanks again!
  20. Hi, You can disable individual modules here: AdminCP -> System -> Applications Just click where it says "Enabled" to disable it.
  21. What happens if you echo $select->query, and copy the query into phpmyadmin or some other mysql console? Does the query look like you think it should? Often times I've used this method to figure out a syntax error in the php version of the query.
  22. Underflow exception would indicate there aren't any results for the query, I've seen. If it is normal for this query to sometimes not return a result, then you may need to try: {{ try { $select = \IPS\Db::i()->select( 'cms_custom_database_12.field_142 as preco, cms_custom_database_12.field_154 as link, cms_custom_database_12.record_updated as atualizado, cms_custom_database_13.field_143 as loja, cms_custom_database_13.record_image_thumb as logo, cms_custom_database_13.field_160 as cupom, cms_custom_database_13.field_161 as cupom_valor, cms_custom_database_13.primary_id_field as loja_ID', 'cms_custom_database_12', array( array( 'field_156=?', $row->primary_id_field ), array( 'field_141=?', 1 ) ), 'cms_custom_database_12.field_142 ASC')->join( 'cms_custom_database_13', 'cms_custom_database_13.primary_id_field=field_155', 'INNER' )->first(); } catch( \UnderflowException $e ) { $select = ''; } }} Do you get any results when you run this query in mysql directly? SET @field_156 ='yourdata'; SELECT cms_custom_database_12.field_142 as preco, cms_custom_database_12.field_154 as link, cms_custom_database_12.record_updated as atualizado, cms_custom_database_13.field_143 as loja, cms_custom_database_13.record_image_thumb as logo, cms_custom_database_13.field_160 as cupom, cms_custom_database_13.field_161 as cupom_valor, cms_custom_database_13.primary_id_field as loja_ID FROM cms_custom_database_12 INNER JOIN cms_custom_database_13 ON cms_custom_database_13.primary_id_field = cms_custom_database_12.field_155 WHERE field_156 = @field_156 AND field_141=1 ORDER BY cms_custom_database_12.field_142 ASC LIMIT 1;
  23. I hope this isn't stating the obvious, but what happens when you try this? {{$select = \IPS\Db::i()->select( 'cms_custom_database_12.field_142 as preco, cms_custom_database_12.field_154 as link, cms_custom_database_12.record_updated as atualizado, cms_custom_database_13.field_143 as loja, cms_custom_database_13.record_image_thumb as logo, cms_custom_database_13.field_160 as cupom, cms_custom_database_13.field_161 as cupom_valor, cms_custom_database_13.primary_id_field as loja_ID', 'cms_custom_database_12', array( array( 'field_156=?', $row->primary_id_field ), array( 'field_141=?', 1 ) ), 'cms_custom_database_12.field_142 ASC')->join( 'cms_custom_database_13', 'cms_custom_database_13.primary_id_field=field_155', 'INNER' )->first();}}
  24. That should work, however I would verify by testing on a single post first. After REPLACE(), add WHERE pid = 1234; (post ID of a post that contains the emoji you're replacing)
×
×
  • Create New...