SHARE
TWEET

Untitled

a guest Jul 16th, 2019 70 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. <?php
  2. /**
  3.  * Config for WPGraphQL ACF
  4.  *
  5.  * @package wp-graphql-acf
  6.  */
  7.  
  8. namespace WPGraphQL\ACF;
  9.  
  10. use WPGraphQL\Data\DataSource;
  11. use WPGraphQL\Model\Comment;
  12. use WPGraphQL\Model\Menu;
  13. use WPGraphQL\Model\MenuItem;
  14. use WPGraphQL\Model\Post;
  15. use WPGraphQL\Model\Term;
  16. use WPGraphQL\TypeRegistry;
  17. use WPGraphQL\Types;
  18.  
  19. /**
  20.  * Config class.
  21.  */
  22. class Config {
  23.  
  24.     /**
  25.      * Initialize WPGraphQL to ACF
  26.      */
  27.     public function init() {
  28.         /**
  29.          * Add ACF Fields to GraphQL Types
  30.          */
  31.         $this->add_acf_fields_to_post_object_types();
  32.         $this->add_acf_fields_to_term_objects();
  33.         $this->add_acf_fields_to_comments();
  34.         $this->add_acf_fields_to_menus();
  35.         $this->add_acf_fields_to_menu_items();
  36.         $this->add_acf_fields_to_media_items();
  37.         $this->add_acf_fields_to_individual_posts();
  38.     }
  39.  
  40.     /**
  41.      * Determines whether a field group should be exposed to the GraphQL Schema. By default, field
  42.      * groups will not be exposed to GraphQL.
  43.      *
  44.      * @param array $field_group Undocumented.
  45.      *
  46.      * @return bool
  47.      */
  48.     protected function should_field_group_show_in_graphql( $field_group ) {
  49.  
  50.         /**
  51.          * By default, field groups will not be exposed to GraphQL.
  52.          */
  53.         $show = false;
  54.  
  55.         /**
  56.          * If
  57.          */
  58.         if ( isset( $field_group['show_in_graphql'] ) && true === (bool) $field_group['show_in_graphql'] ) {
  59.             $show = true;
  60.         }
  61.  
  62.         /**
  63.          * Determine conditions where the GraphQL Schema should NOT be shown in GraphQL for
  64.          * root groups, not nested groups with parent.
  65.          */
  66.         if ( ! isset( $field_group['parent'] ) ) {
  67.             if (
  68.                 ( isset( $field_group['active'] ) && true != $field_group['active'] ) ||
  69.                 ( empty( $field_group['location'] ) || ! is_array( $field_group['location'] ) )
  70.             ) {
  71.                 $show = false;
  72.             }
  73.         }
  74.  
  75.         /**
  76.          * Whether a field group should show in GraphQL.
  77.          *
  78.          * @var boolean $show        Whether the field group should show in the GraphQL Schema
  79.          * @var array   $field_group The ACF Field Group
  80.          * @var Config  $this        The Config for the ACF Plugin
  81.          */
  82.         return apply_filters( 'wpgraphql_acf_should_field_group_show_in_graphql', $show, $field_group, $this );
  83.  
  84.     }
  85.  
  86.     /**
  87.      * Undocumented function
  88.      *
  89.      * @todo: This may be a good utility to add to WPGraphQL Core? May even have something already?
  90.      *
  91.      * @param string $str      Unknown.
  92.      * @param array  $no_strip Unknown.
  93.      *
  94.      * @return mixed|null|string|string[]
  95.      */
  96.     public static function camel_case( $str, array $no_strip = [] ) {
  97.         // non-alpha and non-numeric characters become spaces.
  98.         $str = preg_replace( '/[^a-z0-9' . implode( '', $no_strip ) . ']+/i', ' ', $str );
  99.         $str = trim( $str );
  100.         // Lowercase the string
  101.         $str = strtolower( $str );
  102.         // uppercase the first character of each word.
  103.         $str = ucwords( $str );
  104.         // Replace spaces
  105.         $str = str_replace( ' ', '', $str );
  106.         // Lowecase first letter
  107.         $str = lcfirst( $str );
  108.  
  109.         return $str;
  110.     }
  111.  
  112.     /**
  113.      * Add ACF Fields to Post Object Types.
  114.      *
  115.      * This gets the Post Types that are configured to show_in_graphql and iterates
  116.      * over them to expose ACF Fields to their Type in the GraphQL Schema.
  117.      */
  118.     protected function add_acf_fields_to_post_object_types() {
  119.  
  120.         /**
  121.          * Get a list of post types that have been registered to show in graphql
  122.          */
  123.         $graphql_post_types = get_post_types(['show_in_graphql' => true]);
  124.  
  125.         /**
  126.          * If there are no post types exposed to GraphQL, bail
  127.          */
  128.         if ( empty( $graphql_post_types ) || ! is_array( $graphql_post_types ) ) {
  129.             return;
  130.         }
  131.  
  132.         /**
  133.          * Loop over the post types exposed to GraphQL
  134.          */
  135.         foreach ( $graphql_post_types as $post_type ) {
  136.  
  137.             /**
  138.              * Get the field groups associated with the post type
  139.              */
  140.             $field_groups = acf_get_field_groups(
  141.                 [
  142.                     'post_type' => $post_type,
  143.                 ]
  144.             );
  145.  
  146.             /**
  147.              * If there are no field groups for this post type, move on to the next one.
  148.              */
  149.             if ( empty( $field_groups ) || ! is_array( $field_groups ) ) {
  150.                 continue;
  151.             }
  152.  
  153.             /**
  154.              * Get the post_type_object
  155.              */
  156.             $post_type_object = get_post_type_object( $post_type );
  157.  
  158.             /**
  159.              * Loop over the field groups for this post type
  160.              */
  161.             foreach ( $field_groups as $field_group ) {
  162.  
  163.                 $field_name = isset( $field_group['graphql_field_name'] ) ? $field_group['graphql_field_name'] : Config::camel_case( $field_group['title'] );
  164.  
  165.                 $field_group['type'] = 'group';
  166.                 $field_group['name'] = $field_name;
  167.                 $config              = [
  168.                     'name'            => $field_name,
  169.                     'description'     => $field_group['description'],
  170.                     'acf_field'       => $field_group,
  171.                     'acf_field_group' => null,
  172.                     'resolve'         => function( $root ) use ( $field_group ) {
  173.                         return isset( $root ) ? $root : null;
  174.                     }
  175.                 ];
  176.  
  177.                 $this->register_graphql_field( $post_type_object->graphql_single_name, $field_name, $config );
  178.             }
  179.         }
  180.  
  181.     }
  182.  
  183.     /**
  184.      * Undocumented function
  185.      *
  186.      * @param [type] $root Undocumented.
  187.      * @param [type] $acf_field Undocumented.
  188.      *
  189.      * @return mixed
  190.      */
  191.     protected function get_acf_field_value( $root, $acf_field ) {
  192.  
  193.         $value = null;
  194.         if ( is_array( $root ) ) {
  195.             if ( isset( $root[ $acf_field['key'] ] ) ) {
  196.                 $value = $root[ $acf_field['key'] ];
  197.  
  198.                 if ( 'wysiwyg' === $acf_field['type'] ) {
  199.                     $value = apply_filters( 'the_content', $value );
  200.                 }
  201.  
  202.             }
  203.         } else {
  204.  
  205.             switch (true) {
  206.                 case $root instanceof Term:
  207.                     $id = acf_get_term_post_id( $root->taxonomyName, $root->term_id );
  208.                     break;
  209.                 case $root instanceof Post:
  210.                     $id = absint( $root->ID );
  211.                     break;
  212.                 case $root instanceof MenuItem:
  213.                     $id = absint( $root->menuItemId );
  214.                     break;
  215.                 case $root instanceof Menu:
  216.                     $id = acf_get_term_post_id( 'nav_menu', $root->menuId  );
  217.                     break;
  218.                 case $root instanceof Comment:
  219.                     $id = 'comment_' . absint( $root->comment_ID );
  220.                     break;
  221.                 default:
  222.                     $id = null;
  223.                     break;
  224.             }
  225.  
  226.             if ( empty( $id ) ) {
  227.                 return null;
  228.             }
  229.  
  230.             $format = false;
  231.  
  232.             if ( 'wysiwyg' === $acf_field['type'] ) {
  233.                 $format = true;
  234.             }
  235.  
  236.             $field_value = get_field( $acf_field['key'], $id, $format );
  237.  
  238.             $value       = ! empty( $field_value ) ? $field_value : null;
  239.         }
  240.  
  241.         return $value;
  242.  
  243.     }
  244.  
  245.     /**
  246.      * Get a list of supported fields that WPGraphQL for ACF supports.
  247.      *
  248.      * This is helpful for determining whether UI should be output for the field, and whether
  249.      * the field should be added to the Schema.
  250.      *
  251.      * Some fields, such as "Accordion" are not supported currently.
  252.      *
  253.      * @return array
  254.      */
  255.     public static function get_supported_fields() {
  256.         $supported_fields = [
  257.             'text',
  258.             'textarea',
  259.             'number',
  260.             'range',
  261.             'email',
  262.             'url',
  263.             'password',
  264.             'image',
  265.             'file',
  266.             'wysiwyg',
  267.             'oembed',
  268.             'gallery',
  269.             'select',
  270.             'checkbox',
  271.             'radio',
  272.             'button_group',
  273.             'true_false',
  274.             'link',
  275.             'post_object',
  276.             'page_link',
  277.             'relationship',
  278.             'taxonomy',
  279.             'user',
  280.             'google_map',
  281.             'date_picker',
  282.             'date_time_picker',
  283.             'time_picker',
  284.             'color_picker',
  285.             'group',
  286.             'repeater',
  287.             'flexible_content'
  288.         ];
  289.  
  290.         /**
  291.          * filter the supported fields
  292.          *
  293.          * @param array $supported_fields
  294.          */
  295.         return apply_filters( 'wpgraphql_acf_supported_fields', $supported_fields );
  296.     }
  297.  
  298.     /**
  299.      * Undocumented function
  300.      *
  301.      * @param [type] $type_name Undocumented.
  302.      * @param [type] $field_name Undocumented.
  303.      * @param [type] $config Undocumented.
  304.      *
  305.      * @return mixed
  306.      */
  307.     protected function register_graphql_field( $type_name, $field_name, $config ) {
  308.  
  309.         $acf_field = isset( $config['acf_field'] ) ? $config['acf_field'] : null;
  310.         $acf_type  = isset( $acf_field['type'] ) ? $acf_field['type'] : null;
  311.  
  312.         if ( empty( $acf_type ) ) {
  313.             return false;
  314.         }
  315.  
  316.         $field_config = [
  317.             'type'    => null,
  318.             'resolve' => isset( $config['resolve'] ) && is_callable( $config['resolve'] ) ? $config['resolve'] : function( $root, $args, $context, $info ) use ( $acf_field ) {
  319.                 $value = $this->get_acf_field_value( $root, $acf_field );
  320.  
  321.                 return ! empty( $value ) ? $value : null;
  322.             },
  323.         ];
  324.  
  325.  
  326.         switch ( $acf_type ) {
  327.             case 'button_group':
  328.             case 'color_picker':
  329.             case 'email':
  330.             case 'textarea':
  331.             case 'text':
  332.             case 'message':
  333.             case 'oembed':
  334.             case 'password':
  335.             case 'wysiwyg':
  336.             case 'url':
  337.                 // Even though Selects and Radios in ACF can _technically_ be an integer
  338.                 // we're chosing to always cast as a string because with
  339.                 // GraphQL we can't return different types
  340.             case 'select':
  341.             case 'radio':
  342.                 $field_config['type'] = 'String';
  343.                 break;
  344.             case 'range':
  345.                 $field_config['type'] = 'Integer';
  346.                 break;
  347.             case 'number':
  348.                 $field_config['type'] = 'Float';
  349.                 break;
  350.             case 'true_false':
  351.                 $field_config['type'] = 'Boolean';
  352.                 break;
  353.             case 'date_picker':
  354.             case 'time_picker':
  355.             case 'date_time_picker':
  356.                 $field_config = [
  357.                     'type'    => 'String',
  358.                     'resolve' => function( $root, $args, $context, $info ) use ( $acf_field ) {
  359.                         return isset( $root->ID ) ? get_field( $acf_field['key'], $root->ID, true ) : null;
  360.                     },
  361.                 ];
  362.                 break;
  363.             case 'relationship':
  364.  
  365.                 if ( isset( $acf_field['post_type'] ) && is_array( $acf_field['post_type'] ) ) {
  366.                     $field_type_name = $type_name . '_' . ucfirst( self::camel_case( $acf_field['name'] ) );
  367.                     if ( TypeRegistry::get_type( $field_type_name ) == $field_type_name ) {
  368.                         $type = $field_type_name;
  369.                     } else {
  370.                         $type_names = [];
  371.                         foreach ( $acf_field['post_type'] as $post_type ) {
  372.                             if ( in_array( $post_type, \WPGraphQL::$allowed_post_types, true ) ) {
  373.                                 $type_names[ $post_type ] = get_post_type_object( $post_type )->graphql_single_name;
  374.                             }
  375.                         }
  376.  
  377.                         if ( empty( $type_names ) ) {
  378.                             $field_config['type'] = null;
  379.                             break;
  380.                         }
  381.  
  382.                         register_graphql_union_type( $field_type_name, [
  383.                             'typeNames'   => $type_names,
  384.                             'resolveType' => function( $value ) use ( $type_names ) {
  385.                                 return ! empty( $value->post_type ) ? Types::post_object( $value->post_type ) : null;
  386.                             }
  387.                         ] );
  388.  
  389.                         $type = $field_type_name;
  390.                     }
  391.                 } else {
  392.                     $type = 'PostObjectUnion';
  393.                 }
  394.  
  395.                 $field_config = [
  396.                     'type'    => [ 'list_of' => $type ],
  397.                     'resolve' => function( $root, $args, $context, $info ) use ( $acf_field ) {
  398.                         $relationship = [];
  399.                         $value        = $this->get_acf_field_value( $root, $acf_field );
  400.                         if ( ! empty( $value ) && is_array( $value ) ) {
  401.                             foreach ( $value as $post_id ) {
  402.                                 $post_object = get_post( $post_id );
  403.                                 if ( $post_object instanceof \WP_Post ) {
  404.                                     $post_model = new Post( $post_object );
  405.                                     $relationship[] = $post_model;
  406.                                 }
  407.                             }
  408.                         }
  409.                         return isset( $value ) ? $relationship : null;
  410.  
  411.                     },
  412.                 ];
  413.                 break;
  414.             case 'page_link':
  415.             case 'post_object':
  416.  
  417.                 if ( isset( $acf_field['post_type'] ) && is_array( $acf_field['post_type'] ) ) {
  418.                     $field_type_name = $type_name . '_' . ucfirst( self::camel_case( $acf_field['name'] ) );
  419.                     if ( TypeRegistry::get_type( $field_type_name ) == $field_type_name ) {
  420.                         $type = $field_type_name;
  421.                     } else {
  422.                         $type_names = [];
  423.                         foreach ( $acf_field['post_type'] as $post_type ) {
  424.                             if ( in_array( $post_type, \WPGraphQL::$allowed_post_types, true ) ) {
  425.                                 $type_names[ $post_type ] = get_post_type_object( $post_type )->graphql_single_name;
  426.                             }
  427.                         }
  428.  
  429.                         if ( empty( $type_names ) ) {
  430.                             $field_config['type'] = null;
  431.                             break;
  432.                         }
  433.  
  434.                         register_graphql_union_type( $field_type_name, [
  435.                             'typeNames'   => $type_names,
  436.                             'resolveType' => function( $value ) use ( $type_names ) {
  437.                                 return ! empty( $value->post_type ) ? Types::post_object( $value->post_type ) : null;
  438.                             }
  439.                         ] );
  440.  
  441.                         $type = $field_type_name;
  442.                     }
  443.                 } else {
  444.                     $type = 'PostObjectUnion';
  445.                 }
  446.  
  447.                 $field_config = [
  448.                     'type'    => $type,
  449.                     'resolve' => function( $root, $args, $context, $info ) use ( $acf_field ) {
  450.                         $value = $this->get_acf_field_value( $root, $acf_field );
  451.                         if ( $value instanceof \WP_Post ) {
  452.                             return new Post( $value );
  453.                         }
  454.  
  455.                         return absint( $value ) ? DataSource::resolve_post_object( (int) $value, $context ) : null;
  456.  
  457.                     },
  458.                 ];
  459.                 break;
  460.             case 'link':
  461.  
  462.                 $field_type_name = 'ACF_Link';
  463.                 if ( TypeRegistry::get_type( $field_type_name ) == $field_type_name ) {
  464.                     $field_config['type'] = $field_type_name;
  465.                     break;
  466.                 }
  467.  
  468.                 register_graphql_object_type(
  469.                     $field_type_name,
  470.                     [
  471.                         'description' => __( 'ACF Link field', 'wp-graphql-acf' ),
  472.                         'fields'      => [
  473.                             'url'    => [
  474.                                 'type'        => 'String',
  475.                                 'description' => __( 'The url of the link', 'wp-graphql-acf' ),
  476.                             ],
  477.                             'title'  => [
  478.                                 'type'        => 'String',
  479.                                 'description' => __( 'The title of the link', 'wp-graphql-acf' ),
  480.                             ],
  481.                             'target' => [
  482.                                 'type'        => 'String',
  483.                                 'description' => __( 'The target of the link (_blank, etc)', 'wp-graphql-acf' ),
  484.                             ],
  485.                         ],
  486.                     ]
  487.                 );
  488.                 $field_config['type'] = $field_type_name;
  489.                 break;
  490.             case 'image':
  491.             case 'file':
  492.                 $field_config = [
  493.                     'type'    => 'MediaItem',
  494.                     'resolve' => function( $root, $args, $context, $info ) use ( $acf_field ) {
  495.                         $value = $this->get_acf_field_value( $root, $acf_field );
  496.  
  497.                         return DataSource::resolve_post_object( (int) $value, $context );
  498.                     },
  499.                 ];
  500.                 break;
  501.             case 'checkbox':
  502.                 $field_config = [
  503.                     'type'    => [ 'list_of' => 'String' ],
  504.                     'resolve' => function( $root, $args, $context, $info ) use ( $acf_field ) {
  505.                         $value = $this->get_acf_field_value( $root, $acf_field );
  506.  
  507.                         return is_array( $value ) ? $value : null;
  508.                     },
  509.                 ];
  510.                 break;
  511.             case 'gallery':
  512.                 $field_config = [
  513.                     'type'    => [ 'list_of' => 'MediaItem' ],
  514.                     'resolve' => function( $root, $args, $context, $info ) use ( $acf_field ) {
  515.                         $value   = $this->get_acf_field_value( $root, $acf_field );
  516.                         $gallery = [];
  517.                         if ( ! empty( $value ) && is_array( $value ) ) {
  518.                             foreach ( $value as $image ) {
  519.                                 $post_object = get_post( (int) $image );
  520.                                 if ( $post_object instanceof \WP_Post ) {
  521.                                     $post_model = new Post( $post_object );
  522.                                     $gallery[] = $post_model;
  523.                                 }
  524.                             }
  525.                         }
  526.  
  527.                         return isset( $value ) ? $gallery : null;
  528.                     },
  529.                 ];
  530.                 break;
  531.             case 'user':
  532.                 $field_config = [
  533.                     'type'    => 'User',
  534.                     'resolve' => function( $root, $args, $context, $info ) use ( $acf_field ) {
  535.                         $value = $this->get_acf_field_value( $root, $acf_field );
  536.  
  537.                         return DataSource::resolve_user( (int) $value, $context );
  538.                     },
  539.                 ];
  540.                 break;
  541.             case 'taxonomy':
  542.                 $field_config = [
  543.                     'type'    => [ 'list_of' => 'TermObjectUnion' ],
  544.                     'resolve' => function( $root, $args, $context, $info ) use ( $acf_field ) {
  545.                         $value = $this->get_acf_field_value( $root, $acf_field );
  546.                         $terms = [];
  547.                         if ( ! empty( $value ) && is_array( $value ) ) {
  548.                             foreach ( $value as $term ) {
  549.                                 $terms[] = DataSource::resolve_term_object( (int) $term, $context );
  550.                             }
  551.                         }
  552.  
  553.                         return $terms;
  554.                     },
  555.                 ];
  556.                 break;
  557.  
  558.             // Accordions are not represented in the GraphQL Schema.
  559.             case 'accordion':
  560.                 $field_config = null;
  561.                 break;
  562.             case 'group':
  563.                 $field_type_name = $type_name . '_' . ucfirst( self::camel_case( $acf_field['name'] ) );
  564.                 if ( TypeRegistry::get_type( $field_type_name ) ) {
  565.                     $field_config['type'] = $field_type_name;
  566.                     break;
  567.                 }
  568.  
  569.                 register_graphql_object_type(
  570.                     $field_type_name,
  571.                     [
  572.                         'description' => __( 'Field Group', 'wp-graphql-acf' ),
  573.                         'fields'      => [
  574.                             'fieldGroupName' => [
  575.                                 'type'    => 'String',
  576.                                 'resolve' => function( $source ) use ( $acf_field ) {
  577.                                     return ! empty( $acf_field['name'] ) ? $acf_field['name'] : null;
  578.                                 },
  579.                             ],
  580.                         ],
  581.                     ]
  582.                 );
  583.  
  584.  
  585.                 $this->add_field_group_fields( $acf_field, $field_type_name );
  586.  
  587.                 $field_config['type'] = $field_type_name;
  588.                 break;
  589.  
  590.             case 'google_map':
  591.                 $field_type_name = 'ACF_GoogleMap';
  592.                 if ( TypeRegistry::get_type( $field_type_name ) == $field_type_name ) {
  593.                     $field_config['type'] = $field_type_name;
  594.                     break;
  595.                 }
  596.  
  597.                 register_graphql_object_type(
  598.                     $field_type_name,
  599.                     [
  600.                         'description' => __( 'Google Map field', 'wp-graphql-acf' ),
  601.                         'fields'      => [
  602.                             'streetAddress' => [
  603.                                 'type'        => 'String',
  604.                                 'description' => __( 'The street address associated with the map', 'wp-graphql-acf' ),
  605.                                 'resolve'     => function( $root ) {
  606.                                     return isset( $root['address'] ) ? $root['address'] : null;
  607.                                 },
  608.                             ],
  609.                             'latitude'      => [
  610.                                 'type'        => 'Float',
  611.                                 'description' => __( 'The latitude associated with the map', 'wp-graphql-acf' ),
  612.                                 'resolve'     => function( $root ) {
  613.                                     return isset( $root['lat'] ) ? $root['lat'] : null;
  614.                                 },
  615.                             ],
  616.                             'longitude'     => [
  617.                                 'type'        => 'Float',
  618.                                 'description' => __( 'The longitude associated with the map', 'wp-graphql-acf' ),
  619.                                 'resolve'     => function( $root ) {
  620.                                     return isset( $root['lng'] ) ? $root['lng'] : null;
  621.                                 },
  622.                             ],
  623.                         ],
  624.                     ]
  625.                 );
  626.                 $field_config['type'] = $field_type_name;
  627.                 break;
  628.             case 'repeater':
  629.                 $field_type_name = $type_name . '_' . self::camel_case( $acf_field['name'] );
  630.  
  631.                 if ( TypeRegistry::get_type( $field_type_name ) ) {
  632.                     $field_config['type'] = $field_type_name;
  633.                     break;
  634.                 }
  635.  
  636.                 register_graphql_object_type(
  637.                     $field_type_name,
  638.                     [
  639.                         'description' => __( 'Field Group', 'wp-graphql-acf' ),
  640.                         'fields'      => [
  641.                             'fieldGroupName' => [
  642.                                 'type'    => 'String',
  643.                                 'resolve' => function( $source ) use ( $acf_field ) {
  644.                                     return ! empty( $acf_field['name'] ) ? $acf_field['name'] : null;
  645.                                 },
  646.                             ],
  647.                         ],
  648.                         'resolve'     => function( $source ) use ( $acf_field ) {
  649.                             $repeater = $this->get_acf_field_value( $source, $acf_field );
  650.                             return ! empty( $repeater ) ? $repeater : [];
  651.                         },
  652.                     ]
  653.                 );
  654.  
  655.                 $this->add_field_group_fields( $acf_field, $field_type_name );
  656.  
  657.                 $field_config['type'] = [ 'list_of' => $field_type_name ];
  658.                 break;
  659.  
  660.             /**
  661.              * Flexible content fields should return a Union of the Layouts that can be configured.
  662.              *
  663.              *
  664.              * Example Query of a flex field with the name "flex_field" and 2 groups
  665.              *
  666.              * {
  667.              *   post {
  668.              *      flexField {
  669.              *         ...on GroupOne {
  670.              *           textField
  671.              *           textAreaField
  672.              *         }
  673.              *         ...on GroupTwo {
  674.              *           imageField {
  675.              *             id
  676.              *             title
  677.              *           }
  678.              *         }
  679.              *      }
  680.              *   }
  681.              * }
  682.              *
  683.              */
  684.             case 'flexible_content':
  685.  
  686.                 $field_config    = null;
  687.                 $field_type_name = $type_name . '_' . ucfirst( self::camel_case( $acf_field['name'] ) );
  688.                 if ( TypeRegistry::get_type( $field_type_name ) ) {
  689.                     $field_config['type'] = $field_type_name;
  690.                     break;
  691.                 }
  692.  
  693.                 if ( ! empty( $acf_field['layouts'] ) && is_array( $acf_field['layouts'] ) ) {
  694.  
  695.                     $union_types = [];
  696.                     foreach ( $acf_field['layouts'] as $layout ) {
  697.  
  698.                         $flex_field_layout_name = ! empty( $layout['name'] ) ? ucfirst( self::camel_case( $layout['name'] ) ) : null;
  699.                         $flex_field_layout_name = ! empty( $flex_field_layout_name ) ? $field_type_name . '_' . $flex_field_layout_name : null;
  700.                         $layout_type            = TypeRegistry::get_type( $flex_field_layout_name );
  701.  
  702.                         if ( $layout_type ) {
  703.                             $union_types[ $layout['name'] ] = $layout_type;
  704.                         } else {
  705.                             register_graphql_object_type( $flex_field_layout_name, [
  706.                                 'description' => __( 'Group within the flex field', 'wp-graphql-acf' ),
  707.                                 'fields'      => [
  708.                                     'fieldGroupName' => [
  709.                                         'type'    => 'String',
  710.                                         'resolve' => function( $source ) use ( $flex_field_layout_name ) {
  711.                                             return ! empty( $flex_field_layout_name ) ? $flex_field_layout_name : null;
  712.                                         },
  713.                                     ],
  714.                                 ],
  715.                             ] );
  716.                             $layout_type                    = TypeRegistry::get_type( $flex_field_layout_name );
  717.                             $union_types[ $layout['name'] ] = $layout_type;
  718.  
  719.                             $layout['parent']          = $acf_field;
  720.                             $layout['show_in_graphql'] = isset( $acf_field['show_in_graphql'] ) ? (bool) $acf_field['show_in_graphql'] : true;
  721.                             $this->add_field_group_fields( $layout, $flex_field_layout_name );
  722.                         }
  723.                     }
  724.  
  725.                     register_graphql_union_type( $field_type_name, [
  726.                         'types'       => $union_types,
  727.                         'resolveType' => function( $value ) use ( $union_types ) {
  728.                             return isset( $union_types[ $value['acf_fc_layout'] ] ) ? $union_types[ $value['acf_fc_layout'] ] : null;
  729.                         }
  730.                     ] );
  731.  
  732.                     $field_config['type']    = [ 'list_of' => $field_type_name ];
  733.                     $field_config['resolve'] = function( $root, $args, $context, $info ) use ( $acf_field ) {
  734.                         $value = $this->get_acf_field_value( $root, $acf_field );
  735.                         return ! empty( $value ) ? $value : [];
  736.                     };
  737.                 }
  738.                 break;
  739.             default:
  740.                 break;
  741.         }
  742.  
  743.         if ( empty( $field_config ) || empty( $field_config['type'] ) ) {
  744.             return null;
  745.         }
  746.  
  747.         $config = array_merge( $config, $field_config );
  748.  
  749.         return register_graphql_field( $type_name, $field_name, $config );
  750.     }
  751.  
  752.     /**
  753.      * Given a field group array, this adds the fields to the specified Type in the Schema
  754.      *
  755.      * @param array  $field_group The group to add to the Schema.
  756.      * @param string $type_name   The Type name in the GraphQL Schema to add fields to.
  757.      */
  758.     protected function add_field_group_fields( $field_group, $type_name ) {
  759.  
  760.         /**
  761.          * If the field group has the show_in_graphql setting configured, respect it's setting
  762.          * otherwise default to true (for nested fields)
  763.          */
  764.         $field_group['show_in_graphql'] = isset( $field_group['show_in_graphql'] ) ? (boolean) $field_group['show_in_graphql'] : true;
  765.  
  766.         /**
  767.          * Determine if the field group should be exposed
  768.          * to graphql
  769.          */
  770.         if ( ! $this->should_field_group_show_in_graphql( $field_group ) ) {
  771.             return;
  772.         }
  773.  
  774.         /**
  775.          * Get the fields in the group.
  776.          */
  777.         $acf_fields = ! empty( $field_group['sub_fields'] ) ? $field_group['sub_fields'] : acf_get_fields( $field_group );
  778.  
  779.         /**
  780.          * If there are no fields, bail
  781.          */
  782.         if ( empty( $acf_fields ) || ! is_array( $acf_fields ) ) {
  783.             return;
  784.         }
  785.  
  786.         /**
  787.          * Loop over the fields and register them to the Schema
  788.          */
  789.         foreach ( $acf_fields as $acf_field ) {
  790.  
  791.             /**
  792.              * Setup data for register_graphql_field
  793.              */
  794.             $name            = ! empty( $acf_field['name'] ) ? self::camel_case( $acf_field['name'] ) : null;
  795.             $show_in_graphql = isset( $acf_field['show_in_graphql'] ) ? (bool) $acf_field['show_in_graphql'] : true;
  796.             $description     = isset( $acf_field['instructions'] ) ? $acf_field['instructions'] : __( 'ACF Field added to the Schema by WPGraphQL ACF' );
  797.  
  798.             /**
  799.              * If the field is missing a name or a type,
  800.              * we can't add it to the Schema.
  801.              */
  802.             if (
  803.                 empty( $name ) ||
  804.                 true != $show_in_graphql
  805.             ) {
  806.  
  807.                 /**
  808.                  * Uncomment line below to determine what fields are not going to be output
  809.                  * in the Schema.
  810.                  */
  811.                 continue;
  812.             }
  813.  
  814.             $config = [
  815.                 'name'            => $name,
  816.                 'description'     => $description,
  817.                 'acf_field'       => $acf_field,
  818.                 'acf_field_group' => $field_group,
  819.             ];
  820.  
  821.             $this->register_graphql_field( $type_name, $name, $config );
  822.  
  823.         }
  824.  
  825.     }
  826.  
  827.     /**
  828.      * Add field groups to Taxonomies
  829.      *
  830.      * @return void
  831.      */
  832.     protected function add_acf_fields_to_term_objects() {
  833.  
  834.         /**
  835.          * Get a list of taxonomies that have been registered to show in graphql
  836.          */
  837.         $graphql_taxonomies = \WPGraphQL::get_allowed_taxonomies();
  838.  
  839.         /**
  840.          * If there are no taxonomies exposed to GraphQL, bail
  841.          */
  842.         if ( empty( $graphql_taxonomies ) || ! is_array( $graphql_taxonomies ) ) {
  843.             return;
  844.         }
  845.  
  846.         /**
  847.          * Loop over the taxonomies exposed to GraphQL
  848.          */
  849.         foreach ( $graphql_taxonomies as $taxonomy ) {
  850.  
  851.             /**
  852.              * Get the field groups associated with the taxonomy
  853.              */
  854.             $field_groups = acf_get_field_groups(
  855.                 [
  856.                     'taxonomy' => $taxonomy,
  857.                 ]
  858.             );
  859.  
  860.             /**
  861.              * If there are no field groups for this taxonomy, move on to the next one.
  862.              */
  863.             if ( empty( $field_groups ) || ! is_array( $field_groups ) ) {
  864.                 continue;
  865.             }
  866.  
  867.             /**
  868.              * Get the Taxonomy object
  869.              */
  870.             $tax_object = get_taxonomy( $taxonomy );
  871.  
  872.             /**
  873.              * Loop over the field groups for this post type
  874.              */
  875.             foreach ( $field_groups as $field_group ) {
  876.  
  877.                 $field_name = isset( $field_group['graphql_field_name'] ) ? $field_group['graphql_field_name'] : Config::camel_case( $field_group['title'] );
  878.  
  879.                 $field_group['type'] = 'group';
  880.                 $field_group['name'] = $field_name;
  881.                 $description = $field_group['description'] ? $field_group['description'] . ' | ' : '';
  882.                 $config              = [
  883.                     'name'            => $field_name,
  884.                     'description'     => $description . sprintf( __( 'Added to the GraphQL Schema because the ACF Field Group "%1$s" was assigned to the "%2$s" taxonomy', 'wp-graphql-acf' ), $field_group['title'], $tax_object->name ),
  885.                     'acf_field'       => $field_group,
  886.                     'acf_field_group' => null,
  887.                     'resolve'         => function( $root ) use ( $field_group ) {
  888.                         return isset( $root ) ? $root : null;
  889.                     }
  890.                 ];
  891.  
  892.                 $this->register_graphql_field( $tax_object->graphql_single_name, $field_name, $config );
  893.             }
  894.         }
  895.     }
  896.  
  897.     /**
  898.      * Add ACF Fields to comments
  899.      *
  900.      * @return void
  901.      */
  902.     protected function add_acf_fields_to_comments() {
  903.  
  904.         $comment_field_groups = [];
  905.  
  906.         /**
  907.          * Get the field groups associated with the taxonomy
  908.          */
  909.         $field_groups = acf_get_field_groups();
  910.  
  911.         foreach( $field_groups as $field_group ) {
  912.             if ( ! empty( $field_group['location'] ) && is_array( $field_group['location'] ) ) {
  913.                 foreach ( $field_group['location'] as $locations ) {
  914.                     if ( ! empty( $locations ) && is_array( $locations ) ) {
  915.                         foreach ( $locations as $location ) {
  916.                             if ( 'comment' === $location['param'] && '!=' === $location['operator'] ) {
  917.                                 continue;
  918.                             }
  919.                             if ( 'comment' === $location['param'] && '==' === $location['operator'] ) {
  920.                                 $comment_field_groups[] = $field_group;
  921.                             }
  922.                         }
  923.                     }
  924.                 }
  925.             }
  926.         }
  927.  
  928.         if ( empty( $comment_field_groups ) ) {
  929.             return;
  930.         }
  931.  
  932.         /**
  933.          * Loop over the field groups for this post type
  934.          */
  935.         foreach ( $comment_field_groups as $field_group ) {
  936.  
  937.             $field_name = isset( $field_group['graphql_field_name'] ) ? $field_group['graphql_field_name'] : Config::camel_case( $field_group['title'] );
  938.  
  939.             $field_group['type'] = 'group';
  940.             $field_group['name'] = $field_name;
  941.             $description = $field_group['description'] ? $field_group['description'] . ' | ' : '';
  942.             $config              = [
  943.                 'name'            => $field_name,
  944.                 'description'     => $description . sprintf( __( 'Added to the GraphQL Schema because the ACF Field Group "%s" was assigned to Comments', 'wp-graphql-acf' ), $field_group['title'] ),
  945.                 'acf_field'       => $field_group,
  946.                 'acf_field_group' => null,
  947.                 'resolve'         => function( $root ) use ( $field_group ) {
  948.                     return isset( $root ) ? $root : null;
  949.                 }
  950.             ];
  951.  
  952.             $this->register_graphql_field( 'Comment', $field_name, $config );
  953.  
  954.         }
  955.  
  956.     }
  957.  
  958.     /**
  959.      * Add Fields to Menus in the GraphQL Schema
  960.      *
  961.      * @return void
  962.      */
  963.     protected function add_acf_fields_to_menus() {
  964.  
  965.         $menu_field_groups = [];
  966.  
  967.         /**
  968.          * Get the field groups associated with the taxonomy
  969.          */
  970.         $field_groups = acf_get_field_groups();
  971.  
  972.         foreach( $field_groups as $field_group ) {
  973.             if ( ! empty( $field_group['location'] ) && is_array( $field_group['location'] ) ) {
  974.                 foreach ( $field_group['location'] as $locations ) {
  975.                     if ( ! empty( $locations ) && is_array( $locations ) ) {
  976.                         foreach ( $locations as $location ) {
  977.                             if ( 'nav_menu' === $location['param'] && '!=' === $location['operator'] ) {
  978.                                 continue;
  979.                             }
  980.                             if ( 'nav_menu' === $location['param'] && '==' === $location['operator'] ) {
  981.                                 $menu_field_groups[] = $field_group;
  982.                                 break;
  983.                             }
  984.                         }
  985.                     }
  986.                 }
  987.             }
  988.         }
  989.  
  990.         if ( empty( $menu_field_groups ) ) {
  991.             return;
  992.         }
  993.  
  994.         /**
  995.          * Loop over the field groups for this post type
  996.          */
  997.         foreach ( $menu_field_groups as $field_group ) {
  998.  
  999.             $field_name = isset( $field_group['graphql_field_name'] ) ? $field_group['graphql_field_name'] : Config::camel_case( $field_group['title'] );
  1000.  
  1001.             $field_group['type'] = 'group';
  1002.             $field_group['name'] = $field_name;
  1003.             $description = $field_group['description'] ? $field_group['description'] . ' | ' : '';
  1004.             $config              = [
  1005.                 'name'            => $field_name,
  1006.                 'description'     => $description . sprintf( __( 'Added to the GraphQL Schema because the ACF Field Group "%s" was assigned to Menus', 'wp-graphql-acf' ), $field_group['title'] ),
  1007.                 'acf_field'       => $field_group,
  1008.                 'acf_field_group' => null,
  1009.                 'resolve'         => function( $root ) use ( $field_group ) {
  1010.                     return isset( $root ) ? $root : null;
  1011.                 }
  1012.             ];
  1013.  
  1014.             $this->register_graphql_field( 'Menu', $field_name, $config );
  1015.  
  1016.         }
  1017.  
  1018.     }
  1019.  
  1020.     /**
  1021.      * Add ACF Field Groups to Menu Items
  1022.      *
  1023.      * @return void
  1024.      */
  1025.     protected function add_acf_fields_to_menu_items() {
  1026.  
  1027.         $menu_item_field_groups = [];
  1028.  
  1029.         /**
  1030.          * Get the field groups associated with the taxonomy
  1031.          */
  1032.         $field_groups = acf_get_field_groups();
  1033.         foreach( $field_groups as $field_group ) {
  1034.             if ( ! empty( $field_group['location'] ) && is_array( $field_group['location'] ) ) {
  1035.                 foreach ( $field_group['location'] as $locations ) {
  1036.                     if ( ! empty( $locations ) && is_array( $locations ) ) {
  1037.                         foreach ( $locations as $location ) {
  1038.                             if ( 'nav_menu_item' === $location['param'] && '!=' === $location['operator'] ) {
  1039.                                 continue;
  1040.                             }
  1041.                             if ( 'nav_menu_item' === $location['param'] && '==' === $location['operator'] ) {
  1042.                                 $menu_item_field_groups[] = $field_group;
  1043.                             }
  1044.                         }
  1045.                     }
  1046.                 }
  1047.             }
  1048.         }
  1049.  
  1050.         if ( empty( $menu_item_field_groups ) ) {
  1051.             return;
  1052.         }
  1053.  
  1054.         /**
  1055.          * Loop over the field groups for this post type
  1056.          */
  1057.         foreach ( $menu_item_field_groups as $field_group ) {
  1058.  
  1059.             $field_name = isset( $field_group['graphql_field_name'] ) ? $field_group['graphql_field_name'] : Config::camel_case( $field_group['title'] );
  1060.  
  1061.             $field_group['type'] = 'group';
  1062.             $field_group['name'] = $field_name;
  1063.             $description = $field_group['description'] ? $field_group['description'] . ' | ' : '';
  1064.             $config              = [
  1065.                 'name'            => $field_name,
  1066.                 'description'     => $description . sprintf( __( 'Added to the GraphQL Schema because the ACF Field Group "%s" was assigned to Menu Items', 'wp-graphql-acf' ), $field_group['title'] ),
  1067.                 'acf_field'       => $field_group,
  1068.                 'acf_field_group' => null,
  1069.                 'resolve'         => function( $root ) use ( $field_group ) {
  1070.                     return isset( $root ) ? $root : null;
  1071.                 }
  1072.             ];
  1073.  
  1074.             $this->register_graphql_field( 'MenuItem', $field_name, $config );
  1075.  
  1076.         }
  1077.     }
  1078.  
  1079.     /**
  1080.      * Add ACF Field Groups to Media Items (attachments)
  1081.      *
  1082.      * @return void
  1083.      */
  1084.     protected function add_acf_fields_to_media_items() {
  1085.  
  1086.         $media_item_field_groups = [];
  1087.  
  1088.         /**
  1089.          * Get the field groups associated with the taxonomy
  1090.          */
  1091.         $field_groups = acf_get_field_groups();
  1092.  
  1093.         foreach( $field_groups as $field_group ) {
  1094.             if ( ! empty( $field_group['location'] ) && is_array( $field_group['location'] ) ) {
  1095.                 foreach ( $field_group['location'] as $locations ) {
  1096.                     if ( ! empty( $locations ) && is_array( $locations ) ) {
  1097.                         foreach ( $locations as $location ) {
  1098.                             if ( 'attachment' === $location['param'] && '!=' === $location['operator'] ) {
  1099.                                 continue;
  1100.                             }
  1101.                             if ( 'attachment' === $location['param'] && '==' === $location['operator'] ) {
  1102.                                 $media_item_field_groups[] = $field_group;
  1103.                             }
  1104.                         }
  1105.                     }
  1106.                 }
  1107.             }
  1108.         }
  1109.  
  1110.         if ( empty( $media_item_field_groups ) ) {
  1111.             return;
  1112.         }
  1113.  
  1114.         /**
  1115.          * Loop over the field groups for this post type
  1116.          */
  1117.         foreach ( $media_item_field_groups as $field_group ) {
  1118.  
  1119.             $field_name = isset( $field_group['graphql_field_name'] ) ? $field_group['graphql_field_name'] : Config::camel_case( $field_group['title'] );
  1120.  
  1121.             $field_group['type'] = 'group';
  1122.             $field_group['name'] = $field_name;
  1123.             $description = $field_group['description'] ? $field_group['description'] . ' | ' : '';
  1124.             $config              = [
  1125.                 'name'            => $field_name,
  1126.                 'description'     => $description . sprintf( __( 'Added to the GraphQL Schema because the ACF Field Group "%s" was assigned to attachments', 'wp-graphql-acf' ), $field_group['title'] ),
  1127.                 'acf_field'       => $field_group,
  1128.                 'acf_field_group' => null,
  1129.                 'resolve'         => function( $root ) use ( $field_group ) {
  1130.                     return isset( $root ) ? $root : null;
  1131.                 }
  1132.             ];
  1133.  
  1134.             $this->register_graphql_field( 'MediaItem', $field_name, $config );
  1135.  
  1136.         }
  1137.     }
  1138.  
  1139.     protected function add_acf_fields_to_individual_posts() {
  1140.  
  1141.         $post_field_groups = [];
  1142.  
  1143.         /**
  1144.          * Get the field groups associated with the taxonomy
  1145.          */
  1146.         $field_groups = acf_get_field_groups();
  1147.  
  1148.         foreach( $field_groups as $field_group ) {
  1149.             if ( ! empty( $field_group['location'] ) && is_array( $field_group['location'] ) ) {
  1150.                 foreach ( $field_group['location'] as $locations ) {
  1151.                     if ( ! empty( $locations ) && is_array( $locations ) ) {
  1152.                         foreach ( $locations as $location ) {
  1153.  
  1154.                             /**
  1155.                              * If the operator is not equal to, we don't need to do anything,
  1156.                              * so we can just continue
  1157.                              */
  1158.                             if ( '!=' === $location['operator'] ) {
  1159.                                 continue;
  1160.                             }
  1161.  
  1162.                             /**
  1163.                              * If the param (the post_type) is in the array of allowed_post_types
  1164.                              */
  1165.                             if ( 'post' === $location['param'] && '==' === $location['operator'] ) {
  1166.                                 $post_field_groups[] = [
  1167.                                     'field_group' => $field_group,
  1168.                                     'post_id' => $location['value']
  1169.                                 ];
  1170.                             }
  1171.                         }
  1172.                     }
  1173.                 }
  1174.             }
  1175.         }
  1176.  
  1177.         /**
  1178.          * If no field groups are assigned to a specific post, we don't need to modify the Schema
  1179.          */
  1180.         if ( empty( $post_field_groups ) ) {
  1181.             return;
  1182.         }
  1183.  
  1184.         $allowed_post_types = get_post_types([
  1185.             'show_ui' => true,
  1186.             'show_in_graphql' => true
  1187.         ]);
  1188.  
  1189.         /**
  1190.          * Remove the `attachment` post_type, as it's treated special and we don't
  1191.          * want to add field groups in the same way we do for other post types
  1192.          */
  1193.         unset( $allowed_post_types['attachment'] );
  1194.  
  1195.         /**
  1196.          * Loop over the field groups assigned to a specific post
  1197.          * and register them to the Schema
  1198.          */
  1199.         foreach ( $post_field_groups as $key => $group ) {
  1200.  
  1201.             if ( empty( $group['field_group'] ) || ! is_array( $group['field_group'] ) ) {
  1202.                 continue;
  1203.             }
  1204.  
  1205.             $post_object = get_post( (int) $group['post_id'] );
  1206.  
  1207.             if ( ! $post_object instanceof \WP_Post ) {
  1208.                 continue;
  1209.             }
  1210.  
  1211.             $field_group = $group['field_group'];
  1212.             $post_type = get_post_type_object( $post_object->post_type );
  1213.             $field_name = isset( $field_group['graphql_field_name'] ) ? $field_group['graphql_field_name'] : Config::camel_case( $field_group['title'] );
  1214.  
  1215.             $field_group['type'] = 'group';
  1216.             $field_group['name'] = $field_name;
  1217.             $description         = $field_group['description'] ? $field_group['description'] . ' | ' : '';
  1218.             $config              = [
  1219.                 'name'            => $field_name,
  1220.                 'description'     => $description . sprintf( __( 'Added to the GraphQL Schema because the ACF Field Group "%1$s" was assigned to an individual post of the post_type: "%2$s". The group will be present in the Schema for the "%3$s" Type, but will only resolve if the entity has content saved.', 'wp-graphql-acf' ), $field_group['title'], $post_type->name, $post_type->graphql_plural_name ),
  1221.                 'acf_field'       => $field_group,
  1222.                 'acf_field_group' => null,
  1223.                 'resolve'         => function( $root ) use ( $field_group ) {
  1224.                     return isset( $root ) ? $root : null;
  1225.                 }
  1226.             ];
  1227.  
  1228.             $this->register_graphql_field( $post_type->graphql_single_name, $field_name, $config );
  1229.  
  1230.         }
  1231.  
  1232.     }
  1233.  
  1234.     protected function add_acf_fields_to_options_pages() {
  1235.         // @todo: Coming soon
  1236.     }
  1237.  
  1238. }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top