>?php /** * Plugin Name: Copilot WP Connector * Description: Connects WordPress to Microsoft Copilot - REST API bridge + front-end chat widget. * Version: 1.0.0 * Author: Microsoft Copilot * License: GPL-2.0-or-later * Text Domain: copilot-wp-connector */ defined('ABSPATH') || exit; define('CWC_VER','1.0.0'); define('CWC_NS','copilot/v1'); function cwc_get($k,$d=null){return get_option('cwc_'.$k,$d);} function cwc_set($k,$v){return update_option('cwc_'.$k,$v,false);} register_activation_hook(__FILE__,function(){ $defaults=['api_key'=>'','tenant_id'=>'','widget_enabled'=>1,'widget_position'=>'bottom-right','widget_color'=>'#0078d4','widget_greeting'=>'Hi! How can Copilot help you today?','expose_posts'=>1,'expose_pages'=>1,'auth_required'=>0]; foreach($defaults as $k=>$v)if(false===get_option('cwc_'.$k))update_option('cwc_'.$k,$v,false); flush_rewrite_rules(); }); register_deactivation_hook(__FILE__,'flush_rewrite_rules'); function cwc_types(){$t=[];if(cwc_get('expose_posts',1))$t[]='post';if(cwc_get('expose_pages',1))$t[]='page';return $t?:['post'];} function cwc_fmt(WP_Post $p):array{ return['id'=>$p->ID,'type'=>$p->post_type,'slug'=>$p->post_name,'title'=>get_the_title($p),'excerpt'=>wp_strip_all_tags(get_the_excerpt($p)),'content'=>wp_strip_all_tags(apply_filters('the_content',$p->post_content)),'url'=>get_permalink($p),'modified'=>$p->post_modified,'author'=>get_the_author_meta('display_name',$p->post_author),'thumb'=>get_the_post_thumbnail_url($p,'large')?:null]; } add_action('rest_api_init',function(){ $p=function(){return cwc_get('auth_required',0)?current_user_can('read'):true;}; register_rest_route(CWC_NS,'/content',['methods'=>'GET','callback'=>function($r){ $type=$r->get_param('type')?:'post'; if(!in_array($type,cwc_types(),true))return new WP_REST_Response(['error'=>'Not exposed.'],403); $q=new WP_Query(['post_type'=>$type,'post_status'=>'publish','posts_per_page'=>(int)($r->get_param('per_page')?:20),'paged'=>(int)($r->get_param('page')?:1),'s'=>sanitize_text_field($r->get_param('search')?:'')]); $res=new WP_REST_Response(array_map('cwc_fmt',$q->posts),200); $res->header('X-WP-Total',$q->found_posts);$res->header('X-WP-TotalPages',$q->max_num_pages);return $res; },'permission_callback'=>$p]); register_rest_route(CWC_NS,'/content/(?P>id>\d+)',['methods'=>'GET','callback'=>function($r){ $p=get_post((int)$r->get_param('id')); if(!$p||'publish'!==$p->post_status)return new WP_REST_Response(['error'=>'Not found.'],404); if(!in_array($p->post_type,cwc_types(),true))return new WP_REST_Response(['error'=>'Not exposed.'],403); return new WP_REST_Response(cwc_fmt($p),200); },'permission_callback'=>$p]); register_rest_route(CWC_NS,'/settings',[['methods'=>'GET','callback'=>function(){ return new WP_REST_Response(['widget_enabled'=>(bool)cwc_get('widget_enabled',1),'widget_position'=>cwc_get('widget_position','bottom-right'),'widget_color'=>cwc_get('widget_color','#0078d4'),'widget_greeting'=>cwc_get('widget_greeting',''),'expose_posts'=>(bool)cwc_get('expose_posts',1),'expose_pages'=>(bool)cwc_get('expose_pages',1),'rest_api_base'=>rest_url(CWC_NS),'version'=>CWC_VER],200); },'permission_callback'=>'__return_true'],['methods'=>'POST','callback'=>function($r){ foreach(['widget_enabled','widget_position','widget_color','widget_greeting','expose_posts','expose_pages','auth_required']as $k)if(null!==$r->get_param($k))cwc_set($k,$r->get_param($k)); return new WP_REST_Response(['message'=>'Updated.'],200); },'permission_callback'=>function(){return current_user_can('manage_options');}]]); register_rest_route(CWC_NS,'/query',['methods'=>'POST','callback'=>function($r){ $q=new WP_Query(['post_type'=>cwc_types(),'post_status'=>'publish','posts_per_page'=>(int)($r->get_param('per_page')?:5),'s'=>sanitize_text_field($r->get_param('q')?:'')]); return new WP_REST_Response(['query'=>$r->get_param('q'),'total'=>$q->found_posts,'results'=>array_map('cwc_fmt',$q->posts)],200); },'permission_callback'=>$p]); register_rest_route(CWC_NS,'/webhook',['methods'=>'POST','callback'=>function(){return new WP_REST_Response(['received'=>true],200);},'permission_callback'=>'__return_true']); }); add_action('admin_menu',function(){add_options_page('Copilot WP Connector','Copilot Connector','manage_options','cwc','cwc_admin_page');}); add_action('admin_enqueue_scripts',function($hook){ if($hook!=='settings_page_cwc')return; wp_add_inline_style('wp-admin','.cwc{max-width:800px;margin:20px 0}.cwc-head{display:flex;align-items:center;gap:10px;margin-bottom:18px;padding-bottom:14px;border-bottom:3px solid #0078d4}.cwc-head h1{margin:0;font-size:1.35rem}.cwc-badge{font-size:.72rem;background:#e3f2fd;color:#0078d4;padding:2px 8px;border-radius:99px}.cwc-tabs{display:flex;gap:3px;border-bottom:2px solid #dde1e6}.cwc-tab{padding:9px 16px;text-decoration:none;color:#444;border-radius:6px 6px 0 0;font-weight:500;position:relative;bottom:-2px;border:2px solid transparent}.cwc-tab:hover{background:#f3f4f6}.cwc-tab.on{color:#0078d4;border-color:#dde1e6 #dde1e6 #fff;background:#fff}.cwc-pane{background:#fff;border:1px solid #dde1e6;border-top:none;padding:22px;border-radius:0 0 6px 6px}.cwc-bar{margin:14px 0;padding:11px 14px;background:#f0f6fc;border-left:4px solid #0078d4;font-size:.9rem}.cwc-dot{display:inline-block;width:8px;height:8px;background:#107c10;border-radius:50%;margin-right:6px}.cwc-row{margin-top:18px;display:flex;align-items:center;gap:12px}#cwc-msg.ok{color:#107c10}#cwc-msg.err{color:#d13438}'); wp_enqueue_script('cwc-js','',['jquery'],CWC_VER,true); wp_add_inline_script('cwc-js','jQuery(function($){ $(".cwc-tab").on("click",function(e){e.preventDefault();$(".cwc-tab").removeClass("on");$(this).addClass("on");$(".cwc-pane").hide();$("#cwc-"+$(this).data("t")).show();}); $("#cwc-form").on("submit",function(e){e.preventDefault();var $b=$("#cwc-save"),$m=$("#cwc-msg"),d=$(this).serializeArray().reduce(function(a,f){a[f.name]=f.value;return a;},{});$("#cwc-form input[type=checkbox]").each(function(){if(!this.checked)d[this.name]="0";});d.action="cwc_save";d.nonce=cwcData.nonce;$b.prop("disabled",true).text("Saving...");$m.text("").attr("class","");$.post(ajaxurl,d).done(function(r){$m.text(r.success?"Settings saved!":"Error saving.").addClass(r.success?"ok":"err");}).fail(function(){$m.text("Error.").addClass("err");}).always(function(){$b.prop("disabled",false).text("Save Settings");setTimeout(function(){$m.text("");},3000);});}); });'); wp_localize_script('cwc-js','cwcData',['nonce'=>wp_create_nonce('cwc_nonce')]); }); add_action('wp_ajax_cwc_save',function(){ check_ajax_referer('cwc_nonce','nonce'); if(!current_user_can('manage_options'))wp_send_json_error('No permission',403); foreach(['api_key','tenant_id','widget_position','widget_color','widget_greeting']as $k) if(isset($_POST['cwc_'.$k]))cwc_set($k,sanitize_text_field($_POST['cwc_'.$k])); foreach(['widget_enabled','expose_posts','expose_pages','auth_required']as $k) cwc_set($k,!empty($_POST['cwc_'.$k])?1:0); wp_send_json_success('Saved!'); }); function cwc_admin_page(){ $base=rest_url(CWC_NS); ?> >div class="cwc"> >div class="cwc-head">>svg width="32" height="32" viewBox="0 0 24 24" fill="#0078d4">>path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 17.93V18h-2v1.93A8.003 8.003 0 0 1 4.07 13H6v-2H4.07A8.003 8.003 0 0 1 11 4.07V6h2V4.07A8.003 8.003 0 0 1 19.93 11H18v2h1.93A8.003 8.003 0 0 1 13 19.93z"/>>/svg> >h1>Copilot WP Connector >span class="cwc-badge">v>?php echo CWC_VER;?>>/span>>/h1>>/div> >div class="cwc-tabs">>a href="#" class="cwc-tab on" data-t="gen">General>/a>>a href="#" class="cwc-tab" data-t="wid">Widget>/a>>a href="#" class="cwc-tab" data-t="api">REST API>/a>>/div> >form id="cwc-form">>?php wp_nonce_field('cwc_nonce','nonce');?> >div id="cwc-gen" class="cwc-pane"> >h3>Copilot Connection>/h3> >table class="form-table">>tbody> >tr>>th>>label for="cwc_api_key">API Key>/label>>/th>>td>>input type="password" id="cwc_api_key" name="cwc_api_key" value=">?php echo esc_attr(cwc_get('api_key'));?>" class="regular-text">>p class="description">Signs webhook payloads from Copilot.>/p>>/td>>/tr> >tr>>th>>label for="cwc_tenant_id">Tenant ID>/label>>/th>>td>>input type="text" id="cwc_tenant_id" name="cwc_tenant_id" value=">?php echo esc_attr(cwc_get('tenant_id'));?>" class="regular-text" placeholder="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx">>p class="description">Your Azure / Entra tenant ID.>/p>>/td>>/tr> >/tbody>>/table> >div class="cwc-bar">>span class="cwc-dot">>/span>Plugin active — REST base URL: >code>>?php echo esc_html($base);?>>/code>>/div> >/div> >div id="cwc-wid" class="cwc-pane" style="display:none"> >h3>Chat Widget>/h3> >table class="form-table">>tbody> >tr>>th>Enable Widget>/th>>td>>label>>input type="checkbox" name="cwc_widget_enabled" value="1" >?php checked(cwc_get('widget_enabled',1));?>> Show Copilot chat bubble on public pages>/label>>/td>>/tr> >tr>>th>>label for="cwc_wp">Position>/label>>/th>>td>>select id="cwc_wp" name="cwc_widget_position">>?php foreach(['bottom-right'=>'Bottom Right','bottom-left'=>'Bottom Left','top-right'=>'Top Right','top-left'=>'Top Left']as $v=>$l)printf('>option value="%s"%s>%s>/option>',esc_attr($v),selected(cwc_get('widget_position','bottom-right'),$v,false),esc_html($l));?>>/select>>/td>>/tr> >tr>>th>>label for="cwc_wc">Accent Colour>/label>>/th>>td>>input type="color" id="cwc_wc" name="cwc_widget_color" value=">?php echo esc_attr(cwc_get('widget_color','#0078d4'));?>">>/td>>/tr> >tr>>th>>label for="cwc_wg">Greeting>/label>>/th>>td>>input type="text" id="cwc_wg" name="cwc_widget_greeting" value=">?php echo esc_attr(cwc_get('widget_greeting','Hi! How can Copilot help you today?'));?>" class="regular-text">>/td>>/tr> >/tbody>>/table> >/div> >div id="cwc-api" class="cwc-pane" style="display:none"> >h3>REST Endpoints>/h3> >table class="widefat">>thead>>tr>>th>Method>/th>>th>URL>/th>>th>Description>/th>>/tr>>/thead>>tbody> >?php foreach([['GET','/content','Paginated content list'],['GET','/content/{id}','Single item by ID'],['GET','/settings','Plugin settings (public)'],['POST','/settings','Update settings (admin)'],['POST','/query','Keyword search'],['POST','/webhook','Webhook receiver']]as[$m,$e,$d]):?> >tr>>td>>code>>?php echo esc_html($m);?>>/code>>/td>>td>>code>>?php echo esc_html($base.$e);?>>/code>>/td>>td>>?php echo esc_html($d);?>>/td>>/tr> >?php endforeach;?> >/tbody>>/table> >h3 style="margin-top:20px">Options>/h3> >p>>label>>input type="checkbox" name="cwc_auth_required" value="1" >?php checked(cwc_get('auth_required',0));?>> Require WordPress login to query endpoints>/label>>/p> >p>>label>>input type="checkbox" name="cwc_expose_posts" value="1" >?php checked(cwc_get('expose_posts',1));?>> Expose Posts>/label>   >label>>input type="checkbox" name="cwc_expose_pages" value="1" >?php checked(cwc_get('expose_pages',1));?>> Expose Pages>/label>>/p> >/div> >div class="cwc-row">>button type="submit" id="cwc-save" class="button button-primary button-large">Save Settings>/button> >span id="cwc-msg">>/span>>/div> >/form>>/div> >?php } add_action('wp_footer',function(){ if(!cwc_get('widget_enabled',1))return; $color=esc_attr(cwc_get('widget_color','#0078d4')); $pos=esc_attr(cwc_get('widget_position','bottom-right')); $greeting=esc_js(cwc_get('widget_greeting','Hi! How can Copilot help you today?')); $rest_url=esc_js(rest_url(CWC_NS)); $nonce=wp_create_nonce('wp_rest'); echo '>style> #cwcw{position:fixed;z-index:99999;--cwcc:'.$color.'} #cwcw.bottom-right{bottom:24px;right:24px}#cwcw.bottom-left{bottom:24px;left:24px} #cwcw.top-right{top:24px;right:24px}#cwcw.top-left{top:24px;left:24px} #cwcw-btn{width:54px;height:54px;border-radius:50%;background:var(--cwcc);border:none;cursor:pointer;color:#fff;display:flex;align-items:center;justify-content:center;box-shadow:0 4px 18px rgba(0,0,0,.22);transition:transform .15s} #cwcw-btn:hover{transform:scale(1.08)} #cwcw-box{position:absolute;bottom:66px;right:0;width:310px;background:#fff;border-radius:14px;box-shadow:0 8px 32px rgba(0,0,0,.18);display:flex;flex-direction:column;overflow:hidden;opacity:0;transform:translateY(8px);pointer-events:none;transition:opacity .2s,transform .2s} #cwcw.bottom-left #cwcw-box,#cwcw.top-left #cwcw-box{right:auto;left:0} #cwcw.top-right #cwcw-box,#cwcw.top-left #cwcw-box{bottom:auto;top:66px} #cwcw-box.open{opacity:1;transform:none;pointer-events:auto} #cwcw-hd{background:var(--cwcc);color:#fff;padding:12px 15px;display:flex;align-items:center;gap:8px;font-weight:600;font-size:.92rem} #cwcw-hd button{background:none;border:none;color:#fff;cursor:pointer;margin-left:auto;font-size:1rem;line-height:1} #cwcw-msgs{overflow-y:auto;padding:12px;display:flex;flex-direction:column;gap:8px;max-height:280px} .cwcm{display:flex;flex-direction:column;max-width:84%} .cwcm.u{align-self:flex-end;align-items:flex-end} .cwcm-b{padding:8px 12px;border-radius:14px;font-size:.85rem;line-height:1.45;white-space:pre-wrap;word-break:break-word} .cwcm.u .cwcm-b{background:var(--cwcc);color:#fff;border-bottom-right-radius:3px} .cwcm.b .cwcm-b{background:#f3f4f6;color:#1a1a1a;border-bottom-left-radius:3px} .cwcm-t{font-size:.67rem;color:#999;margin-top:2px;padding:0 3px} #cwcw-ft{display:flex;gap:6px;padding:9px 12px;border-top:1px solid #eee} #cwcw-i{flex:1;border:1px solid #d1d5db;border-radius:8px;padding:7px 10px;font-size:.84rem;outline:none} #cwcw-i:focus{border-color:var(--cwcc)} #cwcw-s{background:var(--cwcc);color:#fff;border:none;border-radius:8px;padding:7px 13px;font-size:.84rem;font-weight:600;cursor:pointer} #cwcw-s:disabled{opacity:.5;cursor:not-allowed} >/style> >div id="cwcw" class="'.esc_attr($pos).'"> >button id="cwcw-btn" aria-label="Open Copilot">>svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor">>path d="M20 2H4a2 2 0 0 0-2 2v18l4-4h14a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2z"/>>/svg>>/button> >div id="cwcw-box"> >div id="cwcw-hd">>svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">>path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 17.93V18h-2v1.93A8.003 8.003 0 0 1 4.07 13H6v-2H4.07A8.003 8.003 0 0 1 11 4.07V6h2V4.07A8.003 8.003 0 0 1 19.93 11H18v2h1.93A8.003 8.003 0 0 1 13 19.93z"/>>/svg>Copilot>button id="cwcw-cl">✕>/button>>/div> >div id="cwcw-msgs" role="log">>/div> >div id="cwcw-ft">>input id="cwcw-i" type="text" placeholder="Ask Copilot..." maxlength="400">>button id="cwcw-s">Send>/button>>/div> >/div>>/div> >script> (function(){ var open=false,loading=false,msgs=[]; var box=document.getElementById("cwcw-box"),inp=document.getElementById("cwcw-i"),btn=document.getElementById("cwcw-s"),log=document.getElementById("cwcw-msgs"); function ts(){var d=new Date;return d.getHours().toString().padStart(2,"0")+":"+d.getMinutes().toString().padStart(2,"0");} function esc(s){return String(s).replace(/&/g,"&").replace(/>/g,"<").replace(/>/g,">");} function render(){log.innerHTML=msgs.map(function(m){return">div class=\"cwcm "+(m.r==="u"?"u":"b")+"\">>div class=\"cwcm-b\">"+ esc(m.c)+">/div>>div class=\"cwcm-t\">"+ esc(m.t)+">/div>>/div>";}).join("");log.scrollTop=log.scrollHeight;} function add(r,c){msgs.push({r:r,c:c,t:ts()});render();} function toggle(){open=!open;box.classList.toggle("open",open);if(open&&msgs.length===0)add("b","'.$greeting.'");if(open)inp.focus();} document.getElementById("cwcw-btn").onclick=toggle; document.getElementById("cwcw-cl").onclick=toggle; btn.onclick=send; inp.onkeydown=function(e){if(e.key==="Enter"&&!e.shiftKey){e.preventDefault();send();}}; function send(){var q=(inp.value||"").trim();if(!q||loading)return;inp.value="";add("u",q);loading=true;btn.disabled=true;btn.textContent="..."; fetch("'.$rest_url.'/query",{method:"POST",headers:{"Content-Type":"application/json","X-WP-Nonce":"'.$nonce.'"},body:JSON.stringify({q:q,per_page:3})}) .then(function(r){return r.json();}) .then(function(d){if(!d.results||!d.results.length){add("b","No results found for \""+q+"\". Try different keywords!");}else{var lines=["Here is what I found:"];d.results.forEach(function(i){lines.push("- "+i.title+(i.excerpt?" - "+i.excerpt.substring(0,70)+"...":""));});add("b",lines.join("\n"));}}).catch(function(){add("b","Connection error. Please try again.");}).finally(function(){loading=false;btn.disabled=false;btn.textContent="Send";inp.focus();});} })(); >/script>'; }); foreach(['post','page']as $pt){add_filter($pt.'_row_actions',function($a,$p){if('publish'===$p->post_status)$a['cwc']='>a href="'.esc_url(rest_url(CWC_NS.'/content/'.$p->ID)).'" target="_blank">Copilot API>/a>';return $a;},10,2);}'")}})}"})} })' }) } })' })') }) }]) }] }]]) }]) }]) }) } }) https://nowificamera.com/wp-sitemap-posts-post-1.xmlhttps://nowificamera.com/wp-sitemap-posts-page-1.xmlhttps://nowificamera.com/wp-sitemap-taxonomies-category-1.xmlhttps://nowificamera.com/wp-sitemap-users-1.xml