Custom field not saved - wordpress

I try to add a custom user field to the user by using WPGraphQL. Therefore I tried to recreate the example in the official WPGraphQL documentation https://docs.wpgraphql.com/extending/fields/#register-fields-to-the-schema :
add_action('graphql_init', function () {
$hobbies = [
'type' => ['list_of' => 'String'],
'description' => __('Custom field for user mutations', 'your-textdomain'),
'resolve' => function ($user) {
$hobbies = get_user_meta($user->userId, 'hobbies', true);
return !empty($hobbies) ? $hobbies : [];
},
];
register_graphql_field('User', 'hobbies', $hobbies);
register_graphql_field('CreateUserInput', 'hobbies', $hobbies);
register_graphql_field('UpdateUserInput', 'hobbies', $hobbies);
});
I already changed the type from \WPGraphQL\Types::list_of( \WPGraphQL\Types::string() ) to ['list_of' => 'String'].
If I now execute the updateUser mutation my hobbies don't get updated. What am I dowing wrong?
Mutation:
mutation MyMutation {
__typename
updateUser(input: {clientMutationId: "tempId", id: "dXNlcjox", hobbies: ["football", "gaming"]}) {
clientMutationId
user {
hobbies
}
}
}
Output:
{
"data": {
"__typename": "RootMutation",
"updateUser": {
"clientMutationId": "tempId",
"user": {
"hobbies": []
}
}
}
}

Thanks to xadm, the only thing I forgot was to really mutate the field. I was a bit confused by the documentation, my fault. (I really am new to WPGraphQL btw)
Here's what has to be added:
add_action('graphql_user_object_mutation_update_additional_data', 'graphql_register_user_mutation', 10, 5);
function graphql_register_user_mutation($user_id, $input, $mutation_name, $context, $info)
{
if (isset($input['hobbies'])) {
// Consider other sanitization if necessary and validation such as which
// user role/capability should be able to insert this value, etc.
update_user_meta($user_id, 'hobbies', $input['hobbies']);
}
}

Related

Gutenberg Infinite Loop

I'm working on building a Gutenberg block but it seems I keep getting an infinite loop. How can I invoke the rest API only once?
I am trying to get a list of officers - custom post type - but as the initial call doesn't provide the featured image I thought I should loop through and add the images "manually". If there is a better approach please do let me know.
registerBlockType('test/officers-block', {
title: __('Officers Block', 'test'),
description: __('Block to generate the officers block', 'test'),
icon: '',
category: 'test',
attributes: {
title: {
type: 'string',
},
posts: {
type: 'array',
}
},
edit: ({ attributes, setAttributes }) => {
const {
title,
posts,
} = attributes
// Request data
const data = useSelect((select) => {
return select('core').getEntityRecords('postType', 'officers', { per_page: -1 });
});
const isLoading = useSelect((select) => {
return select('core/data').isResolving('core', 'getEntityRecords', [
'postType', 'officers',
]);
});
const setOfficers = ( data ) => {
let officerData = [];
data.map(( officer ) => {
wp.apiFetch( { path: '/wp/v2/media/' + officer?.featured_media } ).then( function( image ){
officerDataEach.title = officer?.title?.rendered
officerDataEach.content = officer?.content?.rendered
officerDataEach.job = officer?.meta?._job_title
officerDataEach.phone = officer?.meta?._phone
officerDataEach.email = officer?.meta?._email
officerDataEach.image = image?.media_details?.sizes?.full?.source_url
officerData.push( officerDataEach )
})
})
console.log(officerData);
setAttributes( { posts: officerData } )
}
if( !isLoading && data ){
setOfficers( data );
}
if ( isLoading && !data ) {
return <h3>Loading...</h3>;
}
...
Thanks in advance

Symfony ignore 404 status code for get request

I have an application which allows users to create wishes. I use the title of each wish to make an api request to unsplash to download a picture. I now have the problem, that a user can enter a title which doesnt return any images from unsplash. In this case I'd like to use a placeholder image but my code stops after getting an 404 error. Is there a way to ignore this error and just continue my loop?
public function fetchImagesFromUnsplash() {
$wishes = $this->repository->findAll();
foreach ($wishes as $wish) {
try {
$response = $this->httpClient->request('GET', 'https://api.unsplash.com/photos/random', [
'query' => [
'query' => $wish->getDescription(),
'client_id' => 'oa1DsGebE8ehCV9SrvcA1mCx-2QfvnufUKgsIY5N0Mk'
]
]);
} catch (TransportExceptionInterface $e) {
}
if ($response) {
$data = $response->getContent();
$data = json_decode($data, true);
$imageLink = $data['urls']['raw'];
$rawImage = file_get_contents($imageLink);
if ($rawImage) {
file_put_contents("public/images/" . sprintf('imageWish%d.jpg', $wish->getId()), $rawImage);
$wish->setImagePath(sprintf('public/images/imageWish%d.jpg', $wish->getId()));
} else {
$wish->setImagePath('placeholder.png');
}
$this->em->flush();
}
}
}
EDIT:
I tried this:
public function fetchImagesFromUnsplash() {
$wishes = $this->repository->findAll();
foreach ($wishes as $wish) {
try {
$response = $this->httpClient->request('GET', 'https://api.unsplash.com/photos/random', [
'query' => [
'query' => $wish->getDescription(),
'client_id' => 'oa1DsGebE8ehCV9SrvcA1mCx-2QfvnufUKgsIY5N0Mk'
]
]);
} catch (NotFoundHttpException $e) {
}
if ($response) {
$data = $response->getContent();
$data = json_decode($data, true);
$imageLink = $data['urls']['raw'];
$rawImage = file_get_contents($imageLink);
if ($rawImage) {
file_put_contents("public/images/" . sprintf('imageWish%d.jpg', $wish->getId()), $rawImage);
$wish->setImagePath(sprintf('public/images/imageWish%d.jpg', $wish->getId()));
} else {
$wish->setImagePath('placeholder.png');
}
}
}
$this->em->flush();
}
but it still stops after the first 404
As per the documentation:
When the HTTP status code of the response is in the 300-599 range
(i.e. 3xx, 4xx or 5xx) your code is expected to handle it. If you
don't do that, the getHeaders() and getContent() methods throw an
appropriate exception
You have to check the $response->getStatusCode(), or prepare to handle a ClientException (representing 4xx status codes).

Disable Algolia for WP SearchAsYouType

I have implemented Algolia for Wordpress and am customizing the search template in the "instantsearch.php" file.
Looking at the documentation here https://www.algolia.com/doc/api-reference/widgets/search-box/js/#widget-param-searchasyoutype setting the searchAsYouType parameter to false should prevent Algolia from detecting user input and searching while a user types. However, this parameter is not disabling the search as you type for my site.
Below is the code for my input field widget and other custom components:
/* Instantiate instantsearch.js */
var search = instantsearch({
appId: algolia.application_id,
apiKey: algolia.search_api_key,
indexName: algolia.indices.searchable_posts.name,
urlSync: {
mapping: {'q': 's'},
trackedParameters: ['query']
},
searchParameters: {
facetingAfterDistinct: true,
highlightPreTag: '__ais-highlight__',
highlightPostTag: '__/ais-highlight__'
}
});
/* Search box widget */
search.addWidget(
instantsearch.widgets.searchBox({
container: '#algolia-search-box',
placeholder: 'Search ...',
searchAsYouType: false,
wrapInput: false,
poweredBy: algolia.powered_by_enabled
})
);
/* Hits widget */
search.addWidget(
instantsearch.widgets.hits({
container: '#algolia-hits',
hitsPerPage: 10,
templates: {
empty: 'No results were found for "<strong>{{query}}</strong>".',
item: wp.template('instantsearch-hit')
},
transformData: {
item: function (hit) {
function replace_highlights_recursive (item) {
if( item instanceof Object && item.hasOwnProperty('value')) {
item.value = _.escape(item.value);
item.value = item.value.replace(/__ais-highlight__/g, '<em>').replace(/__\/ais-highlight__/g, '</em>');
} else {
for (var key in item) {
item[key] = replace_highlights_recursive(item[key]);
}
}
return item;
}
hit._highlightResult = replace_highlights_recursive(hit._highlightResult);
hit._snippetResult = replace_highlights_recursive(hit._snippetResult);
console.log(hit);
if ( hit.post_excerpt != '' ){
hit._snippetResult['content']['value'] = hit.post_excerpt;
}
if ( hit.short_title.length > 0 && hit.short_title[0] != '' ){
hit._highlightResult['post_title']['value'] = hit.short_title[0];
}
return hit;
}
}
})
);
/* Pagination widget */
search.addWidget(
instantsearch.widgets.pagination({
container: '#algolia-pagination'
})
);
/* Tags refinement widget */
search.addWidget(
instantsearch.widgets.refinementList({
container: '#facet-tags',
attributeName: 'taxonomies.aar_article_type',
operator: 'and',
limit: 15,
sortBy: ['isRefined:desc', 'count:desc', 'name:asc'],
templates: {
header: '<h2 class="widgettitle">Filter Results</h2>'
}
})
);
/* Start */
search.start();
I have added the parameter to the search box widget, but when i type, the page still auto updates without me having to hit submit. Am I missing a configuration or something?
The correct property for accomplishing this is searchOnEnterKeyPressOnly , not searchAsYouType
The proper documentation for the widget I am using can be found here https://community.algolia.com/instantsearch.js/v2/widgets/searchBox.html#struct-SearchBoxWidgetOptions-searchOnEnterKeyPressOnly

AngularFire2 query, join or filter with foreign keys from another firebase table

I have this firebase data structure
{
members: {
m1: {
lastName: "smith",
firstName: "john"
},
m2: {
lastName: "abc",
firstName: "mike"
}
},
userFavs: {
u1: {
m1:true
},
u2: {
m2:true
}
}
}
In my service, I have this method:
getMembers(): FirebaseListObservable<any[]> {
return this.af.database.list('/members',{
query: {
orderByChild: 'firstName'
}
});
}
In members page TS file, I have method to do search:
setFilteredItems(){
if (this.searchTerm == null || this.searchTerm == ''){
this.members = this.membersSvc.getMembers()
.map((members) => {return members});
}else{
//return items.filter(item => item.name.toLowerCase().indexOf(args[0].toLowerCase()) !== -1);
this.members = this.membersSvc.getMembers()
.map((members) =>
members.filter(member => member.lastName.toLowerCase().indexOf(this.searchTerm.toLowerCase()) !== -1 || member.firstName.toLowerCase().indexOf(this.searchTerm.toLowerCase()) !== -1));
}
}
The search for members is working fine. Now I am adding 2 buttons below the search bar, All and Favorites. A user can add a member in his/her favorites. In search, the app needs to be able to filter the results with member keys that exists in the user favorites.
How can I add the additional filter of member keys that exists in the userFavs node?
I added the additional filter by getting the array of userFavs keys. So in my user service I have a method:
getUserFavKeys(){
let favKeys = [];
const userKey = this.authService.getActiveUser().uid;
let url = `/userCircles/${userKey}`;
this.af.database.list(url, { preserveSnapshot: true})
.subscribe(itemKeys=>{
itemKeys.forEach(itemKey => {
//console.log(itemKey.key);
favKeys.push(itemKey.key);
});
})
return favKeys;
}
Then in the component ngOnInit method, I initialized the array of keys:
this.favKeys = this.userSvc.getUserFavKeys();
And when the circles is selected:
onCirclesSelected(){
this.searching = false;
this.members = this.membersSvc.getMembers()
.map((members) =>
members.filter(member => this.userCircles.indexOf(member.$key) !== -1)
);
if (this.searchTerm == null || this.searchTerm == ''){
//do nothing
}else{
//filter w the search text
this.members = this.members
.map((members) =>
members.filter(member => member.lastName.toLowerCase().indexOf(this.searchTerm.toLowerCase()) !== -1 || member.firstName.toLowerCase().indexOf(this.searchTerm.toLowerCase()) !== -1));
}
}
Hope that helps to anyone that needs the same search feature.

Symfony add Avatar field to sfGuardUser model

I have a project in symfony that I would like to let my users upload an image for their "avatar" field. I have found many posts about how to "extend" the table which I have with the schema below:
Member:
inheritance:
type: column_aggregation
extends: sfGuardUser
columns:
idmember: { type: integer }
birthday: { type: date }
avatar: { type: string(255) }
bio: { type: string(255) }
The columns get added to the table just fine, but when I go to change the widget to a sfWidgetFormInputFileEditable it breaks. Here is the Form.class file:
$file_src = $this->getObject()->getAvatar();
if ($file_src == '')
{
$file_src = 'default_image.png';
}
$this->widgetSchema['avatar'] = new sfWidgetFormInputFileEditable(array(
'label' => ' ',
'file_src' => '/uploads/avatar/'.$file_src,
'is_image' => true,
'edit_mode' => true,
'template' => '<div>%file%<br />%input%</div>',
));
and "save" function of the form:
if($this->isModified())
{
$uploadDir = sfConfig::get('sf_upload_dir');
$thumbnail = new sfThumbnail(150, 150);
$thumbnail2 = new sfThumbnail(800, 800);
if($this->getAvatar())
{
$thumbnail->loadFile($uploadDir.'/avatar/'.$this->getAvatar());
$thumbnail->save($uploadDir.'/avatar/thumbnail/'. $this->getAvatar());
$thumbnail2->loadFile($uploadDir.'/avatar/'.$this->getAvatar());
$thumbnail2->save($uploadDir.'/avatar/big/'. $this->getAvatar());
}
}
When I submit the form, I get this error message:
This form is multipart, which means you need to supply a files array as the bind() method second argument.
In the action where you bind the form you should use something like this:
$form->bind($request->getParamater($form->getName()), $request->getFiles($form->getName()));
So you need to pass the uploaded files as the second parameter to the bind method.

Resources