רישום שדות ב Advanced Custom Fields באמצעות PHP

רישום שדות של ACF באמצעות קוד מציגה מספר יתרונות לעומת הוספה שלהם בממשק הניהול.

רישום שדות ACF באמצעות PHP תורמת למספר מועט יותר של קריאות למסד התונים, אפשרות להשתמש ב Version Control כגון GIT וכדומה. האפשרות להגדיר שדות בקבצי התבנית עצמה מאפשר למפתחים להמנע ממידע שאובד במהלך עבודה מול מספר סביבות פיתוח (dev/staging/live) ולי אישית חוסך לי לא מעט כאבי ראש ואף עבודה כפולה בהרבה מצבים.

נאמר כבר עכשיו כי במידה ואתם מחפשים פתרון לפריסה (deployment) של הקוד במספר סביבות פיתוח, אתם יכולים להשתמש גם ב Local JSON – אפשרות שהגיעה בגירסה 5 של ACF ומספקת פתרון עם מאמץ מינימלי.

ברמת ביצועים – Local JSON, כמו גם רישום שדות ב PHP בהחלט עדיפים על הוספת אותם שדות דרך הגדרות התוסף בממשק הניהול של וורדפרס. להבנתי היתרון המרכזי לרישום השדות ב PHP לעומת Local JSON הינו האפשרות לתרגום השדות וזאת באמצעות שימוש ב textdomain.

כך או כך אני מבטיח לכתוב על השימוש ב Local JSON בעתיד הקרוב…. כמו כן אם אינכם מכירים את התוסף Advanced Custom Field תנו מבט במדריך שימוש בסיסי ב ACF.

רישום שדות של ACF בעזרת PHP

הוספה של קבוצת שדות (field groups) והוספת השדות עצמם הוא תהליך די פשוט. ACF יכולה אף לייצר את הקוד עבורכם מתפריט ה Import / Export של ACF בלוח הבקרה של וורדפרס אם אתם מעוניינים לעשות זאת בצורה הזו.

חשוב לזכור כי המזהה (key) לכל קבוצת שדות והמזהה לכל שדה חייב להיות ייחודי. אותו מזהה מספק רפרנס ל ACF למציאה שמירה וטעינת המידע. אם יהיו שני שדות בעל אותו מזהה, השדה השני ידרוס את הראשון.

הפונקציות בהם תוכלו להשתמש, ואלו בהן נעשה שימוש בדוגמאות בהמשך הפוסט, הינם הפונקציות הבאות, כאשר תוכלו למצוא אף פונקציות נוספות בקובץ core/local.php.

שם הפונקציה תיאור
acf_add_local_field_group( $field_group ) הוספה של קבוצת שדות לקאש המקומי
acf_add_local_field( $field ) הוספת שדה לקאש המקומי
acf_get_local_field( $key ) שליפה של שדה מקומי
acf_remove_local_field( $key ) הסרה של שדה מקומי

מספר דוגמאות

הנה דוגמה בסיסית המתארת כיצד ניתן להוסיף קבוצת שדות בעזרת PHP:

if( function_exists('acf_add_local_field_group') ):

acf_add_local_field_group(array (
	'key' => 'group_1',
	'title' => 'My Group',
	'fields' => array (
		array (
			'key' => 'field_1',
			'label' => 'Sub Title',
			'name' => 'sub_title',
			'type' => 'text',
			'prefix' => '',
			'instructions' => '',
			'required' => 0,
			'conditional_logic' => 0,
			'wrapper' => array (
				'width' => '',
				'class' => '',
				'id' => '',
			),
			'default_value' => '',
			'placeholder' => '',
			'prepend' => '',
			'append' => '',
			'maxlength' => '',
			'readonly' => 0,
			'disabled' => 0,
		)
	),
	'location' => array (
		array (
			array (
				'param' => 'post_type',
				'operator' => '==',
				'value' => 'post',
			),
		),
	),
	'menu_order' => 0,
	'position' => 'normal',
	'style' => 'default',
	'label_placement' => 'top',
	'instruction_placement' => 'label',
	'hide_on_screen' => '',
));

endif;

על קוד זה להיות בקובץ functions.php של התבנית שלכם (או של תבנית הבת במצב האידיאלי). אגב – סביר להניח כי לא יהיה צורך להוסיף את כל ההגדרות שראיתם בקוד מעלה.

תוכלו למזער את הקוד ולהסיר מספר הגדרות כך ש ACF תשתמש בהגדרות ברירת המחדל עבור אלו שהוסרו. הקוד היותר מינימלי נראה כך:

if( function_exists('acf_add_local_field_group') ):

acf_add_local_field_group(array(
	'key' => 'group_1',
	'title' => 'My Group',
	'fields' => array (
		array (
			'key' => 'field_1',
			'label' => 'Sub Title',
			'name' => 'sub_title',
			'type' => 'text',
		)
	),
	'location' => array (
		array (
			array (
				'param' => 'post_type',
				'operator' => '==',
				'value' => 'post',
			),
		),
	),
));

endif;

נאמר כי בקוד הנ״ל הגדרנו גם קבוצת שדות וגם שדה עבור אותה קבוצת שדות (השדה מוגדר בשורות ס עד ס). באותה מידה ניתן להוסיף קבוצת שדות ושדה עבור אותה קבוצה בנפרד.

בדרך זו תוכלו להגדיר את השדה כמשתנה ולהוסיפו למספר קבוצות של שדות. שימו לב כי המשתנה $field חייב להכיל את ההגדרה parent שעליה להיות זהה למזהה של קבוצת השדות או של שדה אב אחר כגון repater או flexible content.

if( function_exists('acf_add_local_field_group') ):

acf_add_local_field_group(array(
	'key' => 'group_1',
	'title' => 'My Group',
	'fields' => $field,
	'location' => array (
		array (
			array (
				'param' => 'post_type',
				'operator' => '==',
				'value' => 'post',
			),
		),
	),
));

$field = acf_add_local_field(array(
	'key' => 'field_1',
	'label' => 'Sub Title',
	'name' => 'sub_title',
	'type' => 'text',
	'parent' => 'group_1'
));

endif;

הוספת קבוצת שדות של ACF באמצעות פונקציה

ניתן להוסיף את הפונקציות שהוזכרו מעלה ישירות לקובץ functions.php אך רצוי להוסיפן באמצעות ההוק acf/init. הוק זה נוסף בגירסה 5.2.7 של ACF וזוהי הדרך המומלצת לשימוש.

היתרון של השימוש בפעולה זו (action) היא שהפונקציה אינה תרוץ אם התוסף ACF אינו אקטיבי מסיבה כזו או אחרת ולכן לא תציג שגיאה במקרים אלו.

function my_acf_add_local_field_groups() {
	
	acf_add_local_field_group(array(
		'key' => 'group_1',
		'title' => 'My Group',
		'fields' => array (
			array (
				'key' => 'field_1',
				'label' => 'Sub Title',
				'name' => 'sub_title',
				'type' => 'text',
			)
		),
		'location' => array (
			array (
				array (
					'param' => 'post_type',
					'operator' => '==',
					'value' => 'post',
				),
			),
		),
	));
	
}

add_action('acf/init', 'my_acf_add_local_field_groups');

ההגדרות האפשריות עבור קבוצת שדות

הנה רשימה מלאה של ההגדרות האפשריות ביצירה של קבוצת שדות. אם אתם מכירים את ACF, לבטח תשימו לב כי כל ההגדרות שנציין בקוד מטה ניתנות לשינוי גם בעריכת קבוצת השדות של ACF בממשק הניהול של וורדפרס.

$group = array(
	
	/* (string) Unique identifier for field group. Must begin with 'group_' */
	'key' => 'group_1',
	
	/* (string) Visible in metabox handle */
	'title' => 'My Group',
	
	/* (array) An array of fields */
	'fields' => array(),
	
	/* (array) An array containing 'rule groups' where each 'rule group' is an array containing 'rules'. 
	Each group is considered an 'or', and each rule is considered an 'and'. */
	'location' => array(
		array(
			array(
				'param' => 'post_type',
				'operator' => '==',
				'value' => 'post',
			),
		),
	),
	
	/* (int) Field groups are shown in order from lowest to highest. Defaults to 0 */
	'menu_order' => 0,
	
	/* (string) Determines the position on the edit screen. Defaults to normal. Choices of 'acf_after_title', 'normal' or 'side' */
	'position' => 'normal',
	
	/* (string) Determines the metabox style. Defaults to 'default'. Choices of 'default' or 'seamless' */
	'style' => 'default',
	
	/* (string) Determines where field labels are places in relation to fields. Defaults to 'top'. 
	Choices of 'top' (Above fields) or 'left' (Beside fields) */
	'label_placement' => 'top',
	
	/* (string) Determines where field instructions are places in relation to fields. Defaults to 'label'. 
	Choices of 'label' (Below labels) or 'field' (Below fields) */
	'instruction_placement' => 'label',
	
	/* (array) An array of elements to hide on the screen */
	'hide_on_screen' => '',
);

הגדרות גנריות עבור שדה אינדיבידואלי

בנוסף, הנה רשימה של ההגדרות הגנריות האפשריות עבור שדה אינדיבידואלי. בנוסף להגדרות אלו, תמצאו בהמשך הפוסט את ההגדרות הספציפיות עבור כל סוג של שדה ב ACF בצורה נוחה…

$field = array (
	
	/* (string) Unique identifier for the field. Must begin with 'field_' */
	'key' => 'field_1',
	
	/* (string) Visible when editing the field value */
	'label' => 'Sub Title',
	
	/* (string) Used to save and load data. Single word, no spaces. Underscores and dashes allowed */
	'name' => 'sub_title',
	
	/* (string) Type of field (text, textarea, image, etc) */
	'type' => 'text',
	
	/* (string) Instructions for authors. Shown when submitting data */
	'instructions' => '',
	
	/* (int) Whether or not the field value is required. Defaults to 0 */
	'required' => 0,
	
	/* (mixed) Conditionally hide or show this field based on other field's values. 
	Best to use the ACF UI and export to understand the array structure. Defaults to 0 */
	'conditional_logic' => 0,
	
	/* (array) An array of attributes given to the field element */
	'wrapper' => array (
		'width' => '',
		'class' => '',
		'id' => '',
	),
	
	/* (mixed) A default value used by ACF if no value has yet been saved */
	'default_value' => '',
);

הגדרות לפי סוג שדה ספציפי

והנה רשימה מלאה של הגדרות נוספות עבור כל סוג של שדה ב ACF…

בסיסי – Basic

Text field settings

$text_field = array(
	
	/* ... Insert generic settings here ... */
	
	/* (string) Appears within the input. Defaults to '' */
	'placeholder' => '',
	
	/* (string) Appears before the input. Defaults to '' */
	'prepend' => '',
	
	/* (string) Appears after the input. Defaults to '' */
	'append' => '',
	
	/* (string) Restricts the character limit. Defaults to '' */
	'maxlength' => '',
	
	/* (bool) Makes the input readonly. Defaults to 0 */
	'readonly' => 0,
	
	/* (bool) Makes the input disabled. Defaults to 0 */
	'disabled' => 0,
	
);

Textarea field settings

$textarea_field = array(
	
	/* ... Insert generic settings here ... */
	
	/* (string) Appears within the input. Defaults to '' */
	'placeholder' => '',
	
	/* (string) Restricts the character limit. Defaults to '' */
	'maxlength' => '',
	
	/* (int) Restricts the number of rows and height. Defaults to '' */
	'rows' => '',
	
	/* (new_lines) Decides how to render new lines. Detauls to 'wpautop'.
	Choices of 'wpautop' (Automatically add paragraphs), 'br' (Automatically add <br>) or '' (No Formatting) */
	'new_lines' => '',
	
	/* (bool) Makes the input readonly. Defaults to 0 */
	'readonly' => 0,
	
	/* (bool) Makes the input disabled. Defaults to 0 */
	'disabled' => 0,
	
);

Number field settings

$number_field = array(
	
	/* ... Insert generic settings here ... */
	
	/* (string) Appears within the input. Defaults to '' */
	'placeholder' => '',
	
	/* (string) Appears before the input. Defaults to '' */
	'prepend' => '',
	
	/* (string) Appears after the input. Defaults to '' */
	'append' => '',
	
	/* (int) Minimum number value. Defaults to '' */
	'min' => '',
	
	/* (int) Maximum number value. Defaults to '' */
	'max' => '',
	
	/* (int) Step size increments. Defaults to '' */
	'step' => '',
	
);

Email field settings

$email_field = array(
	
	/* ... Insert generic settings here ... */
	
	/* (string) Appears within the input. Defaults to '' */
	'placeholder' => '',
	
	/* (string) Appears before the input. Defaults to '' */
	'prepend' => '',
	
	/* (string) Appears after the input. Defaults to '' */
	'append' => '',
	
);

Url field settings

$url_field = array(
	
	/* ... Insert generic settings here ... */
	
	/* (string) Appears within the input. Defaults to '' */
	'placeholder' => '',
	
);

Password field settings

$password_field = array(
	
	/* ... Insert generic settings here ... */
	
	/* (string) Appears within the input. Defaults to '' */
	'placeholder' => '',
	
	/* (string) Appears before the input. Defaults to '' */
	'prepend' => '',
	
	/* (string) Appears after the input. Defaults to '' */
	'append' => '',
	
);

תוכן – Content

WYSIWYG field settings

$wysiwyg_field = array(
	
	/* ... Insert generic settings here ... */
	
	/* (string) Specify which tabs are available. Defaults to 'all'.
	Choices of 'all' (Visual & Text), 'visual' (Visual Only) or text (Text Only) */
	'tabs' => 'all',
	
	/* (string) Specify the editor's toolbar. Defaults to 'full'.
	Choices of 'full' (Full), 'basic' (Basic) or a custom toolbar (https://www.advancedcustomfields.com/resources/customize-the-wysiwyg-toolbars/) */
	'toolbar' => 'full',
	
	/* (bool) Show the media upload button. Defaults to 1 */
	'media_upload' => 1,
	
);

oEmbed field settings

$oembed_field = array(
	
	/* ... Insert generic settings here ... */
	
	/* (int) Specify the width of the oEmbed element. Can be overridden by CSS */
	'width' => '',
	
	/* (int) Specify the height of the oEmbed element. Can be overridden by CSS */
	'height' => '',
	
);

Image field settings

$image_field = array(
	
	/* ... Insert generic settings here ... */
	
	/* (string) Specify the type of value returned by get_field(). Defaults to 'array'.
	Choices of 'array' (Image Array), 'url' (Image URL) or 'id' (Image ID) */
	'return_format' => 'array',
	
	/* (string) Specify the image size shown when editing. Defaults to 'thumbnail'. */
	'preview_size' => 'thumbnail',
	
	/* (string) Restrict the image library. Defaults to 'all'.
	Choices of 'all' (All Images) or 'uploadedTo' (Uploaded to post) */
	'library' => 'all',
	
	/* (int) Specify the minimum width in px required when uploading. Defaults to 0 */
	'min_width' => 0,
	
	/* (int) Specify the minimum height in px required when uploading. Defaults to 0 */
	'min_height' => 0,
	
	/* (int) Specify the minimum filesize in MB required when uploading. Defaults to 0 
	The unit may also be included. eg. '256KB' */
	'min_size' => 0,
	
	/* (int) Specify the maximum width in px allowed when uploading. Defaults to 0 */
	'max_width' => 0,
	
	/* (int) Specify the maximum height in px allowed when uploading. Defaults to 0 */
	'max_height' => 0,
	
	/* (int) Specify the maximum filesize in MB in px allowed when uploading. Defaults to 0
	The unit may also be included. eg. '256KB' */
	'max_size' => 0,
	
	/* (string) Comma separated list of file type extensions allowed when uploading. Defaults to '' */
	'mime_types' => '',
	
);

File field settings

$file_field = array(
	
	/* ... Insert generic settings here ... */
	
	/* (string) Specify the type of value returned by get_field(). Defaults to 'array'.
	Choices of 'array' (File Array), 'url' (File URL) or 'id' (File ID) */
	'return_format' => 'array',
	
	/* (string) Specify the file size shown when editing. Defaults to 'thumbnail'. */
	'preview_size' => 'thumbnail',
	
	/* (string) Restrict the file library. Defaults to 'all'.
	Choices of 'all' (All Files) or 'uploadedTo' (Uploaded to post) */
	'library' => 'all',
		
	/* (int) Specify the minimum filesize in MB required when uploading. Defaults to 0 
	The unit may also be included. eg. '256KB' */
	'min_size' => 0,
		
	/* (int) Specify the maximum filesize in MB in px allowed when uploading. Defaults to 0
	The unit may also be included. eg. '256KB' */
	'max_size' => 0,
	
	/* (string) Comma separated list of file type extensions allowed when uploading. Defaults to '' */
	'mime_types' => '',
	
);

Gallery field settings

$gallery_field = array(
	
	/* ... Insert generic settings here ... */
	
	/* (int) Specify the minimum attachments required to be selected. Defaults to 0 */
	'min' => 0,
	
	/* (int) Specify the maximum attachments allowed to be selected. Defaults to 0 */
	'max' => 0,
	
	/* (string) Specify the image size shown when editing. Defaults to 'thumbnail'. */
	'preview_size' => 'thumbnail',
	
	/* (string) Restrict the image library. Defaults to 'all'.
	Choices of 'all' (All Images) or 'uploadedTo' (Uploaded to post) */
	'library' => 'all',
	
	/* (int) Specify the minimum width in px required when uploading. Defaults to 0 */
	'min_width' => 0,
	
	/* (int) Specify the minimum height in px required when uploading. Defaults to 0 */
	'min_height' => 0,
	
	/* (int) Specify the minimum filesize in MB required when uploading. Defaults to 0 
	The unit may also be included. eg. '256KB' */
	'min_size' => 0,
	
	/* (int) Specify the maximum width in px allowed when uploading. Defaults to 0 */
	'max_width' => 0,
	
	/* (int) Specify the maximum height in px allowed when uploading. Defaults to 0 */
	'max_height' => 0,
	
	/* (int) Specify the maximum filesize in MB in px allowed when uploading. Defaults to 0
	The unit may also be included. eg. '256KB' */
	'max_size' => 0,
	
	/* (string) Comma separated list of file type extensions allowed when uploading. Defaults to '' */
	'mime_types' => '',
	
);

בחירה – Choice

Select field settings

$select_field = array(
	
	/* ... Insert generic settings here ... */
	
	/* (array) Array of choices where the key ('red') is used as value and the value ('Red') is used as label */
	'choices' => array(
		'red'	=> 'Red'
	),
	
	/* (bool) Allow a null (blank) value to be selected. Defaults to 0 */
	'allow_null' => 0,
	
	/* (bool) Allow mulitple choices to be selected. Defaults to 0 */
	'multiple' => 0,
	
	/* (bool) Use the select2 interfacte. Defaults to 0 */
	'ui' => 0,
	
	/* (bool) Load choices via AJAX. The ui setting must also be true for this to work. Defaults to 0 */
	'ajax' => 0,
	
	/* (string) Appears within the select2 input. Defaults to '' */
	'placeholder' => '',
	
);

Checkbox field settings

$checkbox_field = array(
	
	/* ... Insert generic settings here ... */
	
	/* (array) Array of choices where the key ('red') is used as value and the value ('Red') is used as label */
	'choices' => array(
		'red'	=> 'Red'
	),
	
	/* (string) Specify the layout of the checkbox inputs. Defaults to 'vertical'.
	Choices of 'vertical' or 'horizontal' */
	'layout' => 0,
	
);

Radio field settings

$radio_field = array(
	
	/* ... Insert generic settings here ... */
	
	/* (array) Array of choices where the key ('red') is used as value and the value ('Red') is used as label */
	'choices' => array(
		'red'	=> 'Red'
	),
	
	/* (bool) Allow a custom choice to be entered via a text input */
	'other_choice' => 0,
	
	/* (bool) Allow the custom value to be added to this field's choices. Defaults to 0.
	Will not work with PHP registered fields, only DB fields */
	'save_other_choice' => 0,
	
	/* (string) Specify the layout of the checkbox inputs. Defaults to 'vertical'.
	Choices of 'vertical' or 'horizontal' */
	'layout' => 0,
	
);

True / False field settings

$true_false_field = array(
	
	/* ... Insert generic settings here ... */
	
	/* (string) Text shown along side the checkbox */
	'message' => 0,
	
);

שדות Relational

Post Object field settings

$post_object_field = array(
	
	/* ... Insert generic settings here ... */
	
	/* (mixed) Specify an array of post types to filter the available choices. Defaults to '' */
	'post_type' => '',
	
	/* (mixed) Specify an array of taxonomies to filter the available choices. Defaults to '' */
	'taxonomy' => '',
	
	/* (bool) Allow a null (blank) value to be selected. Defaults to 0 */
	'allow_null' => 0,
	
	/* (bool) Allow mulitple choices to be selected. Defaults to 0 */
	'multiple' => 0,
	
	/* (string) Specify the type of value returned by get_field(). Defaults to 'object'.
	Choices of 'object' (Post object) or 'id' (Post ID) */
	'return_format' => 'object',
	
);

Page Link field settings

$page_link_field = array(
	
	/* ... Insert generic settings here ... */
	
	/* (mixed) Specify an array of post types to filter the available choices. Defaults to '' */
	'post_type' => '',
	
	/* (mixed) Specify an array of taxonomies to filter the available choices. Defaults to '' */
	'taxonomy' => '',
	
	/* (bool) Allow a null (blank) value to be selected. Defaults to 0 */
	'allow_null' => 0,
	
	/* (bool) Allow mulitple choices to be selected. Defaults to 0 */
	'multiple' => 0,
	
);

Relationship field settings

$relationship_field = array(
	
	/* ... Insert generic settings here ... */
	
	/* (mixed) Specify an array of post types to filter the available choices. Defaults to '' */
	'post_type' => '',
	
	/* (mixed) Specify an array of taxonomies to filter the available choices. Defaults to '' */
	'taxonomy' => '',
	
	/* (array) Specify the available filters used to search for posts.
	Choices of 'search' (Search input), 'post_type' (Post type select) and 'taxonomy' (Taxonomy select) */
	'filters' => array('search', 'post_type', 'taxonomy'),
	
	/* (array) Specify the visual elements for each post.
	Choices of 'featured_image' (Featured image icon) */
	'elements' => array(),
	
	/* (int) Specify the minimum posts required to be selected. Defaults to 0 */
	'min' => 0,
	
	/* (int) Specify the maximum posts allowed to be selected. Defaults to 0 */
	'max' => 0,
	
	/* (string) Specify the type of value returned by get_field(). Defaults to 'object'.
	Choices of 'object' (Post object) or 'id' (Post ID) */
	'return_format' => 'object',
	
);

Taxonomy field settings

$taxonomy_field = array(
	
	/* ... Insert generic settings here ... */
	
	/* (string) Specify the taxonomy to select terms from. Defaults to 'category' */
	'taxonomy' => '',
	
	/* (array) Specify the appearance of the taxonomy field. Defaults to 'checkbox'
	Choices of 'checkbox' (Checkbox inputs), 'multi_select' (Select field - multiple), 'radio' (Radio inputs) or 'select' (Select field) */
	'field_type' => 'checkbox',
	
	/* (bool) Allow a null (blank) value to be selected. Defaults to 0 */
	'allow_null' => 0,
	
	/* (bool) Allow selected terms to be saved as relatinoships to the post */
	'load_save_terms' 	=> 0,
	
	/* (string) Specify the type of value returned by get_field(). Defaults to 'id'.
	Choices of 'object' (Term object) or 'id' (Term ID) */
	'return_format'		=> 'id',
	
	/* (bool) Allow new terms to be added via a popup window */
	'add_term'			=> 1
	
);

User field settings

$user_field = array(
	
	/* ... Insert generic settings here ... */
	
	/* (array) Array of roles to limit the users available for selection */
	'role' => array(),
	
	/* (bool) Allow a null (blank) value to be selected. Defaults to 0 */
	'allow_null' => 0,
	
	/* (bool) Allow mulitple choices to be selected. Defaults to 0 */
	'multiple' => 0,
	
);

לסיכום

אם אתם עובדות מול מספר סביבות פיתוח אין ספק שעליכם לבצע רישום של שדות ב Advanced Custom Fields  באמצעות PHP או בעזרת הפונקציונליות של Local JSON, זוהי בהחלט הדרך הנוחה ביותר בסיטואציות אלו.

מה גם שברמת אופטימיזציה ומהירות של אתרי וורדפרס שתי אפשרויות אלו עדיפות על הוספת השדות דרך ממשק הניהול של ACF ויחסכו לא מעט קריאות למסד הנתונים המשפיעות על ביצועי האתר – גם אם מינמלית.

אם יש לכם תובנות לגבי ההבדלים בין Local JSON לרישום באמצעות PHP או הערות כלשהן לגבי נושא הפוסט הרגישו חופשי לשתף אותנו בתגובות מטה….  🙂

רועי יוסף
רועי יוסף

מפתח וורדפרס, מאמין ביצירת הזדמנויות לעסקים קטנים, סטארטאפים נועזים ואנשים עצמאים לשנות את העולם. אוהב טיפוגרפיה, צבעים וכל מה שבינהם ומכוון לספק אתרי וורדפרס עם ביצועים גבוהים, תמיכה בכל הדפדפנים, בעלי קוד ולידי, סמנטי ונקי.

0תגובות...

השאירו תגובה

פעימות