Skip to content

Commit 610867b

Browse files
authored
Merge pull request #41 from hametuha/feature/inc-search-block
検索ボックスをブロック化 (#38)
2 parents 36e9a2c + 0a79bb5 commit 610867b

8 files changed

Lines changed: 257 additions & 52 deletions

File tree

README.md

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,16 +64,32 @@ The function automatically enqueues the required JavaScript and CSS assets.
6464

6565
### Search Box
6666

67+
The incremental FAQ search box is available in three forms.
68+
69+
#### Using the Block
70+
71+
Add the **FAQ Search Box** block in the block editor. The block has the following options:
72+
73+
- **Label** — Input placeholder text.
74+
- **Button Text** — Submit button label.
75+
76+
#### Using the Shortcode
77+
6778
You can use shortcode `hamelp-search` in page content.
6879

6980
<pre>
7081
[hamelp-search label='Enter your question here.'][/hamelp-search]
7182
</pre>
7283

73-
And you can call in your theme altenatively.
84+
#### Using the Template Function
85+
86+
You can also call `hamelp_render_search_box()` directly from your theme templates:
7487

7588
<pre>
76-
&lt;?php echo do_shortcode( '[hamelp-search][/hamelp-search]' ) ?&gt;
89+
&lt;?php echo hamelp_render_search_box( [
90+
'label' => 'Enter your question here.',
91+
'btn' => 'Search',
92+
] ); ?&gt;
7793
</pre>
7894

7995
## Installation
@@ -91,6 +107,11 @@ You can contribute to our github repo. Any [issues](https://github.com/hametuha/
91107

92108
## Changelog
93109

110+
### 2.3.0
111+
112+
- Add **FAQ Search Box** block (`hamelp/search-box`). The existing `[hamelp-search]` shortcode continues to work and now shares the same render logic.
113+
- Expose `hamelp_render_search_box()` as a public template function so themes can render the search box without going through the shortcode parser.
114+
94115
### 2.2.0
95116

96117
- Remove bundled [wp-ai-client](https://github.com/WordPress/wp-ai-client) Composer dependency. AI Overview now uses the wp-ai-client bundled with WordPress core, which requires **WordPress 7.0 or later**.

app/Hametuha/Hamelp/Hooks/SearchBoxShortCode.php

Lines changed: 5 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,6 @@ class SearchBoxShortCode extends ShortCode {
2525
*/
2626
protected $dashicons = 'dashicons-search';
2727

28-
/**
29-
* Whether the search box has been rendered.
30-
*
31-
* @var bool
32-
*/
33-
protected static $rendered = false;
34-
3528
/**
3629
* Return label for this shortcode.
3730
*
@@ -44,52 +37,17 @@ protected function get_label() {
4437
/**
4538
* Render shortcode content
4639
*
47-
* @todo Should allow multiple post types.
4840
* @param array $atts
4941
* @param string $content
5042
* @return string
5143
*/
5244
public function render_code( $atts, $content = '' ) {
53-
$place_holder = esc_attr( $atts['label'] );
54-
$button_label = esc_html( $atts['btn'] );
55-
$post_types = implode(
56-
array_map(
57-
function ( $post_type ) {
58-
return sprintf( '<input type="hidden" name="post_type" value="%s" />', esc_attr( $post_type ) );
59-
},
60-
array_keys( PostType::get()->get_post_types() )
61-
)
45+
return hamelp_render_search_box(
46+
[
47+
'label' => $atts['label'],
48+
'btn' => $atts['btn'],
49+
]
6250
);
63-
$query = get_search_query();
64-
$action = esc_url( apply_filters( 'hamelp_endpoint', home_url( '' ) ) );
65-
if ( ! self::$rendered ) {
66-
wp_enqueue_script( 'hamelp-incsearch' );
67-
wp_enqueue_style( 'hamelp-incsearch' );
68-
wp_localize_script(
69-
'hamelp-incsearch',
70-
'HamelpIncSearch',
71-
[
72-
'endpoint' => rest_url( '/wp/v2/faq' ),
73-
'found' => __( 'Found Posts:', 'hamelp' ),
74-
'notFound' => __( 'No posts found. Please change the query.', 'hamelp' ),
75-
]
76-
);
77-
self::$rendered = true;
78-
}
79-
$html = <<<HTML
80-
<form class="hamelp-search-box" action="{$action}">
81-
{$post_types}
82-
<div class="input-group">
83-
<input type="search" class="form-control hamelp-search-input" name="s" placeholder="{$place_holder}" value="{$query}" />
84-
<button class="btn btn-secondary hamelp-search-button" type="submit">{$button_label}</button>
85-
</div>
86-
<div class="hamelp-result-wrapper">
87-
<div class="hamelp-result list-group">
88-
</div>
89-
</div>
90-
</form>
91-
HTML;
92-
return $html;
9351
}
9452

9553
/**

hamelp.php

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,72 @@ function hamelp_register_blocks() {
160160
}
161161
add_action( 'init', 'hamelp_register_blocks' );
162162

163+
/**
164+
* Render FAQ incremental search box.
165+
*
166+
* Use this in theme templates or block render templates to output the FAQ
167+
* incremental search form. The shortcode `[hamelp-search]` and the
168+
* `hamelp/search-box` block both delegate to this function.
169+
*
170+
* @param array $args {
171+
* Optional. Search box arguments.
172+
*
173+
* @type string $label Input placeholder text. Default 'Enter keyword and hit search.'.
174+
* @type string $btn Submit button label. Default 'Search'.
175+
* @type string $wrapper_attrs Pre-built wrapper attributes string (used by block render).
176+
* }
177+
* @return string HTML output.
178+
*/
179+
function hamelp_render_search_box( $args = [] ) {
180+
static $localized = false;
181+
182+
$args = wp_parse_args(
183+
$args,
184+
[
185+
'label' => __( 'Enter keyword and hit search.', 'hamelp' ),
186+
'btn' => __( 'Search', 'hamelp' ),
187+
'wrapper_attrs' => '',
188+
]
189+
);
190+
191+
wp_enqueue_script( 'hamelp-incsearch' );
192+
wp_enqueue_style( 'hamelp-incsearch' );
193+
if ( ! $localized ) {
194+
wp_localize_script(
195+
'hamelp-incsearch',
196+
'HamelpIncSearch',
197+
[
198+
'endpoint' => rest_url( '/wp/v2/faq' ),
199+
'found' => __( 'Found Posts:', 'hamelp' ),
200+
'notFound' => __( 'No posts found. Please change the query.', 'hamelp' ),
201+
]
202+
);
203+
$localized = true;
204+
}
205+
206+
$post_type_inputs = '';
207+
foreach ( array_keys( \Hametuha\Hamelp\Hooks\PostType::get()->get_post_types() ) as $post_type ) {
208+
$post_type_inputs .= sprintf( '<input type="hidden" name="post_type" value="%s" />', esc_attr( $post_type ) );
209+
}
210+
211+
$query = get_search_query();
212+
$action = esc_url( apply_filters( 'hamelp_endpoint', home_url( '' ) ) );
213+
214+
if ( empty( $args['wrapper_attrs'] ) ) {
215+
$args['wrapper_attrs'] = 'class="hamelp-search-box"';
216+
}
217+
218+
return sprintf(
219+
'<form %1$s action="%2$s">%3$s<div class="input-group"><input type="search" class="form-control hamelp-search-input" name="s" placeholder="%4$s" value="%5$s" /><button class="btn btn-secondary hamelp-search-button" type="submit">%6$s</button></div><div class="hamelp-result-wrapper"><div class="hamelp-result list-group"></div></div></form>',
220+
$args['wrapper_attrs'],
221+
$action,
222+
$post_type_inputs,
223+
esc_attr( $args['label'] ),
224+
esc_attr( $query ),
225+
esc_html( $args['btn'] )
226+
);
227+
}
228+
163229
/**
164230
* Render AI Overview widget.
165231
*

src/blocks/search-box/block.json

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{
2+
"$schema": "https://schemas.wp.org/trunk/block.json",
3+
"apiVersion": 3,
4+
"name": "hamelp/search-box",
5+
"title": "FAQ Search Box",
6+
"category": "widgets",
7+
"icon": "search",
8+
"description": "Incremental search box for FAQ posts.",
9+
"textdomain": "hamelp",
10+
"attributes": {
11+
"label": {
12+
"type": "string",
13+
"default": "Enter keyword and hit search."
14+
},
15+
"btn": {
16+
"type": "string",
17+
"default": "Search"
18+
}
19+
},
20+
"supports": {
21+
"html": false,
22+
"align": [ "wide", "full" ]
23+
},
24+
"editorScript": "file:./index.js",
25+
"style": "hamelp-incsearch",
26+
"viewScript": "hamelp-incsearch",
27+
"render": "file:./render.php"
28+
}

src/blocks/search-box/edit.js

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/**
2+
* FAQ Search Box Block Editor Component
3+
*
4+
* @package
5+
*/
6+
7+
import { __ } from '@wordpress/i18n';
8+
import { useBlockProps, InspectorControls } from '@wordpress/block-editor';
9+
import { PanelBody, TextControl } from '@wordpress/components';
10+
11+
/**
12+
* Edit component for FAQ Search Box block.
13+
*
14+
* @param {Object} props Block props.
15+
* @param {Object} props.attributes Block attributes.
16+
* @param {Function} props.setAttributes Function to set attributes.
17+
* @return {JSX.Element} Block editor component.
18+
*/
19+
export default function Edit( { attributes, setAttributes } ) {
20+
const { label, btn } = attributes;
21+
22+
return (
23+
<>
24+
<InspectorControls>
25+
<PanelBody title={ __( 'Settings', 'hamelp' ) }>
26+
<TextControl
27+
label={ __( 'Label', 'hamelp' ) }
28+
value={ label }
29+
onChange={ ( value ) =>
30+
setAttributes( { label: value } )
31+
}
32+
/>
33+
<TextControl
34+
label={ __( 'Button Text', 'hamelp' ) }
35+
value={ btn }
36+
onChange={ ( value ) =>
37+
setAttributes( { btn: value } )
38+
}
39+
/>
40+
</PanelBody>
41+
</InspectorControls>
42+
<div { ...useBlockProps( { className: 'hamelp-search-box' } ) }>
43+
<div className="input-group">
44+
<input
45+
type="search"
46+
className="form-control"
47+
placeholder={ label }
48+
disabled
49+
/>
50+
<button
51+
type="button"
52+
className="btn btn-secondary"
53+
disabled
54+
>
55+
{ btn }
56+
</button>
57+
</div>
58+
</div>
59+
</>
60+
);
61+
}

src/blocks/search-box/index.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/**
2+
* FAQ Search Box Block
3+
*
4+
* @package
5+
*/
6+
7+
import { registerBlockType } from '@wordpress/blocks';
8+
import Edit from './edit';
9+
import metadata from './block.json';
10+
11+
registerBlockType( metadata.name, {
12+
edit: Edit,
13+
save: () => null, // Dynamic block.
14+
} );

src/blocks/search-box/render.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
/**
3+
* FAQ Search Box Block Render Template
4+
*
5+
* @package hamelp
6+
* @var array $attributes Block attributes.
7+
* @var string $content Block content.
8+
* @var WP_Block $block Block instance.
9+
*/
10+
11+
$wrapper_attributes = get_block_wrapper_attributes(
12+
[
13+
'class' => 'hamelp-search-box',
14+
]
15+
);
16+
17+
echo hamelp_render_search_box( // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
18+
[
19+
'label' => $attributes['label'] ?? __( 'Enter keyword and hit search.', 'hamelp' ),
20+
'btn' => $attributes['btn'] ?? __( 'Search', 'hamelp' ),
21+
'wrapper_attrs' => $wrapper_attributes,
22+
]
23+
);

src/scss/incsearch.scss

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,20 @@
22
* Incremental search styles for Hamelp
33
*
44
* @handle hamelp-incsearch
5+
*
6+
* Positional rules use normal selectors so they always apply.
7+
* Visual fallbacks are wrapped in :where() so specificity is 0 — any theme
8+
* styles or Bootstrap's .list-group/.list-group-item win automatically.
59
*/
610

711
.hamelp {
8-
&-search-box{
12+
&-search-box {
913
position: relative;
1014
margin: 2em 0;
1115
}
12-
&-result{
13-
&-wrapper{
16+
17+
&-result {
18+
&-wrapper {
1419
position: absolute;
1520
z-index: 100;
1621
width: 100%;
@@ -19,3 +24,32 @@
1924
}
2025
}
2126
}
27+
28+
:where(.hamelp-result) {
29+
background: #fff;
30+
31+
&:empty {
32+
display: none;
33+
}
34+
}
35+
36+
:where(.hamelp-result-link),
37+
:where(.hamelp-message) {
38+
display: block;
39+
padding: 0.5em 1em;
40+
border: 1px solid rgba(0, 0, 0, 0.125);
41+
border-bottom-width: 0;
42+
color: inherit;
43+
text-decoration: none;
44+
45+
&:last-child {
46+
border-bottom-width: 1px;
47+
}
48+
}
49+
50+
:where(.hamelp-result-link) {
51+
&:hover,
52+
&:focus {
53+
background: rgba(0, 0, 0, 0.05);
54+
}
55+
}

0 commit comments

Comments
 (0)