[WordPress]不要メニューを非表示
function custom_remove_menus() { global $menu; /** 投稿 */ remove_menu_page('edit.php'); /** コメント */ remove_menu_page('edit-comments.php'); } add_action('admin_menu', 'custom_remove_menus');
function custom_remove_menus() { global $menu; /** 投稿 */ remove_menu_page('edit.php'); /** コメント */ remove_menu_page('edit-comments.php'); } add_action('admin_menu', 'custom_remove_menus');
Checkout.jsx
import { Banner, TextBlock, reactExtension, useSettings, } from '@shopify/ui-extensions-react/checkout'; export default reactExtension("purchase.checkout.block.render", () => ( <Extension /> )); function Extension() { const { title,desc,banner_status } = useSettings(); const _title = title ? title : ''; const _desc = desc ? desc : ''; const _banner_status = banner_status ? banner_status : 'warning'; const descs = _desc.split("\n").map((item,i)=>{ return <TextBlock size="base" appearance={_banner_status}>{item}</TextBlock> }); return ( <Banner title={_title} status={_banner_status}> {descs} </Banner> ); }
shopify.extension.tomlに追記
[extensions.settings] [[extensions.settings.fields]] key = "title" type = "single_line_text_field" name = "表示するタイトル" description = "表示するタイトルを入力してください" [[extensions.settings.fields]] key = "desc" type = "multi_line_text_field" name = "表示する文言" description = "表示する文言を入力してください" [[extensions.settings.fields]] key = "banner_status" type = "single_line_text_field" name = "バナーの状態" [[extensions.settings.fields.validations]] name = "choices" value = '["info", "success","warning","critical"]'
functions.phpに追記
function disable_jsonld_of_aioseo() { return true; } add_filter( 'aioseo_schema_disable', 'disable_jsonld_of_aioseo' );
import { View, Text, Grid, GridItem, Link, Divider, useApi, useAttributeValues, useSettings, reactExtension, } from '@shopify/ui-extensions-react/checkout'; export default reactExtension("purchase.checkout.block.render", () => ( <Extension /> )); function Extension() { const { attributes_lines,hide_empty,hide_edit } = useSettings(); const attributeKeys = attributes_lines ? attributes_lines.split("\n") : []; if(!attributeKeys.length){ return ''; } let i,j,tmp; let key,value; /* 指定キーのattributeを表示 */ const attributeValues = attributeKeys.length ? useAttributeValues(attributeKeys) : []; const { shop } = useApi(); const cartUrl = shop.storefrontUrl.replace(/\/$/,'') + '/cart'; const rowSpan = attributeKeys.length + 1; let rows = []; let attributeKeysIndexList = []; for (i=0;i<attributeKeys.length;i++) { value = i < attributeValues.length ? attributeValues[i] : ' '; if(value){ if(!hide_empty || (hide_empty && value.replace(/[ ]+/g,'') != '')){ attributeKeysIndexList.push(i); } } } for (j=0;j<attributeKeysIndexList.length;j++) { i = attributeKeysIndexList[j]; /* ラベル */ key = attributeKeys[i]; tmp = attributesAltLineKeyValues.find((elm) => elm[0] == key); if(tmp && 1 < tmp.length && tmp[1]){ key = tmp[1]; } /* 値 */ value = i < attributeValues.length ? attributeValues[i] : ' '; rows.push(<View border="none" padding="base" key={`${j}_key`}><Text size="base">{key}</Text></View>); rows.push(<View border="none" padding="base" key={`${j}_value`}><Text size="base">{value}</Text></View>); if(j < 1 && !hide_edit){ rows.push( <GridItem rowSpan={rowSpan} spacing="base" key={`${j}_griditem`}> <View border="none" padding="base" key={`${j}_grid`}> <Link to={cartUrl} padding="none">変更</Link> </View> </GridItem> ); } if(1 < attributeKeysIndexList.length && j < attributeKeysIndexList.length-1){ rows.push( <GridItem columnSpan={2} key={`${j}_divider`}> <Divider></Divider> </GridItem> ); } } let gridColumns = hide_edit ? ['auto', 'fill'] : ['auto', 'fill', 'auto']; let gridRows = []; for(i=0;i<attributeKeysIndexList.length+(attributeKeysIndexList.length-1);i++){ gridRows.push('auto'); } return ( <Grid border="base" cornerRadius='base' padding='none' columns={gridColumns} rows={gridRows} > {rows} </Grid> ); }
shopify.extension.toml
[extensions.settings] [[extensions.settings.fields]] key = "attributes_lines" type = "multi_line_text_field" name = "表示するattribute.key" description = "" [[extensions.settings.fields]] key = "hide_attributes" type = "multi_line_text_field" name = "非表示条件のcart.attributesのキー:値" description = "" [[extensions.settings.fields]] key = "hide_empty" type = "boolean" name = "値が空欄の項目を表示しない" [[extensions.settings.fields]] key = "hide_edit" type = "boolean" name = "変更リンクを表示しない"
{% if variant.inventory_management == blank or variant.inventory_policy == "continue" or 0 < variant.inventory_quantity %} //在庫を追跡しないor在庫切れでも販売を続けるor在庫あり {% else %} //在庫なし {% endif %}
assign interval_seconds = 3 | times: 24 | times: 60 | times: 60 assign target_seconds = 'now' | date:'%s' | plus:interval_seconds
{{ target_seconds | date:'%Y/%m/%d' }}
公開済みの記事を編集してプレビューするとカスタムフィールドの値が古いままなのを解決する
※公式対応までのつなぎ
※2024/12/27 最新版ACFProに合わせて修正
functions.phpに下記追記
/** * $dataをjsonで出力 */ function echo_json($data) { header("Content-Type: application/json; charset=utf-8"); echo json_encode($data); } /** * テンプレートのadmin.jsを読み込む */ function add_admin_style() { $path_js = get_template_directory_uri().'/scripts/admin.js'; wp_enqueue_script('admin_script', $path_js); } add_action('admin_enqueue_scripts', 'add_admin_style'); /** * ajaxで送信されたカスタムフィールドの値をdbへ保存 */ function save_acf_by_ajax() { if(empty($_POST['post_id'])){ echo_json(['success' => false,'preview_id' => 0]); wp_die(); exit; } $post_id = $_POST['post_id']; $post_status = get_post_status($post_id); if($post_status !== "publish"){ echo_json(['success' => false,'preview_id' => 0]); wp_die(); exit; } $preview_id = 0; global $wpdb; $row = $wpdb->get_row("SELECT p.ID FROM $wpdb->posts AS p WHERE p.post_type = '_cf_preview_id' AND p.post_parent = ${post_id} ORDER BY p.ID DESC LIMIT 1"); if(empty($row)) { $post = array( 'post_name' => '_cf_preview_id', 'post_title' => '_cf_preview_id', 'post_status' => 'private', 'post_type' => '_cf_preview_id', 'post_author' => 1, 'ping_status' => 'closed', 'post_parent' => $post_id, 'comment_status' => 'closed', ); $preview_id = wp_insert_post($post); }else{ $preview_id = $row->ID; } unset($_POST['action']); unset($_POST['post_id']); unset($_POST['preview_id']); if(!empty($preview_id)) { foreach ($_POST as $key => $value) { update_field($key, $value, $preview_id); } } $_POST['post_id'] = $post_id; $_POST['preview_id'] = $preview_id; $_POST['success'] = !empty($preview_id); echo_json($_POST); wp_die(); } add_action( 'wp_ajax_save_acf_by_ajax_action', 'save_acf_by_ajax' ); /** * プレビュー時カスタムフィールドの値用のpostidを返す */ function get_cf_post_id($post_id = '') { if(empty($post_id)){ $post_id = get_the_ID(); } $cf_post_id = $post_id; if(is_preview()){ $post_status = get_post_status($post_id); if($post_status === 'publish'){ global $wpdb; $row = $wpdb->get_row("SELECT p.ID FROM $wpdb->posts AS p WHERE p.post_type = '_cf_preview_id' AND p.post_parent = ${post_id}"); if (!empty($row)) { $cf_post_id = $row->ID; } } } return $cf_post_id; }
wp-content/themes/テーマ/assets/js/admin.jsに下記追記
class CFSaveManager { qsall(selector,elm){ if(!elm)elm = document; return elm.querySelectorAll(selector); } qs(selector,elm){ if(!elm)elm = document; return elm.querySelector(selector); } constructor(){ } /* 初期化 */ init(){ this.initAutoSave(); } /* プレビューボタンにイベント設定 */ initAutoSave(){ const button = this.qs('.editor-preview-dropdown__toggle.components-dropdown-menu__toggle'); if(!button){ setTimeout(() => { this.initAutoSave(); },200); return; } button.addEventListener('click',() => { this.autoSave(); }); } /* ajaxでカスタムフィールドの値をapiへ送信・保存 */ autoSave(){ const elm = this.qs('[name="post_ID"]'); const form = this.qs('form.metabox-location-normal'); const formData = new FormData(form); let sendFormData = new FormData(); for (let item of formData) { if(/^acf\[.+\]$/.test(item[0])){ const key = item[0].split('[').pop().replace(/\]$/,''); if(key){ sendFormData.append(key,item[1]); } }else{ sendFormData.append(item[0],item[1]); } } sendFormData.append('action','save_acf_by_ajax_action'); sendFormData.append('post_id',elm.value); const options = { method : "POST", headers : { 'Accept': 'application/json' }, body : sendFormData }; fetch(window.ajaxurl,options) .then((response)=>{ if (!response.ok) { throw new Error(); } return response.json(); }) .then((json)=>{ console.log(json); }) .catch(console.error); } } window.addEventListener('DOMContentLoaded',(e) => { const cfsm = new CFSaveManager(); cfsm.init(); });
wpテンプレでカスタムフィールドの値を出力する部分
$post_id = get_the_ID(); if(is_preview()){ $post_id = get_cf_post_id($post_id); } $value = get_field( "test_text1" ,$post_id); echo "post_id :$post_id <br>"; echo "<h2>test_text1:".esc_html($value)."</h2>";
let sendData = { updates : {} }; this.deleteItems.forEach((item,index)=>{ sendData.updates[item.key] = 0; }); let options = { method : 'POST', credentials: 'same-origin', headers : { 'Content-Type': 'application/json' }, body : JSON.stringify(sendData) }; fetch(window.Shopify.routes.root+'cart/update.js',options) .then((response)=>{ if (!response.ok) { throw new Error(); } return response.json; }) .then((json)=>{ this.finishFetch(2); }) .catch((error)=>{ console.log(error); });
sysdm.cpl
「詳細設定」タブの「環境変数」ボタン押下
「Path」を選択した状態で「編集」ボタン押下
「新規」ボタン押下
C:\Program Files\MySQL\MySQL Server 8.0\bin
を入力後「OK」押下
let sendData = { id : item.key, quantity : item.quantity, properties : {} }; item.properties.forEach((property,index)=>{ sendData.properties['プロパティ'+(index+1)] = property.value; }); let options = { method : 'POST', credentials : 'same-origin', headers : { 'Content-Type' : 'application/json' }, body : JSON.stringify(sendData) }; fetch(window.Shopify.routes.root+'cart/change.js',options) .then((response)=>{ if (!response.ok) { throw new Error(); } return response.json; }) .then((json)=>{ this.finishFetch(); }) .catch((error)=>{ console.log(error); });