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

Refactored feature theme mods #571

Closed
Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 3 additions & 1 deletion docker-tasks/run-local-app/docker-compose.yml
Expand Up @@ -4,12 +4,14 @@ services:
wpgraphql.test:
image: "wordpress:${WP_VERSION}-php${PHP_VERSION}-apache"
ports:
- '80:80'
- '8000:80'
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we get this as a separate PR?

environment:
WORDPRESS_DB_HOST: 'mysql_test'
WORDPRESS_DB_NAME: 'wpgraphql_test'
WORDPRESS_DB_USER: 'root'
WORDPRESS_DB_PASSWORD: 'testing'
WORDPRESS_CONFIG_EXTRA: |
Copy link
Collaborator

@jasonbahl jasonbahl Nov 5, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

^ see prev comment about separate PR

define( 'WP_DEBUG', true );
volumes:
- "${PWD}:/var/www/html/wp-content/plugins/wp-graphql:ro"

Expand Down
91 changes: 91 additions & 0 deletions src/Data/DataSource.php
Expand Up @@ -328,6 +328,89 @@ public static function resolve_theme( $stylesheet ) {
}
}

/**
* Retrieves and formats theme modification data
*
* @param array|null $theme_mods - array of raw theme modification data
* @return array|null
*/
public static function resolve_theme_mods_data() {
/**
* Output array
*/
$theme_mod_data = [];

/**
* Loop through raw active theme mods array and format theme mod data
*/

$theme_mods = array_merge(
get_theme_mods(),
[
'background_image' => get_theme_mod( 'background_image', get_theme_support( 'custom-background', 'default-image' ) ),
'background_color' => get_theme_mod( 'background_color', get_theme_support( 'custom-background', 'default-color' ) ),
]
);

foreach( $theme_mods as $mod_name => $mod_data ){
if( gettype($mod_name) === 'integer' ) continue; // Skip mods without keys
if( $mod_name === 'sidebars_widgets' ) continue; // Skip sidebars

switch( $mod_name ) {
/**
* Custom CSS Post Id
*/
case 'custom_css_post_id':
$theme_mod_data[ $mod_name ] = absint($mod_data);
break;

/**
* Background
*/
case 'background_preset':
case 'background_size':
case 'background_repeat':
case 'background_attachment':
$key = str_replace('background_', '', $mod_name );
$theme_mod_data[ 'background' ][ $key ] = $mod_data;
break;
case 'background_image':
$theme_mod_data[ 'background' ]['id'] = attachment_url_to_postid( (string) $mod_data );
break;
case 'background_color':
$theme_mod_data[ $mod_name ] = (string) $mod_data;
break;

/**
* Custom Logo
*/
case 'custom_logo':
$theme_mod_data[ $mod_name ] = absint( $mod_data );
break;

/**
* Header Image
*/
case 'header_image_data':
if ( ! isset( $theme_mod_data[ 'header_image' ] ) ) $theme_mod_data[ 'header_image' ] = [];
$theme_mod_data[ 'header_image' ] += get_object_vars( $mod_data );
break;
case 'header_image':
\Codeception\Util\Debug::debug( attachment_url_to_postid( $mod_data ) );
$theme_mod_data[ 'header_image' ]['id'] = attachment_url_to_postid( (string) $mod_data );
break;

Copy link
Member Author

@kidunot89 kidunot89 Nov 5, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Edge data in header_image and background_image mods stored and can be updated in mutations but can not be queried at the moment.

/**
* Nav Menu Locations and Custom Mods
*/
default:
$theme_mod_data[ $mod_name ] = $mod_data;
}

}
return $theme_mod_data;
}

/**
* Wrapper for the ThemesConnectionResolver::resolve method
*
Expand Down Expand Up @@ -766,4 +849,12 @@ public static function get_post_object_by_uri( $uri, $output = OBJECT, $post_typ
return null;

}

/**
* Returns an array of nav menu location names
*/
public static function get_registered_nav_menu_locations() {
global $_wp_registered_nav_menus;
return array_keys( $_wp_registered_nav_menus );
}
}
119 changes: 119 additions & 0 deletions src/Data/ThemeModsMutation.php
@@ -0,0 +1,119 @@
<?php

namespace WPGraphQL\Data;

/**
* Class ThemeModsMutation
*
* @package WPGraphQL\Data\ThemeModsMutation
*/
class ThemeModsMutation {
/**
* This handles updating theme modifications
*
* @param array $input The input for the mutation
* @param string $mutation_name The name of the mutation being performed
*
* @return array $output_args
* @throws \Exception
*/
public static function prepare_theme_mods_values( $input, $mutation_name ) {

$prepared_values = [];

/**
* Scalar Inputs
*/
if ( ! empty( $input['backgroundColor'] ) ) {
$prepared_values['background_color'] = $input['backgroundColor'];
}
if ( ! empty( $input['customCssPostId'] ) ) {
$prepared_values['custom_css_post_id'] = $input['customCssPostId'];
}
if ( ! empty( $input['customLogo'] ) ) {
$prepared_values['custom_logo'] = $input['customLogo'];
}

/**
* Complex Inputs
*/
if ( ! empty( $input['background'] ) && is_array( $input['background'] ) ) {
foreach( $input['background'] as $key => $value ) {
switch( $key ) {
case 'imageId':
$value_key = 'background_image';
$prepared_values[ $value_key ] = wp_get_attachment_url( $value );
break;
default:
$value_key = 'background_'. preg_replace( '/([A-Z])/', '_\\L$1', $key );
$prepared_values[ $value_key ] = $value;
}
}
}

if ( ! empty( $input['headerImage'] ) && is_array( $input['headerImage'] ) ) {

$data_key = 'header_image_data';
foreach( $input['headerImage'] as $key => $value ) {
switch( $key ) {
case 'imageId':
$url = wp_get_attachment_url( $value );
$value_key = 'header_image';
$prepared_values[ $value_key ] = $url;

if( empty( $prepared_values[ $data_key ] ) ) {
$prepared_values[ $data_key ] = get_theme_mod( $data_key, new \stdClass );
}
$prepared_values[ $data_key ]->url = $url;
break;

default:
if( empty( $prepared_values[ $data_key ] ) ) {
$prepared_values[ $data_key ] = get_theme_mod( $data_key, new \stdClass );
}
$value_name = 'background_'. preg_replace( '/([A-Z])/', '_\\L$1', $key );
$prepared_values[ $data_key ]->$value_name = $value;

}
}
}

if ( ! empty( $input['navMenuLocations'] ) && is_array( $input['navMenuLocations'] ) ) {
$prepared_values[ 'nav_menu_locations' ] = array_merge(
get_nav_menu_locations(),
$input['navMenuLocations']
);
}

/**
* Filter the $theme_mods_update_values
*
* @param array $prepared_values The array of theme mods values that will be passed to set_theme_mod
* @param array $input The data that was entered as input for the mutation
* @param string $mutation_type The type of mutation being performed ( create, edit, etc )
*/
$prepared_values = apply_filters( 'graphql_theme_mods_update_values', $prepared_values, $input, $mutation_name );

return $prepared_values;
}

/**
* Updates theme modifications with $theme_mods_args array
*
* @param array $theme_mods_args - new values for theme mods
* @return boolean - true on success and false on fail
*/
public static function update_theme_mods( $theme_mods_args ) {

if( is_array( $theme_mods_args ) && ! empty( $theme_mods_args ) ) {
foreach( $theme_mods_args as $name => $value ) {
set_theme_mod( $name, $value );
}
return true;
}

return false;

}

}
91 changes: 91 additions & 0 deletions src/Mutation/UpdateThemeMods.php
@@ -0,0 +1,91 @@
<?php

namespace WPGraphQL\Mutation;

use GraphQL\Error\UserError;
use WPGraphQL\Data\DataSource;
use WPGraphQL\Data\ThemeModsMutation;

/**
* Class UpdateThemeMods
*
* @package WPGraphQL\Mutation\UpdateThemeMods
*/
class UpdateThemeMods {
public static function register_mutation() {
register_graphql_mutation( 'updateThemeMods', [
'inputFields' => self::get_input_fields(),
'outputFields' => [
'themeMods' => [
'type' => 'ThemeMods',
'resolve' => function ( $payload ) {
return $payload;
},
],
],
'mutateAndGetPayload' => function ( $input ) {
/**
* Check that the user can manage setting options
*/
if ( ! current_user_can( 'edit_theme_options' ) ) {
throw new UserError(
__( 'Sorry, you are not allowed to edit theme settings as this user.', 'wp-graphql' )
);
}

$prepared_values = ThemeModsMutation::prepare_theme_mods_values( $input, 'update' );

/**
* Update theme mods
*/
$success = ThemeModsMutation::update_theme_mods( $prepared_values );

/**
* Throw an exception if update
*/
if ( ! $success ) {
throw new UserError( __( 'The updates to theme settings failed to save', 'wp-graphql' ) );
}

/**
* Return the payload
*/
return DataSource::resolve_theme_mods_data();
}
] );
}

/**
* Returns the input_fields definition
*
* @return mixed|array|null $input_fields
*/
private static function get_input_fields() {
return [
'background' => [
'type' => 'CustomBackgroundInput',
'description' => __( 'The theme mod "background" object', 'wp-graphql' ),
],
'backgroundColor' => [
'type' => 'String',
'description' => __( 'The theme mod "background-color" hex color code', 'wp-graphql' ),
],
'customCssPostId' => [
'type' => 'Int',
'description' => __( 'The theme mod "custom-css-post-id" post id', 'wp-graphql' ),
],
'customLogo' => [
'type' => 'Int',
'description' => __( 'The theme mod "custom-logo" attachment id', 'wp-graphql' ),
],
'headerImage' => [
'type' => 'CustomHeaderInput',
'description' => __( 'The theme mod "header-image" object', 'wp-graphql' ),
],
'navMenuLocations' => [
'type' => 'NavMenuLocationsInput',
'description' => __( 'The theme mod "nav-menu-locations" object', 'wp-graphql' ),
],
];
}
}
6 changes: 4 additions & 2 deletions src/Type/Enum/MenuLocationEnum.php
@@ -1,12 +1,14 @@
<?php
namespace WPGraphQL\Type;

use WPGraphQL\Data\DataSource;

$values = [];

$locations = array_keys( get_nav_menu_locations() );
$locations = DataSource::get_registered_nav_menu_locations();
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gets all nav menu locations even ones that don't have menus assigned.


if ( ! empty( $locations ) && is_array( $locations ) ) {
foreach ( array_keys( get_nav_menu_locations() ) as $location ) {
foreach ( $locations as $location ) {
$values[ WPEnumType::get_safe_name( $location ) ] = [
'value' => $location,
];
Expand Down
28 changes: 28 additions & 0 deletions src/Type/Input/CustomBackgroundInput.php
@@ -0,0 +1,28 @@
<?php
namespace WPGraphQL\Type;

register_graphql_input_type( 'CustomBackgroundInput', [
'description' => __( 'Custom background values' ),
'fields' => [
'imageId' => [
'type' => 'ID',
'description' => __( 'The theme mod "background"\'s image attachment id', 'wp-graphql' ),
],
'preset' => [
'type' => 'String',
'description' => __( 'The theme mod "background"\'s preset property', 'wp-graphql' ),
],
'size' => [
'type' => 'String',
'description' => __( 'The theme mod "background"\'s css background-size property', 'wp-graphql' ),
],
'repeat' => [
'type' => 'String',
'description' => __( 'The theme mod "background"\'s css background-repeat property', 'wp-graphql' ),
],
'attachment' => [
'type' => 'String',
'description' => __( 'The theme mod "background"\'s css background-attachement property', 'wp-graphql' ),
],
],
] );