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

Add search block #13583

Merged
merged 15 commits into from Feb 7, 2019
Merged
Show file tree
Hide file tree
Changes from 14 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
3 changes: 3 additions & 0 deletions lib/load.php
Expand Up @@ -49,3 +49,6 @@
if ( ! function_exists( 'render_block_core_shortcode' ) ) {
require dirname( __FILE__ ) . '/../packages/block-library/src/shortcode/index.php';
}
if ( ! function_exists( 'render_block_core_search' ) ) {
require dirname( __FILE__ ) . '/../packages/block-library/src/search/index.php';
}
1 change: 1 addition & 0 deletions packages/block-library/CHANGELOG.md
Expand Up @@ -4,6 +4,7 @@

- Add background color controls for the table block.
- Add new `RSS` block ([#7966](https://github.com/WordPress/gutenberg/pull/7966)).
- Add new `Search` block ([#13583](https://github.com/WordPress/gutenberg/pull/13583)).
noisysocks marked this conversation as resolved.
Show resolved Hide resolved

## 2.2.12 (2019-01-03)

Expand Down
1 change: 1 addition & 0 deletions packages/block-library/src/editor.scss
Expand Up @@ -23,6 +23,7 @@
@import "./pullquote/editor.scss";
@import "./quote/editor.scss";
@import "./rss/editor.scss";
@import "./search/editor.scss";
@import "./shortcode/editor.scss";
@import "./spacer/editor.scss";
@import "./subhead/editor.scss";
Expand Down
2 changes: 2 additions & 0 deletions packages/block-library/src/index.js
Expand Up @@ -39,6 +39,7 @@ import * as preformatted from './preformatted';
import * as pullquote from './pullquote';
import * as reusableBlock from './block';
import * as rss from './rss';
import * as search from './search';
import * as separator from './separator';
import * as shortcode from './shortcode';
import * as spacer from './spacer';
Expand Down Expand Up @@ -87,6 +88,7 @@ export const registerCoreBlocks = () => {
preformatted,
pullquote,
rss,
search,
separator,
reusableBlock,
spacer,
Expand Down
43 changes: 43 additions & 0 deletions packages/block-library/src/search/edit.js
@@ -0,0 +1,43 @@
/**
* WordPress dependencies
*/
import { RichText } from '@wordpress/editor';
import { __ } from '@wordpress/i18n';

export default function SearchEdit( { className, attributes, setAttributes } ) {
const { label, placeholder, buttonText } = attributes;

return (
<div className={ className }>
<RichText
wrapperClassName="wp-block-search__label"
aria-label={ __( 'Label text' ) }
placeholder={ __( 'Add label…' ) }
keepPlaceholderOnFocus
formattingControls={ [] }
value={ label }
onChange={ ( html ) => setAttributes( { label: html } ) }
/>
<input
noisysocks marked this conversation as resolved.
Show resolved Hide resolved
className="wp-block-search__input"
aria-label={ __( 'Optional placeholder text' ) }
// We hide the placeholder field's placeholder when there is a value. This
// stops screen readers from reading the placeholder field's placeholder
// which is confusing.
placeholder={ ! placeholder && __( 'Optional placeholder…' ) }
value={ placeholder }
onChange={ ( event ) => setAttributes( { placeholder: event.target.value } ) }
/>
<RichText
wrapperClassName="wp-block-search__button"
className="wp-block-search__button-rich-text"
aria-label={ __( 'Button text' ) }
placeholder={ __( 'Add button text…' ) }
keepPlaceholderOnFocus
formattingControls={ [] }
value={ buttonText }
onChange={ ( html ) => setAttributes( { buttonText: html } ) }
/>
</div>
);
}
26 changes: 26 additions & 0 deletions packages/block-library/src/search/editor.scss
@@ -0,0 +1,26 @@
.wp-block-search {
.wp-block-search__input {
border-radius: $radius-round-rectangle;
border: 1px solid $dark-gray-150;
color: $dark-opacity-300;
font-family: $default-font;
font-size: $default-font-size;

&:focus {
outline: none;
}
}

.wp-block-search__button {
background: #f7f7f7;
border-radius: $radius-round-rectangle;
border: 1px solid #ccc;
box-shadow: inset 0 -1px 0 #ccc;
font-family: $default-font;
font-size: $default-font-size;

.wp-block-search__button-rich-text {
padding: 6px 10px;
}
}
}
29 changes: 29 additions & 0 deletions packages/block-library/src/search/index.js
@@ -0,0 +1,29 @@
/**
* WordPress dependencies
*/
import { __ } from '@wordpress/i18n';

/**
* Internal dependencies
*/
import edit from './edit';

export const name = 'core/search';

export const settings = {
title: __( 'Search' ),

description: __( 'Help visitors find your content.' ),

icon: 'search',

category: 'widgets',

keywords: [ __( 'find' ) ],

edit,

save() {
return null;
},
};
82 changes: 82 additions & 0 deletions packages/block-library/src/search/index.php
@@ -0,0 +1,82 @@
<?php
/**
* Server-side rendering of the `core/search` block.
*
* @package WordPress
*/

/**
* Dynamically renders the `core/search` block.
*
* @param array $attributes The block attributes.
*
* @return string The search block markup.
*/
function render_block_core_search( $attributes ) {
static $instance_id = 0;

$input_id = 'wp-block-search__input-' . ++$instance_id;

if ( ! empty( $attributes['label'] ) ) {
$label_markup = sprintf(
'<label for="%s" class="wp-block-search__label">%s</label>',
$input_id,
$attributes['label']
);
}

$input_markup = sprintf(
'<input type="search" id="%s" class="wp-block-search__input" name="s" value="%s" placeholder="%s" />',
$input_id,
esc_attr( get_search_query() ),
esc_attr( $attributes['placeholder'] )
);

if ( ! empty( $attributes['buttonText'] ) ) {
$button_markup = sprintf(
'<button type="submit" class="wp-block-search__button">%s</button>',
$attributes['buttonText']
);
}

$class = 'wp-block-search';
if ( isset( $attributes['className'] ) ) {
$class .= ' ' . $attributes['className'];
}

return sprintf(
'<form class="%s" role="search" method="get" action="%s">%s</form>',
$class,
esc_url( home_url( '/' ) ),
$label_markup . $input_markup . $button_markup
);
}

/**
* Registers the `core/search` block on the server.
*/
function register_block_core_search() {
register_block_type(
'core/search',
array(
'attributes' => array(
'label' => array(
'type' => 'string',
'default' => __( 'Search' ),
),
'placeholder' => array(
'type' => 'string',
'default' => '',
),
'buttonText' => array(
'type' => 'string',
'default' => __( 'Search' ),
),
),

'render_callback' => 'render_block_core_search',
)
);
}

add_action( 'init', 'register_block_core_search' );
16 changes: 16 additions & 0 deletions packages/block-library/src/search/style.scss
@@ -0,0 +1,16 @@
.wp-block-search {
display: flex;
flex-wrap: wrap;

.wp-block-search__label {
width: 100%;
}

.wp-block-search__input {
flex-grow: 1;
}

.wp-block-search__button {
margin-left: 10px;
}
}
5 changes: 5 additions & 0 deletions packages/block-library/src/search/theme.scss
@@ -0,0 +1,5 @@
.wp-block-search {
.wp-block-search__label {
font-weight: bold;
}
}
1 change: 1 addition & 0 deletions packages/block-library/src/style.scss
Expand Up @@ -16,6 +16,7 @@
@import "./pullquote/style.scss";
@import "./quote/style.scss";
@import "./rss/style.scss";
@import "./search/style.scss";
@import "./separator/style.scss";
@import "./subhead/style.scss";
@import "./table/style.scss";
Expand Down
1 change: 1 addition & 0 deletions packages/block-library/src/theme.scss
Expand Up @@ -2,5 +2,6 @@
@import "./preformatted/theme.scss";
@import "./pullquote/theme.scss";
@import "./quote/theme.scss";
@import "./search/theme.scss";
@import "./separator/theme.scss";
@import "./table/theme.scss";
1 change: 1 addition & 0 deletions test/integration/full-content/fixtures/core__search.html
@@ -0,0 +1 @@
<!-- wp:search /-->
10 changes: 10 additions & 0 deletions test/integration/full-content/fixtures/core__search.json
@@ -0,0 +1,10 @@
[
{
"clientId": "_clientId_0",
"name": "core/search",
"isValid": true,
"attributes": {},
"innerBlocks": [],
"originalContent": ""
}
]
18 changes: 18 additions & 0 deletions test/integration/full-content/fixtures/core__search.parsed.json
@@ -0,0 +1,18 @@
[
{
"blockName": "core/search",
"attrs": {},
"innerBlocks": [],
"innerHTML": "",
"innerContent": []
},
{
"blockName": null,
"attrs": {},
"innerBlocks": [],
"innerHTML": "\n",
"innerContent": [
"\n"
]
}
]
@@ -0,0 +1 @@
<!-- wp:search /-->
@@ -0,0 +1 @@
<!-- wp:search {"label":"Custom label","placeholder":"Custom placeholder","buttonText":"Custom button text"} /-->
@@ -0,0 +1,10 @@
[
{
"clientId": "_clientId_0",
"name": "core/search",
"isValid": true,
"attributes": {},
"innerBlocks": [],
"originalContent": ""
}
]
@@ -0,0 +1,22 @@
[
{
"blockName": "core/search",
"attrs": {
"buttonText": "Custom button text",
"label": "Custom label",
"placeholder": "Custom placeholder"
},
"innerBlocks": [],
"innerHTML": "",
"innerContent": []
},
{
"blockName": null,
"attrs": {},
"innerBlocks": [],
"innerHTML": "\n",
"innerContent": [
"\n"
]
}
]
@@ -0,0 +1 @@
<!-- wp:search /-->
Copy link
Member

@aduth aduth Feb 25, 2019

Choose a reason for hiding this comment

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

The fact that this markup does not match core__search__custom-text.html should be alarming; it's the entire purpose of these fixtures to guarantee.

<!-- wp:search {"label":"Custom label","placeholder":"Custom placeholder","buttonText":"Custom button text"} /-->

Running npm run fixtures:regenerate locally seems to produce some changes for me which produce a result more to what's expected.

However, it's still very concerning that:

  • The build passes despite these markups being entirely different
  • The build passes despite there being local changes to commit after running npm run fixtures:regenerate

Edit: Upon further investigation, it's not strictly accurate for me to claim that the entire point of these fixture tests is to verify equivalence between the original and serialized sources. In many cases, this is true (or at least they should be "equivalent"). Others, we're clearly testing for a different result (e.g. core__text__converts-to-paragraph). However, the fact we're not programmatically enforcing some equivalence in the majority of cases leads to situations just like this one where we aren't carefully considering whether the serialized output makes sense given the input (in this instance, it definitely doesn't). I'd conclude that we need to either (a) enforce some equivalence between the original and serialized outputs and make exceptions only where appropriate, (b) in some other way enforce some consciousness about the serialized output, or (c) abandon the fixtures tests altogether.

Related:

Copy link
Member

Choose a reason for hiding this comment

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

See #14122 for fix