Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/pricing fields #293

Merged
merged 20 commits into from
Aug 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/Data/EntryObjectMutation.php
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,19 @@ public static function get_field_value_input( array $args, array $form, bool $is
case 'post_image':
$field_value_input = FieldValueInput\ImageValuesInput::class;
break;
case 'hiddenproduct':
case 'singleproduct':
case 'calculation':
$field_value_input = FieldValueInput\ProductValueInput::class;
break;
case 'date':
case 'hidden':
case 'number':
case 'phone':
case 'post_content':
case 'post_excerpt':
case 'post_title':
case 'price':
case 'radio':
case 'select':
case 'text':
Expand Down
106 changes: 106 additions & 0 deletions src/Data/FieldValueInput/ProductValueInput.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
<?php
/**
* Manipulates input data for Product field values.
*
* @package WPGraphQL\GF\Data\FieldValueInput
* @since @todo
*/

namespace WPGraphQL\GF\Data\FieldValueInput;

use GFCommon;
use GraphQL\Error\UserError;

/**
* Class - ProductValueInput
*/
class ProductValueInput extends AbstractFieldValueInput {
/**
* {@inheritDoc}
*
* @var array
*/
protected $args;

/**
* {@inheritDoc}
*
* @var array
*/
public $value;

/**
* {@inheritDoc}
*/
protected function get_field_name() : string {
return 'productValues';
}

/**
* {@inheritDoc}
*
* @throws UserError .
*/
protected function is_valid_input_type() : bool {
$is_valid = false;

// Calculation fields need a quantity and price.
if ( 'calculation' === $this->field->get_input_type() && ( ! isset( $this->input_args[ $this->field_name ]['quantity'] ) || ! isset( $this->input_args[ $this->field_name ]['price'] ) ) ) {
return $is_valid;
}

// Fields using `productValues` need a quantity.
if ( isset( $this->input_args[ $this->field_name ] ) && isset( $this->input_args[ $this->field_name ]['quantity'] ) ) {
return true;
}

// Fields using `value` must use it as the quantity.
if ( isset( $this->input_args['value'] ) ) {
if ( ! floatval( $this->input_args['value'] ) ) {
throw new UserError(
sprintf(
// translators: field ID, input key.
__( 'Mutation not processed. Field %1$s requires the use of `%2$s` as a valid quantity.', 'wp-graphql-gravity-forms' ),
$this->field->id,
'value',
)
);
}
return true;
}

return $is_valid;
}

/**
* {@inheritDoc}
*
* @return array
*/
public function get_args() {
return $this->input_args[ $this->field_name ] ?? [
'quantity' => $this->input_args['value'],
'price' => null,
];
}

/**
* {@inheritDoc}
*/
protected function prepare_value() {
$field = $this->field;

return [
(string) $field->inputs[0]['id'] => $field->label,
(string) $field->inputs[1]['id'] => ! empty( $this->args['price'] ) ? GFCommon::format_number( $this->args['price'], 'currency' ) : $field->basePrice,
(string) $field->inputs[2]['id'] => floatval( $this->args['quantity'] ),
];
}

/**
* {@inheritDoc}
*/
public function add_value_to_submission( array &$field_values ) : void {
$field_values += $this->value;
}
}
31 changes: 31 additions & 0 deletions src/Data/FieldValueInput/ValueInput.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,45 @@

namespace WPGraphQL\GF\Data\FieldValueInput;

use GFCommon;
/**
* Class - ValueInput
*/
class ValueInput extends AbstractFieldValueInput {
/**
* {@inheritDoc}
*
* @var string
*/
protected $args;

/**
* {@inheritDoc}
*/
protected function get_field_name() : string {
return 'value';
}

/**
* {@inheritDoc}
*/
protected function prepare_value() : string {
// Handle choices with price.
if ( property_exists( $this->field, 'enablePrice' ) && $this->field->enablePrice && false === strpos( $this->args, '|' ) ) {
$value_key = property_exists( $this->field, 'enableChoiceValue' ) && $this->field->enableChoiceValue ? 'value' : 'text';

$choice_key = array_search( $this->args, array_column( $this->field->choices, $value_key ), true );

$choice = $this->field->choices[ $choice_key ];

$price = rgempty( 'price', $choice ) ? 0 : GFCommon::to_number( rgar( $choice, 'price' ) );

return $this->args . '|' . $price;
} elseif ( 'total' === $this->field->type ) {
// Convert to number so draft updates dont return the currency.
return GFCommon::to_number( $this->args );
}

return $this->args;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class SignatureValuesInput extends ValueInput {
/**
* {@inheritDoc}
*/
protected function prepare_value() {
protected function prepare_value() : string {
$value = $this->args;

$this->ensure_signatures_folder_exists();
Expand Down
3 changes: 3 additions & 0 deletions src/Mutation/UpdateEntry.php
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,9 @@ private static function prepare_field_values( array $field_values, array $entry,
* @param array $form the existing form.
*/
public static function prepare_field_values_for_save( array $values, array $entry, array $form ) : array {
// We need the entry fresh to prepare the values.
$entry = array_merge( $entry, $values );

foreach ( $values as $id => &$value ) {
$input_name = 'input_' . str_replace( '.', '_', $id );
$field_id = strtok( $id, '.' );
Expand Down
5 changes: 4 additions & 1 deletion src/Registry/FieldChoiceRegistry.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,13 @@ public static function get_type_name( GF_Field $field ) : string {
$input_type = $field->get_input_type();

switch ( true ) {
// Post Category choices are on the interface.
// Some choices belong on the the interface.
case 'post_category' === $field->type:
$input_name = 'PostCategoryFieldChoice';
break;
case 'option' === $field->type:
$input_name = 'OptionFieldChoice';
break;
default:
$input_name = ( $field->type !== $input_type ? $field->type . '_' . $input_type : $field->type ) . 'FieldChoice';
}
Expand Down
21 changes: 18 additions & 3 deletions src/Registry/FormFieldRegistry.php
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ protected static function register_interface_and_types( GF_Field $field, array $
continue;
}

$possible_settings[ $gf_type ] = $child_field->get_form_editor_field_settings();
$possible_settings[ $gf_type ] = self::get_field_settings( $child_field );
}

// We flip the arrays and compare the keys for performance.
Expand Down Expand Up @@ -174,7 +174,12 @@ function( TypeRegistry $type_registry ) use ( $field, $interface_settings, $poss

// Loop through the child fields and register each one.
foreach ( $possible_types as $gf_type => $graphql_type ) {
$field_to_register = clone( $field );
if ( in_array( $gf_type, [ 'calculation', 'hiddenproduct', 'singleproduct', 'singleshipping' ], true ) ) {
// These possible types are actually their own GF_Field classes that were skipped in the register() loop.
$field_to_register = GF_Fields::get( $gf_type );
} else {
$field_to_register = clone( $field );
}

// Override the field config from the inherited GF field with those from the child type.
$field_to_register->inputType = $gf_type;
Expand All @@ -197,7 +202,13 @@ function( TypeRegistry $type_registry ) use ( $field, $interface_settings, $poss
* @param GF_Field $field .
*/
public static function get_field_settings( GF_Field $field ) : array {
$settings = $field->get_form_editor_field_settings();
$settings = $field->get_form_editor_field_settings();

// Product inputs are not stored as a setting, so we're going to fake it.
if ( 'singleproduct' === $field->type ) {
$settings[] = 'single_product_inputs';
}

$input_type = $field->get_input_type();

// Bail early if the types are the same.
Expand Down Expand Up @@ -390,6 +401,10 @@ public static function get_field_value_fields( GF_Field $field ) : array {
case 'post_image':
$fields += FieldValues::image_values();
break;
case 'singleproduct':
case 'product':
$fields += FieldValues::product_values();
break;
case 'time':
$fields += FieldValues::time_values();
break;
Expand Down
6 changes: 5 additions & 1 deletion src/Registry/TypeRegistry.php
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ private static function inputs() : array {
Input\FormsConnectionOrderbyInput::class,
Input\ListFieldInput::class,
Input\NameFieldInput::class,
Input\ProductFieldInput::class,
Input\SubmitFormMetaInput::class,
Input\UpdateDraftEntryMetaInput::class,
Input\UpdateEntryMetaInput::class,
Expand Down Expand Up @@ -276,10 +277,11 @@ public static function objects() : array {
// Form Field Value properties.
WPObject\FormField\FieldValue\ValueProperty\AddressFieldValue::class,
WPObject\FormField\FieldValue\ValueProperty\CheckboxFieldValue::class,
WPObject\FormField\FieldValue\ValueProperty\ImageFieldValue::class,
WPObject\FormField\FieldValue\ValueProperty\FileUploadFieldValue::class,
WPObject\FormField\FieldValue\ValueProperty\ListFieldValue::class,
WPObject\FormField\FieldValue\ValueProperty\NameFieldValue::class,
WPObject\FormField\FieldValue\ValueProperty\ImageFieldValue::class,
WPObject\FormField\FieldValue\ValueProperty\ProductFieldValue::class,
WPObject\FormField\FieldValue\ValueProperty\TimeFieldValue::class,
// Form Fields.
WPObject\FormField\FormFields::class,
Expand Down Expand Up @@ -375,6 +377,7 @@ public static function form_field_settings() : array {
'rich_text_editor_setting' => WPInterface\FieldSetting\FieldWithRichTextEditor::class,
'rules_setting' => WPInterface\FieldSetting\FieldWithRules::class,
'select_all_choices_setting' => WPInterface\FieldSetting\FieldWithSelectAllChoices::class,
'single_product_inputs' => WPInterface\FieldSetting\FieldWithSingleProductInputs::class,
'size_setting' => WPInterface\FieldSetting\FieldWithSize::class,
'sub_label_placement_setting' => WPInterface\FieldSetting\FieldWithSubLabelPlacement::class,
'time_format_setting' => WPInterface\FieldSetting\FieldWithTimeFormat::class,
Expand Down Expand Up @@ -405,6 +408,7 @@ public static function form_field_setting_inputs() : array {
'password_setting' => WPInterface\FieldInputSetting\InputWithPassword::class,
'select_all_choices_setting' => WPInterface\FieldInputSetting\InputWithSelectAllChoices::class,
'time_format_setting' => WPInterface\FieldInputSetting\InputWithTimeFormat::class,
'single_product_inputs' => WPInterface\FieldInputSetting\InputWithSingleProduct::class,
];

/**
Expand Down
4 changes: 4 additions & 0 deletions src/Type/Input/FormFieldValuesInput.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,10 @@ public static function get_fields() : array {
'type' => NameFieldInput::$type,
'description' => __( 'The form field values for Name fields.', 'wp-graphql-gravity-forms' ),
],
'productValues' => [
'type' => ProductFieldInput::$type,
'description' => __( 'The form field values for Name fields.', 'wp-graphql-gravity-forms' ),
],
'values' => [
'type' => [ 'list_of' => 'String' ],
'description' => __( 'The form field values for fields that accept multiple string values. Used by MultiSelect, Post Category, Post Custom, and Post Tags fields.', 'wp-graphql-gravity-forms' ),
Expand Down
45 changes: 45 additions & 0 deletions src/Type/Input/ProductFieldInput.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php
/**
* GraphQL Input Type - ProductFieldInput
* Input fields for a product.
*
* @package WPGraphQL\GF\Type\Input
* @since 0.5.0
*/

namespace WPGraphQL\GF\Type\Input;

/**
* Class - ProductFieldInput
*/
class ProductFieldInput extends AbstractInput {
/**
* Type registered in WPGraphQL.
*
* @var string
*/
public static string $type = 'ProductFieldInput';

/**
* {@inheritDoc}
*/
public static function get_description() : string {
return __( 'Input fields for Product field.', 'wp-graphql-gravity-forms' );
}

/**
* {@inheritDoc}
*/
public static function get_fields() : array {
return [
'quantity' => [
'type' => 'Float',
'description' => __( 'Product quantity.', 'wp-graphql-gravity-forms' ),
],
'price' => [
'type' => 'Float',
'description' => __( 'Product price.', 'wp-graphql-gravity-forms' ),
],
];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public static function get_fields() : array {
public static function add_fields_to_child_type( array $fields, string $choice_name, GF_Field $field, array $settings, array $interfaces ) : array {
if (
! in_array( self::$type, $interfaces, true ) ||
( empty( $field->enablePrice ) && ! in_array( $field->type, [ 'product', 'option', 'shipping' ], true ) )
( empty( $field->enablePrice ) && ! in_array( $field->type, [ 'product', 'quantity', 'option', 'shipping' ], true ) )
) {
return $fields;
}
Expand Down
Loading